SeaLang/src/ast2/intern.rs

1575 lines
50 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::{
collections::BTreeMap,
fmt::Display,
hash::{Hash, Hasher},
};
use num_bigint::{BigInt, BigUint, Sign};
use crate::{
ast::IntegralType,
common::{from_lo_hi_dwords, into_lo_hi_dwords},
variant,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum SimpleType {
F32,
F64,
Bool,
Void,
USize,
ISize,
ComptimeInt,
/// Top type: this is the supertype of all types, and any value can coerce into it.
/// Although Rust's `()` is not a top type, it can be thought of as a top type in some contexts.
Top,
/// Bottom type: this is the subtype of all types, and it can coerce into a value of any type.
/// Akin to Rust's `!`.
Bottom,
UInt(u16),
SInt(u16),
}
impl From<u32> for SimpleType {
fn from(value: u32) -> Self {
let [discriminant, bits] = *crate::common::u32_as_u16_slice(&value);
match discriminant {
0 => Self::F32,
1 => Self::F64,
2 => Self::Bool,
3 => Self::Void,
4 => Self::USize,
5 => Self::ISize,
6 => Self::ComptimeInt,
7 => Self::Top,
8 => Self::Bottom,
9 => Self::UInt(bits),
10 => Self::SInt(bits),
_ => panic!("{value} is not a simple type"),
}
}
}
impl From<SimpleType> for u32 {
fn from(value: SimpleType) -> Self {
match value {
SimpleType::F32 => crate::common::u32_from_u16_slice(&[0, 0]),
SimpleType::F64 => crate::common::u32_from_u16_slice(&[1, 0]),
SimpleType::Bool => crate::common::u32_from_u16_slice(&[2, 0]),
SimpleType::Void => crate::common::u32_from_u16_slice(&[3, 0]),
SimpleType::USize => crate::common::u32_from_u16_slice(&[4, 0]),
SimpleType::ISize => crate::common::u32_from_u16_slice(&[5, 0]),
SimpleType::ComptimeInt => crate::common::u32_from_u16_slice(&[6, 0]),
SimpleType::Top => crate::common::u32_from_u16_slice(&[7, 0]),
SimpleType::Bottom => crate::common::u32_from_u16_slice(&[8, 0]),
SimpleType::UInt(bits) => crate::common::u32_from_u16_slice(&[9, bits]),
SimpleType::SInt(bits) => crate::common::u32_from_u16_slice(&[10, bits]),
}
}
}
impl Display for SimpleType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let fmt: std::borrow::Cow<str> = match self {
SimpleType::F32 => "f32".into(),
SimpleType::F64 => "f64".into(),
SimpleType::Bool => "bool".into(),
SimpleType::Void => "void".into(),
SimpleType::USize => "usize".into(),
SimpleType::ISize => "isize".into(),
SimpleType::ComptimeInt => "comptime_int".into(),
SimpleType::Top => "".into(),
SimpleType::Bottom => "".into(),
SimpleType::UInt(bits) => format!("u{bits}").into(),
SimpleType::SInt(bits) => format!("i{bits}").into(),
};
write!(f, "{fmt}",)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Tag {
String,
SIntSmall,
UIntSmall,
TrueValue,
FalseValue,
UInt64,
SInt64,
F32,
F64,
PositiveInt,
NegativeInt,
SimpleType,
PointerType,
ArrayType,
FunctionType,
StructType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(super) struct Item {
pub(super) tag: Tag,
pub(super) index: u32,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Key<'a> {
String {
str: &'a str,
},
Bytes {
bytes: &'a [u8],
},
SIntSmall {
bits: i32,
},
UIntSmall {
bits: u32,
},
SInt64 {
bits: i64,
},
UInt64 {
bits: u64,
},
F32 {
bits: f32,
},
F64 {
bits: f64,
},
PositiveInt {
bigint: BigInt,
},
NegativeInt {
bigint: BigInt,
},
SimpleType {
ty: SimpleType,
},
PointerType {
pointee: Index,
flags: PointerFlags,
},
ArrayType {
pointee: Index,
flags: PointerFlags,
length: u32,
},
FunctionType {
return_type: Index,
parameters: Vec<Index>,
},
StructType {
decl: super::Index,
name: Index,
packed: bool,
c_like: bool,
/// vec of (Name, Type)
fields: Vec<(Index, Index)>,
},
TrueValue,
FalseValue,
}
pub struct KeyDisplay<'a> {
ip: &'a InternPool,
key: Key<'a>,
}
impl Display for KeyDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.key {
Key::String { str } => write!(f, "\"{str}\"")?,
Key::Bytes { bytes } => write!(f, "{bytes:>02x?}")?,
Key::SIntSmall { bits } => write!(f, "{bits}")?,
Key::UIntSmall { bits } => write!(f, "{bits}")?,
Key::SInt64 { bits } => write!(f, "{bits}")?,
Key::UInt64 { bits } => write!(f, "{bits}")?,
Key::F32 { bits } => write!(f, "{bits}")?,
Key::F64 { bits } => write!(f, "{bits}")?,
Key::PositiveInt { ref bigint } => write!(f, "{bigint}")?,
Key::NegativeInt { ref bigint } => write!(f, "{bigint}")?,
Key::SimpleType { ty } => write!(f, "{ty}")?,
Key::PointerType { pointee, flags } => {
write!(f, "*{flags}{}", self.ip.display_key(pointee))?
}
Key::ArrayType {
pointee,
flags,
length,
} => write!(f, "[{flags}{}; {length}]", self.ip.display_key(pointee))?,
Key::FunctionType {
return_type,
ref parameters,
} => {
write!(f, "fn (")?;
let mut iter = parameters.iter().map(|&ty| self.ip.display_key(ty));
let Some(next) = iter.next() else {
return Ok(());
};
write!(f, "{next}")?;
for item in iter {
write!(f, ", {item}")?;
}
write!(f, ") -> {}", self.ip.display_key(return_type))?;
}
Key::StructType {
decl,
name,
packed,
c_like,
ref fields,
} => {
_ = (decl, name, packed, c_like, fields);
todo!()
}
Key::TrueValue => write!(f, "true")?,
Key::FalseValue => write!(f, "false")?,
}
Ok(())
}
}
impl Hash for Key<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
match self {
Key::String { str } => str.hash(state),
Key::Bytes { bytes } => bytes.hash(state),
Key::SIntSmall { bits } => bits.hash(state),
Key::UIntSmall { bits } => bits.hash(state),
Key::SInt64 { bits } => bits.hash(state),
Key::UInt64 { bits } => bits.hash(state),
Key::F32 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
Key::F64 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
Key::PositiveInt { bigint } => bigint.hash(state),
Key::NegativeInt { bigint } => bigint.hash(state),
Key::SimpleType { ty } => ty.hash(state),
Key::PointerType { pointee, flags } => (pointee, flags).hash(state),
Key::ArrayType {
pointee,
flags,
length,
} => (*pointee, *flags, *length).hash(state),
Key::StructType { name, decl, .. } => (*name, *decl).hash(state),
Key::FunctionType {
return_type,
parameters,
} => (return_type, parameters).hash(state),
Key::TrueValue | Key::FalseValue => {}
}
}
}
// #[repr(packed)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PointerFlags {
pub volatile: bool,
pub is_const: bool,
pub noalias: bool,
}
impl Display for PointerFlags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_const {
write!(f, "const ")?
}
if self.volatile {
write!(f, "volatile ")?
}
if self.noalias {
write!(f, "noalias ")?
}
Ok(())
}
}
impl PointerFlags {
pub fn new(is_const: bool, volatile: bool, noalias: bool) -> Self {
Self {
is_const,
volatile,
noalias,
}
}
pub fn union(self, other: Self) -> Self {
Self::new(
self.is_const || other.is_const,
self.volatile || other.volatile,
self.noalias || other.noalias,
)
}
pub fn pack(self) -> u8 {
(self.volatile as u8) << 0 | (self.is_const as u8) << 1 | (self.noalias as u8) << 2
}
pub fn unpack(packed: u8) -> Self {
Self {
volatile: packed & (1 << 0) != 0,
is_const: packed & (1 << 1) != 0,
noalias: packed & (1 << 2) != 0,
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructFlags {
pub packed: bool,
pub c_like: bool,
pub num_fields: u32,
}
impl StructFlags {
const MASK: u32 = (1u32 << 30) - 1;
pub fn new(packed: bool, c_like: bool, num_fields: u32) -> Self {
assert!(num_fields < (1 << 30));
Self {
packed,
c_like,
num_fields,
}
}
pub fn pack(self) -> u32 {
assert!(self.num_fields < (1 << 30));
(self.packed as u32) << 31 | (self.c_like as u32) << 30 | self.num_fields & Self::MASK
}
pub fn unpack(packed: u32) -> Self {
Self {
packed: packed & (1 << 31) != 0,
c_like: packed & (1 << 30) != 0,
num_fields: packed & Self::MASK,
}
}
}
#[derive(Debug, Clone, Copy)]
struct FunctionInfo {
void_return: bool,
num_params: u32,
}
impl FunctionInfo {
fn new(void_return: bool, num_params: u32) -> Self {
Self {
void_return,
num_params,
}
}
const MASK: u32 = 1u32 << (u32::BITS - 1);
fn pack(self) -> u32 {
(self.void_return as u32 * Self::MASK) | self.num_params & !Self::MASK
}
fn unpack(packed: u32) -> Self {
Self {
void_return: packed & Self::MASK != 0,
num_params: packed & !Self::MASK,
}
}
fn len(self) -> u32 {
self.void_return as u32 + self.num_params
}
}
impl Item {
fn idx(self) -> usize {
self.index as usize
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Index(u32);
impl Display for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "${}", self.index())
}
}
impl Index {
pub fn new(inner: u32) -> Self {
Self(inner)
}
pub fn into_u32(self) -> u32 {
unsafe { core::mem::transmute(self) }
}
pub fn from_u32(inner: u32) -> Self {
unsafe { core::mem::transmute(inner) }
}
pub fn as_u32(&self) -> &u32 {
unsafe { core::mem::transmute(self) }
}
fn index(&self) -> usize {
self.0 as usize
}
pub fn is_valid(&self) -> bool {
self.0 != u32::MAX
}
pub fn invalid() -> Self {
Self(u32::MAX)
}
}
pub struct InternPoolWrapper(core::cell::UnsafeCell<InternPool>);
impl InternPoolWrapper {
pub fn as_mut(&self) -> &mut InternPool {
unsafe { &mut *self.0.get() }
}
pub fn as_ref(&self) -> &InternPool {
unsafe { &*self.0.get() }
}
pub fn new() -> Self {
InternPool::new().into()
}
}
impl From<InternPool> for InternPoolWrapper {
fn from(value: InternPool) -> Self {
Self(core::cell::UnsafeCell::new(value))
}
}
impl core::ops::Deref for InternPoolWrapper {
type Target = InternPool;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0.get() }
}
}
impl core::ops::DerefMut for InternPoolWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl AsRef<InternPool> for InternPoolWrapper {
fn as_ref(&self) -> &InternPool {
Self::as_ref(self)
}
}
impl AsRef<InternPool> for InternPool {
fn as_ref(&self) -> &InternPool {
self
}
}
// impl AsMut<InternPool> for InternPoolWrapper {
// fn as_mut(&mut self) -> &mut InternPool {
// Self::as_mut(self)
// }
// }
// impl AsMut<InternPool> for InternPool {
// fn as_mut(&mut self) -> &mut InternPool {
// self
// }
// }
impl core::fmt::Debug for InternPoolWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("InternPoolWrapper")
.field(self.as_ref())
.finish()
}
}
pub struct InternPool {
tags: Vec<Tag>,
indices: Vec<u32>,
//
strings: Vec<u8>,
words: Vec<u32>,
hashed: BTreeMap<u64, Index>,
}
impl std::fmt::Debug for InternPool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InternPool")
.field_with("keys", |f| {
let mut list = f.debug_list();
let keys = (0..self.indices.len())
.map(|i| Index(i as u32))
.map(|idx| (idx, self.get_key(idx)));
for (idx, key) in keys {
list.entry_with(|f| write!(f, "{}: {key:?}", idx.0));
}
list.finish()
})
.field_with("hashed", |f| {
let mut list = f.debug_list();
for (hash, idx) in self.hashed.iter() {
list.entry_with(|f| write!(f, "{hash}: {}", idx.0));
}
list.finish()
})
.finish_non_exhaustive()
}
}
impl InternPool {
pub fn display_key(&self, index: Index) -> KeyDisplay<'_> {
KeyDisplay {
ip: self,
key: self.get_key(index),
}
}
}
macro_rules! static_keys {
($($name:ident => $def:expr),* $(,)?) => {
impl Index {
$(
pub const $name: Self = Self(${index()});
)*
}
const STATIC_KEYS: [Key; ${count($def)}] = [
$($def),*
];
};
}
static_keys!(
TOP => Key::SimpleType {ty: SimpleType::Top,},
BOTTOM => Key::SimpleType {ty: SimpleType::Bottom,},
BOOL => Key::SimpleType {ty: SimpleType::Bool,},
F32 => Key::SimpleType {ty: SimpleType::F32,},
F64 => Key::SimpleType {ty: SimpleType::F64,},
USIZE => Key::SimpleType {ty: SimpleType::USize,},
ISIZE => Key::SimpleType {ty: SimpleType::ISize,},
VOID => Key::SimpleType {ty: SimpleType::Void,},
COMPTIME_INT => Key::SimpleType {ty: SimpleType::ComptimeInt,},
I0 => Key::SimpleType { ty: SimpleType::SInt(0) },
U0 => Key::SimpleType { ty: SimpleType::UInt(0) },
I1 => Key::SimpleType { ty: SimpleType::SInt(1) },
U1 => Key::SimpleType { ty: SimpleType::UInt(1) },
I8 => Key::SimpleType { ty: SimpleType::SInt(8) },
U8 => Key::SimpleType { ty: SimpleType::UInt(8) },
I16 => Key::SimpleType { ty: SimpleType::SInt(16) },
U16 => Key::SimpleType { ty: SimpleType::UInt(16) },
I32 => Key::SimpleType { ty: SimpleType::SInt(32) },
U32 => Key::SimpleType { ty: SimpleType::UInt(32) },
I64 => Key::SimpleType { ty: SimpleType::SInt(64) },
U64 => Key::SimpleType { ty: SimpleType::UInt(64) },
I128 => Key::SimpleType { ty: SimpleType::SInt(128) },
U128 => Key::SimpleType { ty: SimpleType::UInt(128) },
TRUE => Key::TrueValue,
FALSE => Key::FalseValue,
EMPTY_STRING => Key::String { str: "" },
EMPTY_BYTES => Key::Bytes { bytes: &[] },
);
impl InternPool {
pub fn get_void_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Void,
})
}
pub fn get_bool_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Bool,
})
}
pub fn get_true_value(&self) -> Index {
self.get_assume_present(&Key::TrueValue)
}
pub fn get_false_value(&self) -> Index {
self.get_assume_present(&Key::FalseValue)
}
pub fn get_f32_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::F32,
})
}
pub fn get_f64_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::F64,
})
}
pub fn get_comptime_int_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::ComptimeInt,
})
}
pub fn get_usize_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::USize,
})
}
pub fn get_isize_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::ISize,
})
}
// Assumes the type is present in the pool.
fn get_simple_type_unchecked(&self, ty: SimpleType) -> Index {
self.get_assume_present(&Key::SimpleType { ty })
}
pub fn get_u0_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(0))
}
pub fn get_i0_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(0))
}
pub fn get_u1_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(1))
}
pub fn get_i1_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(1))
}
pub fn get_u8_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(8))
}
pub fn get_i8_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(8))
}
pub fn get_u16_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(16))
}
pub fn get_i16_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(16))
}
pub fn get_u32_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(32))
}
pub fn get_i32_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(32))
}
pub fn get_u64_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(64))
}
pub fn get_i64_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(64))
}
pub fn get_u128_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::UInt(128))
}
pub fn get_i128_type(&self) -> Index {
self.get_simple_type_unchecked(SimpleType::SInt(128))
}
pub fn get_top_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Top,
})
}
pub fn get_bottom_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Bottom,
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct TypeInfo {
pub bitsize: u32,
pub bitalign: u32,
pub signed: bool,
}
impl TypeInfo {
/// byte size
pub fn size(&self) -> u32 {
self.bitsize.div_ceil(8)
}
/// byte align
pub fn align(&self) -> u32 {
self.bitalign.div_ceil(8)
}
}
impl InternPool {
pub fn peer_type(&mut self, lhs: Index, rhs: Index) -> Option<Index> {
if lhs == rhs {
return Some(rhs);
}
let lt = self.get_key(lhs);
let rt = self.get_key(rhs);
match (lt, rt) {
(
Key::SimpleType {
ty: SimpleType::ComptimeInt,
},
Key::SimpleType {
ty: SimpleType::F32,
}
| Key::SimpleType {
ty: SimpleType::F64,
}
| Key::SimpleType {
ty: SimpleType::USize,
}
| Key::SimpleType {
ty: SimpleType::ISize,
}
| Key::SimpleType {
ty: SimpleType::SInt(_) | SimpleType::UInt(_),
},
) => Some(rhs),
(
Key::SimpleType {
ty: SimpleType::F32,
}
| Key::SimpleType {
ty: SimpleType::F64,
}
| Key::SimpleType {
ty: SimpleType::USize,
}
| Key::SimpleType {
ty: SimpleType::ISize,
}
| Key::SimpleType {
ty: SimpleType::SInt(_) | SimpleType::UInt(_),
},
Key::SimpleType {
ty: SimpleType::ComptimeInt,
},
) => Some(lhs),
(
Key::PointerType {
pointee: lp,
flags: lf,
},
Key::PointerType {
pointee: rp,
flags: rf,
},
) => {
if lp == rp {
Some(self.get_pointer_type(lp, Some(lf.union(rf))))
} else {
None
}
}
_ => None,
}
}
pub fn to_mir_type(&self, index: Index, _ptr_size: TypeInfo) -> crate::mir::Type {
use crate::mir::Type;
match self.get_key(index) {
Key::SimpleType { ty } => match ty {
SimpleType::F32 => Type::SinglePrecision,
SimpleType::F64 => Type::DoublePrecision,
SimpleType::Bool => Type::Byte,
SimpleType::Void => {
todo!("void can't be turned into a mir type")
}
SimpleType::ISize | SimpleType::USize => Type::QWord,
SimpleType::UInt(bits) | SimpleType::SInt(bits) => {
Type::from_bitsize_int(bits as u32)
}
SimpleType::Top | SimpleType::Bottom | SimpleType::ComptimeInt => {
panic!("{ty} can't be turned into a mir type")
}
},
Key::ArrayType { .. } => {
panic!("arrays can't be directly accessed in mir")
}
Key::FunctionType { .. } => Type::Function,
Key::PointerType { .. } => Type::QWord,
Key::StructType { .. } => {
panic!("arrays can't be directly accessed in mir")
}
_ => {
panic!("index was not a type")
}
}
}
pub fn is_type_signed(&self, index: Index, _ptr_size: TypeInfo) -> bool {
match self.get_key(index) {
Key::SimpleType { ty } => match ty {
SimpleType::USize | SimpleType::UInt(_) => false,
SimpleType::ISize | SimpleType::SInt(_) => true,
_ => false,
},
Key::PointerType { .. } => false,
Key::ArrayType { .. } => false,
Key::FunctionType { .. } => false,
Key::StructType { .. } => false,
_ => false,
}
}
pub fn size_of_type(&self, index: Index, ptr_size: TypeInfo) -> TypeInfo {
match self.get_key(index) {
Key::SimpleType { ty } => match ty {
SimpleType::SInt(bits) => TypeInfo {
bitsize: bits as u32,
bitalign: (bits as u32).next_multiple_of(8).next_power_of_two(),
signed: true,
},
SimpleType::UInt(bits) => TypeInfo {
bitsize: bits as u32,
bitalign: (bits as u32).next_multiple_of(8).next_power_of_two(),
signed: false,
},
SimpleType::F32 => TypeInfo {
bitsize: 32,
bitalign: 32,
signed: true,
},
SimpleType::F64 => TypeInfo {
bitsize: 64,
bitalign: 64,
signed: true,
},
SimpleType::Bool => TypeInfo {
bitsize: 1,
bitalign: 1,
signed: false,
},
SimpleType::Void => TypeInfo {
bitsize: 0,
bitalign: 0,
signed: false,
},
SimpleType::USize => ptr_size,
SimpleType::ISize => ptr_size,
SimpleType::Top | SimpleType::Bottom => {
panic!("top and bottom types are not sized")
}
SimpleType::ComptimeInt => panic!("comptime int is unsized"),
},
Key::PointerType { .. } => ptr_size,
Key::ArrayType {
pointee, length, ..
} => {
let element_size = self.size_of_type(pointee, ptr_size);
let bitsize = element_size.bitalign * length;
TypeInfo {
bitsize,
signed: false,
..element_size
}
}
Key::FunctionType { .. } => ptr_size,
Key::StructType { packed, fields, .. } => {
// TODO: c-like layout
let (size, align) = fields.iter().fold((0, 0), |(size, align), (_name, ty)| {
let field_size = self.size_of_type(*ty, ptr_size);
let size = size + field_size.bitsize;
let size = if packed {
size.next_multiple_of(field_size.bitalign)
} else {
size
};
let align = align.max(field_size.bitalign);
(size, align)
});
TypeInfo {
bitsize: size,
bitalign: align,
signed: false,
}
}
_ => {
panic!("index was not a type")
}
}
}
pub fn insert_ast1_type(&mut self, pointer_bits: u16, ty: &crate::ast::Type) -> Index {
match ty {
crate::ast::Type::Bool => self.get_bool_type(),
crate::ast::Type::ComptimeNumber => self.get_comptime_int_type(),
crate::ast::Type::Integer(i) => self.get_or_insert({
if i.signed {
Key::SimpleType {
ty: SimpleType::SInt(i.bits),
}
} else {
Key::SimpleType {
ty: SimpleType::UInt(i.bits),
}
}
}),
crate::ast::Type::Floating(crate::ast::FloatingType::Binary32) => self.get_f32_type(),
crate::ast::Type::Floating(crate::ast::FloatingType::Binary64) => self.get_f64_type(),
crate::ast::Type::Pointer { constness, pointee } => {
let pointee = self.insert_ast1_type(pointer_bits, &pointee);
self.get_or_insert(Key::PointerType {
pointee,
flags: PointerFlags::new(*constness, false, false),
})
}
crate::ast::Type::Fn {
parameter_types,
return_type,
} => {
let parameters = parameter_types
.iter()
.map(|ty| self.insert_ast1_type(pointer_bits, ty))
.collect::<Vec<_>>();
let return_type = self.from_ast1_type(pointer_bits, &return_type);
self.get_or_insert(Key::FunctionType {
return_type,
parameters,
})
}
crate::ast::Type::Void => self.get_void_type(),
_ => {
todo!()
}
}
}
pub fn from_ast1_type(&self, pointer_bits: u16, ty: &crate::ast::Type) -> Index {
match ty {
crate::ast::Type::Bool => self.get_bool_type(),
crate::ast::Type::ComptimeNumber => self.get_comptime_int_type(),
crate::ast::Type::Integer(i) => self.get_assume_present(&{
if i.signed {
Key::SimpleType {
ty: SimpleType::SInt(i.bits),
}
} else {
Key::SimpleType {
ty: SimpleType::UInt(i.bits),
}
}
}),
crate::ast::Type::Floating(crate::ast::FloatingType::Binary32) => self.get_f32_type(),
crate::ast::Type::Floating(crate::ast::FloatingType::Binary64) => self.get_f64_type(),
crate::ast::Type::Pointer { constness, pointee } => {
let pointee = self.from_ast1_type(pointer_bits, &pointee);
self.get_assume_present(&Key::PointerType {
pointee,
flags: PointerFlags::new(*constness, false, false),
})
}
crate::ast::Type::Fn {
parameter_types,
return_type,
} => {
let parameters = parameter_types
.iter()
.map(|ty| self.from_ast1_type(pointer_bits, ty))
.collect::<Vec<_>>();
let return_type = self.from_ast1_type(pointer_bits, &return_type);
self.get_assume_present(&Key::FunctionType {
return_type,
parameters,
})
}
crate::ast::Type::Void => self.get_void_type(),
_ => {
todo!()
}
}
}
pub fn as_ast1_type(&self, pointer_bits: u16, index: Index) -> crate::ast::Type {
use crate::ast::Type;
match self.get_key(index) {
Key::SimpleType { ty } => match ty {
SimpleType::F32 => Type::Floating(crate::ast::FloatingType::Binary32),
SimpleType::F64 => Type::Floating(crate::ast::FloatingType::Binary64),
SimpleType::SInt(bits) => Type::Integer(IntegralType::new(true, bits)),
SimpleType::UInt(bits) => Type::Integer(IntegralType::new(false, bits)),
SimpleType::Bool => Type::Bool,
SimpleType::Void => Type::Void,
SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
SimpleType::ComptimeInt => Type::comptime_number(),
SimpleType::Top | SimpleType::Bottom => {
panic!("top and bottom types cannot be converted to ast1 types")
}
},
Key::PointerType { pointee, flags } => Type::Pointer {
constness: flags.is_const,
pointee: Box::new(self.as_ast1_type(pointer_bits, pointee)),
},
Key::FunctionType {
return_type,
parameters,
} => Type::Fn {
parameter_types: parameters
.into_iter()
.map(|i| self.as_ast1_type(pointer_bits, i))
.collect(),
return_type: Box::new(self.as_ast1_type(pointer_bits, return_type)),
},
_ => unimplemented!(),
}
}
}
pub const AMD64_POINTER_BITS: u16 = 64;
pub const AMD64_POINTER_TYPE_INFO: TypeInfo = TypeInfo {
bitsize: 64,
bitalign: 64,
signed: false,
};
impl InternPool {
pub fn new() -> Self {
let mut this = Self {
tags: Vec::new(),
indices: Vec::new(),
strings: Vec::new(),
words: Vec::new(),
hashed: BTreeMap::new(),
};
this.extend_keys(STATIC_KEYS);
this
}
fn extend_keys<'a, K: IntoIterator<Item = Key<'a>>>(&mut self, keys: K) {
for k in keys.into_iter() {
let mut hasher = std::hash::DefaultHasher::new();
k.hash(&mut hasher);
let digest = hasher.finish();
let i = self.insert(k);
self.hashed.insert(digest, i);
}
}
fn len(&self) -> u32 {
u32::try_from(self.tags.len())
.expect(&format!("more than {} items in internpool!", u32::MAX))
}
pub fn get_or_insert(&mut self, key: Key) -> Index {
let mut hasher = std::hash::DefaultHasher::new();
key.hash(&mut hasher);
let digest = hasher.finish();
if let Some(&idx) = self.hashed.get(&digest) {
idx
} else {
let i = self.insert(key);
self.hashed.insert(digest, i);
i
}
}
fn insert(&mut self, key: Key) -> Index {
match key {
Key::String { str } => {
let len = str.len() as u32;
let start = self.extend_strings(str);
let words_idx = self.extend_words([start, len]);
self.create_item(Tag::String, words_idx)
}
Key::Bytes { bytes } => {
let len = bytes.len() as u32;
let start = self.extend_strings(bytes);
let words_idx = self.extend_words([start, len]);
self.create_item(Tag::String, words_idx)
}
Key::SIntSmall { bits } => self.create_item(Tag::SIntSmall, bits as u32),
Key::UIntSmall { bits } => self.create_item(Tag::UIntSmall, bits as u32),
Key::F32 { bits } => self.create_item(Tag::F32, bits as u32),
Key::F64 { bits } => {
let (lo, hi) = into_lo_hi_dwords(bits as u64);
let words_idx = self.extend_words([lo, hi]);
self.create_item(Tag::F64, words_idx)
}
Key::SInt64 { bits } => {
let (lo, hi) = into_lo_hi_dwords(bits as u64);
let i = self.extend_words([lo, hi]);
self.create_item(Tag::SInt64, i)
}
Key::UInt64 { bits } => {
let (lo, hi) = into_lo_hi_dwords(bits as u64);
let i = self.extend_words([lo, hi]);
self.create_item(Tag::UInt64, i)
}
Key::PositiveInt { bigint } => {
let (_, words) = bigint.to_u32_digits();
let i = self.push_word(words.len() as u32);
_ = self.extend_words(words);
self.create_item(Tag::PositiveInt, i)
}
Key::NegativeInt { bigint } => {
let (_, words) = bigint.to_u32_digits();
let i = self.push_word(words.len() as u32);
_ = self.extend_words(words);
self.create_item(Tag::NegativeInt, i)
}
Key::SimpleType { ty } => self.create_item(Tag::SimpleType, ty.into()),
Key::PointerType { pointee, flags } => {
let flags = flags.pack();
let i = self.extend_words([pointee.index() as u32, flags as u32]);
self.create_item(Tag::PointerType, i)
}
Key::ArrayType {
pointee,
flags,
length,
} => {
let flags = flags.pack();
let i = self.extend_words([pointee.index() as u32, flags as u32, length]);
self.create_item(Tag::ArrayType, i)
}
Key::StructType {
name,
decl,
packed,
c_like,
fields,
} => {
let flags = StructFlags::new(packed, c_like, fields.len() as u32).pack();
let i = self.extend_words([name.into_u32(), decl.into_u32(), flags, u32::MAX]);
if !fields.is_empty() {
let fields_offset = self.extend_words(
fields
.into_iter()
.map(|(n, t)| [n.into_u32(), t.into_u32()])
.flatten(),
);
self.words[i as usize + 3] = fields_offset;
}
self.create_item(Tag::StructType, i)
}
Key::FunctionType {
return_type,
parameters,
} => {
let info = FunctionInfo::new(
return_type == self.get_simple_type(SimpleType::Void),
parameters.len() as u32,
);
let start = self.push_word(info.pack());
self.extend_words([return_type.into_u32()]);
_ = self.extend_words(parameters.into_iter().map(|i| i.index() as u32));
self.create_item(Tag::FunctionType, start)
}
Key::TrueValue => self.create_item(Tag::TrueValue, 0),
Key::FalseValue => self.create_item(Tag::FalseValue, 0),
}
}
fn extend_strings<B: AsRef<[u8]>>(&mut self, b: B) -> u32 {
let idx = self.strings.len() as u32;
self.strings.extend(b.as_ref());
idx
}
fn extend_words<I: IntoIterator<Item = u32>>(&mut self, i: I) -> u32 {
let idx = self.words.len() as u32;
self.words.extend(i);
idx
}
fn push_word(&mut self, word: u32) -> u32 {
let idx = self.words.len() as u32;
self.words.push(word);
idx
}
fn create_item(&mut self, tag: Tag, index: u32) -> Index {
let len = self.len();
self.tags.push(tag);
self.indices.push(index);
Index::new(len)
}
pub fn get_key(&self, index: Index) -> Key {
let item = self.get_item(index).unwrap();
match item.tag {
Tag::String => {
let start = self.words[item.idx()];
let len = self.words[item.idx() + 1];
let str = unsafe {
core::str::from_utf8_unchecked(&self.strings[start as usize..][..len as usize])
};
Key::String { str }
}
Tag::UIntSmall => Key::UIntSmall {
bits: item.index as u32,
},
Tag::SIntSmall => Key::SIntSmall {
bits: item.index as i32,
},
Tag::F32 => Key::F32 {
bits: f32::from_le_bytes(item.index.to_le_bytes()),
},
Tag::F64 => {
let idx = item.idx();
let bits = from_lo_hi_dwords(self.words[idx], self.words[idx + 1]);
Key::F64 {
bits: f64::from_le_bytes(bits.to_le_bytes()),
}
}
Tag::SInt64 => {
let bits =
from_lo_hi_dwords(self.words[item.idx()], self.words[item.idx() + 1]) as i64;
Key::SInt64 { bits }
}
Tag::UInt64 => {
let bits = from_lo_hi_dwords(self.words[item.idx()], self.words[item.idx() + 1]);
Key::UInt64 { bits }
}
Tag::NegativeInt => {
let len = self.words[item.idx()];
let start = item.idx() + 1;
let end = start + len as usize;
let data = BigUint::from_slice(&self.words[start..end]);
let bigint = BigInt::from_biguint(Sign::Minus, data);
Key::NegativeInt { bigint }
}
Tag::PositiveInt => {
let len = self.words[item.idx()];
let start = item.idx() + 1;
let end = start + len as usize;
let data = BigUint::from_slice(&self.words[start..end]);
let bigint = BigInt::from_biguint(Sign::Plus, data);
Key::PositiveInt { bigint }
}
Tag::SimpleType => {
let ty = item.idx() as u32;
Key::SimpleType {
ty: SimpleType::from(ty),
}
}
Tag::PointerType => {
let pointee = Index::new(self.words[item.idx()]);
let flags = PointerFlags::unpack(self.words[item.idx() + 1] as u8);
Key::PointerType { pointee, flags }
}
Tag::ArrayType => {
let pointee = Index::new(self.words[item.idx()]);
let flags = PointerFlags::unpack(self.words[item.idx() + 1] as u8);
let length = self.words[item.idx() + 2];
Key::ArrayType {
pointee,
flags,
length,
}
}
Tag::StructType => {
let name = Index::new(self.words[item.idx()]);
let decl = super::Index::from_u32(self.words[item.idx() + 1]).unwrap();
let flags = StructFlags::unpack(self.words[item.idx() + 2]);
let fields = if flags.num_fields != 0 {
let fields_offset = self.words[item.idx() + 3] as usize;
let fields_end = fields_offset + flags.num_fields as usize * 2;
self.words[fields_offset..fields_end]
.iter()
.cloned()
.array_chunks::<2>()
.map(|[n, t]| (Index::new(n), Index::new(t)))
.collect::<Vec<_>>()
} else {
vec![]
};
Key::StructType {
name,
decl,
packed: flags.packed,
c_like: flags.c_like,
fields,
}
}
Tag::FunctionType => {
let info = FunctionInfo::unpack(self.words[item.idx()]);
let len = info.len();
let (return_type, parameters) = if info.void_return {
let start = item.idx() + 1;
let end = start + len as usize;
let params = self.words[start..end]
.iter()
.map(|&i| Index::new(i))
.collect::<Vec<_>>();
(
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Void,
}),
params,
)
} else {
let return_type = Index::new(self.words[item.idx() + 1]);
let start = item.idx() + 2;
let end = start + len as usize;
let params = self.words[start..end]
.iter()
.map(|&i| Index::new(i))
.collect::<Vec<_>>();
(return_type, params)
};
Key::FunctionType {
return_type,
parameters,
}
}
Tag::TrueValue => Key::TrueValue,
Tag::FalseValue => Key::FalseValue,
}
}
pub fn try_get_index(&self, key: &Key) -> Option<Index> {
let mut hasher = std::hash::DefaultHasher::new();
key.hash(&mut hasher);
let digest = hasher.finish();
self.hashed.get(&digest).cloned()
}
pub fn get_assume_present(&self, key: &Key) -> Index {
self.try_get_index(&key)
.expect(&format!("key {key:?} not present in pool."))
}
pub fn get_int_type(&mut self, signed: bool, bits: u16) -> Index {
let key = match signed {
true => Key::SimpleType {
ty: SimpleType::SInt(bits),
},
false => Key::SimpleType {
ty: SimpleType::UInt(bits),
},
};
self.get_or_insert(key)
}
pub fn get_unsigned_integer(&mut self, value: u64) -> Index {
let key = match value {
_ if value <= u32::MAX as u64 => Key::UIntSmall { bits: value as u32 },
_ => Key::UInt64 { bits: value as u64 },
};
self.get_or_insert(key)
}
pub fn get_bytes_index(&mut self, bytes: &[u8]) -> Index {
self.get_or_insert(Key::Bytes { bytes })
}
pub fn try_get_bytes_index(&self, bytes: &[u8]) -> Option<Index> {
self.try_get_index(&Key::Bytes { bytes })
}
pub fn insert_string(&mut self, str: &str) -> Index {
self.get_string_index(str)
}
pub fn insert_bytes(&mut self, bytes: &[u8]) -> Index {
self.get_bytes_index(bytes)
}
pub fn get_string_index(&mut self, str: &str) -> Index {
self.get_or_insert(Key::String { str })
}
pub fn try_get_string_index(&self, str: &str) -> Option<Index> {
self.try_get_index(&Key::String { str })
}
pub fn get_simple_type(&mut self, ty: SimpleType) -> Index {
self.get_or_insert(Key::SimpleType { ty })
}
pub fn try_get_simple_type(&self, ty: SimpleType) -> Option<Index> {
self.try_get_index(&Key::SimpleType { ty })
}
pub fn get_function_type<P: IntoIterator<Item = Index>>(
&mut self,
return_type: Index,
parameters: P,
) -> Index {
self.get_or_insert(Key::FunctionType {
return_type,
parameters: parameters.into_iter().collect(),
})
}
pub fn try_get_function_type<P: IntoIterator<Item = Index>>(
&self,
return_type: Index,
parameters: P,
) -> Option<Index> {
self.try_get_index(&Key::FunctionType {
return_type,
parameters: parameters.into_iter().collect(),
})
}
pub fn try_get_pointee_type(&self, pointer: Index) -> Option<Index> {
match self.get_key(pointer) {
Key::PointerType { pointee, .. } | Key::ArrayType { pointee, .. } => Some(pointee),
_ => None,
}
}
pub fn try_get_return_type(&self, func: Index) -> Option<Index> {
match self.get_key(func) {
Key::FunctionType { return_type, .. } => Some(return_type),
_ => None,
}
}
pub fn get_pointer_type(&mut self, pointee: Index, flags: Option<PointerFlags>) -> Index {
let key = Key::PointerType {
pointee,
flags: flags.unwrap_or_default(),
};
self.get_or_insert(key)
}
pub fn try_get_pointer_type(
&self,
pointee: Index,
flags: Option<PointerFlags>,
) -> Option<Index> {
self.try_get_index(
&(Key::PointerType {
pointee,
flags: flags.unwrap_or_default(),
}),
)
}
pub fn insert_or_replace_struct_type<I: IntoIterator<Item = (Index, Index)>>(
&mut self,
name: Index,
decl: super::Index,
packed: bool,
c_like: bool,
fields: I,
) -> Index {
let key = Key::StructType {
name,
decl,
packed,
c_like,
fields: vec![],
};
if let Some(i) = self.try_get_index(&key).and_then(|i| self.get_item(i)) {
let fields_offset = self.extend_words(
fields
.into_iter()
.map(|(n, t)| [n.into_u32(), t.into_u32()])
.flatten(),
);
self.words[i.idx() + 3] = fields_offset;
let fields_end = self.words.len() as u32;
let num_fields = (fields_end - fields_offset) / 2;
let flags = StructFlags::new(packed, c_like, num_fields).pack();
self.words[i.idx() + 2] = flags;
}
self.get_or_insert(key)
}
pub fn get_struct_type(&mut self, name: Index, decl: super::Index) -> Index {
let key = Key::StructType {
name,
decl,
packed: false,
c_like: false,
fields: vec![],
};
self.get_or_insert(key)
}
pub fn try_get_struct_type(&self, name: Index, decl: super::Index) -> Option<Index> {
self.try_get_index(&Key::StructType {
name,
decl,
packed: false,
c_like: false,
fields: vec![],
})
}
pub fn get_array_type(
&mut self,
pointee: Index,
flags: Option<PointerFlags>,
length: u32,
) -> Index {
let key = Key::ArrayType {
pointee,
flags: flags.unwrap_or_default(),
length,
};
self.get_or_insert(key)
}
pub fn try_get_array_type(
&self,
pointee: Index,
flags: Option<PointerFlags>,
length: u32,
) -> Option<Index> {
self.try_get_index(&Key::ArrayType {
pointee,
flags: flags.unwrap_or_default(),
length,
})
}
pub fn get_str(&self, index: Index) -> &str {
let key = self.get_key(index);
assert!(matches!(key, Key::String { .. }));
variant!(key => Key::String { str });
str
}
pub fn get_bytes(&self, index: Index) -> &[u8] {
let key = self.get_key(index);
assert!(matches!(key, Key::Bytes { .. }));
variant!(key => Key::Bytes { bytes });
bytes
}
fn check_bounds(&self, index: Index) -> Option<Index> {
((index.index() as u32) < self.len()).then_some(index)
}
pub(super) fn get_item(&self, index: Index) -> Option<Item> {
self.check_bounds(index).map(|i| Item {
tag: self.tags[i.index()],
index: self.indices[i.index()],
})
}
}
impl InternPool {
pub fn is_function(&self, index: Index) -> bool {
matches!(self.get_key(index), Key::FunctionType { .. })
}
pub fn is_type(&self, index: Index) -> bool {
matches!(
self.get_key(index),
Key::FunctionType { .. }
| Key::ArrayType { .. }
| Key::PointerType { .. }
| Key::SimpleType { .. }
| Key::StructType { .. }
)
}
}