diff --git a/src/ast2/intern.rs b/src/ast2/intern.rs new file mode 100644 index 0000000..c6528d6 --- /dev/null +++ b/src/ast2/intern.rs @@ -0,0 +1,1140 @@ +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 = 0, + F64, + Bool, + Void, + USize, + ISize, + ComptimeInt, +} + +impl From for SimpleType { + fn from(value: u8) -> Self { + match value { + 0 => Self::F32, + 1 => Self::F64, + 2 => Self::Bool, + 3 => Self::Void, + 4 => Self::USize, + 5 => Self::ISize, + 6 => Self::ComptimeInt, + _ => panic!("{value} is not a simple type"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Tag { + String, + SIntSmall, + UIntSmall, + TrueValue, + FalseValue, + UInt64, + SInt64, + F32, + F64, + PositiveInt, + NegativeInt, + UIntType, + SIntType, + SimpleType, + PointerType, + ArrayType, + FunctionType, + StructType, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct Item { + tag: Tag, + index: u32, +} + +#[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] +pub enum Key<'a> { + String { + str: &'a str, + }, + SIntSmall { + bits: i32, + }, + UIntSmall { + bits: u32, + }, + SInt64 { + bits: i64, + }, + UInt64 { + bits: u64, + }, + F32 { + bits: f32, + }, + F64 { + bits: f64, + }, + PositiveInt { + bigint: BigInt, + }, + NegativeInt { + bigint: BigInt, + }, + UIntType { + bits: u16, + }, + SIntType { + bits: u16, + }, + SimpleType { + ty: SimpleType, + }, + PointerType { + pointee: Index, + flags: PointerFlags, + }, + ArrayType { + pointee: Index, + flags: PointerFlags, + length: u32, + }, + FunctionType { + return_type: Index, + parameters: Vec, + }, + StructType { + decl: super::Index, + name: Index, + packed: bool, + c_like: bool, + /// vec of (Name, Type) + fields: Vec<(Index, Index)>, + }, + TrueValue, + FalseValue, +} + +impl Hash for Key<'_> { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + match self { + Key::String { str } => str.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::UIntType { bits } => bits.hash(state), + Key::SIntType { bits } => bits.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 PointerFlags { + pub fn new(is_const: bool, volatile: bool, noalias: bool) -> Self { + Self { + is_const, + volatile, + 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(pub u32); + +impl Display for Index { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#{}", self.0) + } +} + +impl Index { + pub fn into_u32(self) -> u32 { + unsafe { core::mem::transmute(self) } + } + 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 InternPool { + tags: Vec, + indices: Vec, + // + strings: Vec, + words: Vec, + hashed: BTreeMap, +} + +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() + } +} + +const STATIC_KEYS: [Key; 21] = [ + Key::SimpleType { + ty: SimpleType::Bool, + }, + Key::SimpleType { + ty: SimpleType::F32, + }, + Key::SimpleType { + ty: SimpleType::F64, + }, + Key::SimpleType { + ty: SimpleType::USize, + }, + Key::SimpleType { + ty: SimpleType::ISize, + }, + Key::SimpleType { + ty: SimpleType::Void, + }, + Key::SimpleType { + ty: SimpleType::ComptimeInt, + }, + Key::SIntType { bits: 1 }, + Key::UIntType { bits: 1 }, + Key::SIntType { bits: 0 }, + Key::UIntType { bits: 0 }, + Key::SIntType { bits: 8 }, + Key::UIntType { bits: 8 }, + Key::SIntType { bits: 16 }, + Key::UIntType { bits: 16 }, + Key::SIntType { bits: 32 }, + Key::UIntType { bits: 32 }, + Key::SIntType { bits: 64 }, + Key::UIntType { bits: 64 }, + Key::TrueValue, + Key::FalseValue, +]; + +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, + }) + } + pub fn get_u0_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 0 }) + } + pub fn get_i0_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 0 }) + } + pub fn get_u1_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 1 }) + } + pub fn get_i1_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 1 }) + } + pub fn get_u8_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 8 }) + } + pub fn get_i8_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 8 }) + } + pub fn get_u16_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 16 }) + } + pub fn get_i16_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 16 }) + } + pub fn get_u32_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 32 }) + } + pub fn get_i32_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 32 }) + } + pub fn get_u64_type(&self) -> Index { + self.get_assume_present(&Key::UIntType { bits: 64 }) + } + pub fn get_i64_type(&self) -> Index { + self.get_assume_present(&Key::SIntType { bits: 64 }) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct TypeInfo { + pub bitsize: u32, + pub bitalign: u32, +} + +impl InternPool { + pub fn size_of_type(&self, index: Index, ptr_size: TypeInfo) -> TypeInfo { + match self.get_key(index) { + Key::UIntType { bits } => { + let bits = bits as u32; + TypeInfo { + bitsize: bits, + bitalign: bits.next_multiple_of(8).next_power_of_two(), + } + } + Key::SIntType { bits } => { + let bits = bits as u32; + TypeInfo { + bitsize: bits, + bitalign: bits.next_multiple_of(8).next_power_of_two(), + } + } + Key::SimpleType { ty } => match ty { + SimpleType::F32 => TypeInfo { + bitsize: 32, + bitalign: 32, + }, + SimpleType::F64 => TypeInfo { + bitsize: 64, + bitalign: 64, + }, + SimpleType::Bool => TypeInfo { + bitsize: 1, + bitalign: 1, + }, + SimpleType::Void => TypeInfo { + bitsize: 0, + bitalign: 0, + }, + SimpleType::USize => ptr_size, + SimpleType::ISize => ptr_size, + 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, + ..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, + } + } + _ => { + panic!("index was not a type") + } + } + } + + 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::SIntType { bits: i.bits } + } else { + Key::UIntType { bits: 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 } => self + .get_assume_present(&Key::PointerType { + pointee: self.from_ast1_type(pointer_bits, &pointee), + flags: PointerFlags::new(*constness, false, false), + }), + crate::ast::Type::Fn { .. } => { + unimplemented!() + } + _ => { + 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::UIntType { bits } => { + Type::Integer(IntegralType::new(false, bits)) + } + Key::SIntType { bits } => { + Type::Integer(IntegralType::new(true, bits)) + } + Key::SimpleType { ty } => match ty { + SimpleType::F32 => { + Type::Floating(crate::ast::FloatingType::Binary32) + } + SimpleType::F64 => { + Type::Floating(crate::ast::FloatingType::Binary64) + } + 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(), + }, + 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; + +impl InternPool { + pub fn create() -> 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>>(&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::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::UIntType { bits } => { + self.create_item(Tag::UIntType, bits as u32) + } + Key::SIntType { bits } => { + self.create_item(Tag::SIntType, bits as u32) + } + Key::SimpleType { ty } => { + self.create_item(Tag::SimpleType, ty as u8 as u32) + } + Key::PointerType { pointee, flags } => { + let flags = flags.pack(); + let i = self.extend_words([pointee.0, flags as u32]); + self.create_item(Tag::PointerType, i) + } + Key::ArrayType { + pointee, + flags, + length, + } => { + let flags = flags.pack(); + let i = self.extend_words([pointee.0, 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.0)); + + 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>(&mut self, b: B) -> u32 { + let idx = self.strings.len() as u32; + self.strings.extend(b.as_ref()); + idx + } + fn extend_words>(&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(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::SIntType => Key::SIntType { + bits: item.index as u16, + }, + Tag::UIntType => Key::UIntType { + bits: item.index as u16, + }, + Tag::SimpleType => { + let ty = item.idx() as u8; + + Key::SimpleType { + ty: unsafe { core::mem::transmute::(ty) }, + } + } + Tag::PointerType => { + let pointee = Index(self.words[item.idx()]); + let flags = + PointerFlags::unpack(self.words[item.idx() + 1] as u8); + + Key::PointerType { pointee, flags } + } + Tag::ArrayType => { + let pointee = Index(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(self.words[item.idx()]); + let decl = super::Index::new(self.words[item.idx() + 1]); + 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(n), Index(t))) + .collect::>() + } 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(i)) + .collect::>(); + ( + self.get_assume_present(&Key::SimpleType { + ty: SimpleType::Void, + }), + params, + ) + } else { + let return_type = Index(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(i)) + .collect::>(); + (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 { + 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::SIntType { bits }, + false => Key::UIntType { bits }, + }; + + self.get_or_insert(key) + } + + 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 { + 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 { + self.try_get_index(&Key::SimpleType { ty }) + } + + pub fn get_function_type>( + &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>( + &self, + return_type: Index, + parameters: P, + ) -> Option { + self.try_get_index(&Key::FunctionType { + return_type, + parameters: parameters.into_iter().collect(), + }) + } + + pub fn get_pointer_type( + &mut self, + pointee: Index, + flags: Option, + ) -> 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, + ) -> Option { + self.try_get_index( + &(Key::PointerType { + pointee, + flags: flags.unwrap_or_default(), + }), + ) + } + + pub fn insert_or_replace_struct_type< + I: IntoIterator, + >( + &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 { + 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, + 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, + length: u32, + ) -> Option { + 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 + } + + fn check_bounds(&self, index: Index) -> Option { + (index.0 < self.len()).then_some(index) + } + + fn get_item(&self, index: Index) -> Option { + self.check_bounds(index).map(|i| Item { + tag: self.tags[i.index()], + index: self.indices[i.index()], + }) + } +} diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 191cad5..a1da2e8 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -10,1086 +10,11 @@ use intern::{InternPool, PointerFlags, StructFlags}; use num_bigint::BigInt; use crate::{ - ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, tokens::Token, - writeln_indented, + ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, + tokens::Token, writeln_indented, }; -pub mod intern { - 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 = 0, - F64, - Bool, - Void, - USize, - ISize, - ComptimeInt, - } - - impl From for SimpleType { - fn from(value: u8) -> Self { - match value { - 0 => Self::F32, - 1 => Self::F64, - 2 => Self::Bool, - 3 => Self::Void, - 4 => Self::USize, - 5 => Self::ISize, - 6 => Self::ComptimeInt, - _ => panic!("{value} is not a simple type"), - } - } - } - - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum Tag { - String, - SIntSmall, - UIntSmall, - TrueValue, - FalseValue, - UInt64, - SInt64, - F32, - F64, - PositiveInt, - NegativeInt, - UIntType, - SIntType, - SimpleType, - PointerType, - ArrayType, - FunctionType, - StructType, - } - - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - struct Item { - tag: Tag, - index: u32, - } - - #[derive(Debug, Clone, PartialEq)] - #[non_exhaustive] - pub enum Key<'a> { - String { - str: &'a str, - }, - SIntSmall { - bits: i32, - }, - UIntSmall { - bits: u32, - }, - SInt64 { - bits: i64, - }, - UInt64 { - bits: u64, - }, - F32 { - bits: f32, - }, - F64 { - bits: f64, - }, - PositiveInt { - bigint: BigInt, - }, - NegativeInt { - bigint: BigInt, - }, - UIntType { - bits: u16, - }, - SIntType { - bits: u16, - }, - SimpleType { - ty: SimpleType, - }, - PointerType { - pointee: Index, - flags: PointerFlags, - }, - ArrayType { - pointee: Index, - flags: PointerFlags, - length: u32, - }, - FunctionType { - return_type: Index, - parameters: Vec, - }, - StructType { - decl: super::Index, - name: Index, - packed: bool, - c_like: bool, - /// vec of (Name, Type) - fields: Vec<(Index, Index)>, - }, - TrueValue, - FalseValue, - } - - impl Hash for Key<'_> { - fn hash(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - match self { - Key::String { str } => str.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::UIntType { bits } => bits.hash(state), - Key::SIntType { bits } => bits.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 PointerFlags { - pub fn new(is_const: bool, volatile: bool, noalias: bool) -> Self { - Self { - is_const, - volatile, - 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(pub u32); - - impl Display for Index { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.0) - } - } - - impl Index { - pub fn into_u32(self) -> u32 { - unsafe { core::mem::transmute(self) } - } - 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 InternPool { - tags: Vec, - indices: Vec, - // - strings: Vec, - words: Vec, - hashed: BTreeMap, - } - - 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() - } - } - - const STATIC_KEYS: [Key; 21] = [ - Key::SimpleType { - ty: SimpleType::Bool, - }, - Key::SimpleType { - ty: SimpleType::F32, - }, - Key::SimpleType { - ty: SimpleType::F64, - }, - Key::SimpleType { - ty: SimpleType::USize, - }, - Key::SimpleType { - ty: SimpleType::ISize, - }, - Key::SimpleType { - ty: SimpleType::Void, - }, - Key::SimpleType { - ty: SimpleType::ComptimeInt, - }, - Key::SIntType { bits: 1 }, - Key::UIntType { bits: 1 }, - Key::SIntType { bits: 0 }, - Key::UIntType { bits: 0 }, - Key::SIntType { bits: 8 }, - Key::UIntType { bits: 8 }, - Key::SIntType { bits: 16 }, - Key::UIntType { bits: 16 }, - Key::SIntType { bits: 32 }, - Key::UIntType { bits: 32 }, - Key::SIntType { bits: 64 }, - Key::UIntType { bits: 64 }, - Key::TrueValue, - Key::FalseValue, - ]; - - 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, - }) - } - pub fn get_u0_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 0 }) - } - pub fn get_i0_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 0 }) - } - pub fn get_u1_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 1 }) - } - pub fn get_i1_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 1 }) - } - pub fn get_u8_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 8 }) - } - pub fn get_i8_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 8 }) - } - pub fn get_u16_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 16 }) - } - pub fn get_i16_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 16 }) - } - pub fn get_u32_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 32 }) - } - pub fn get_i32_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 32 }) - } - pub fn get_u64_type(&self) -> Index { - self.get_assume_present(&Key::UIntType { bits: 64 }) - } - pub fn get_i64_type(&self) -> Index { - self.get_assume_present(&Key::SIntType { bits: 64 }) - } - } - - #[derive(Debug, Clone, Copy)] - pub struct TypeInfo { - pub bitsize: u32, - pub bitalign: u32, - } - - impl InternPool { - pub fn size_of_type(&self, index: Index, ptr_size: TypeInfo) -> TypeInfo { - match self.get_key(index) { - Key::UIntType { bits } => { - let bits = bits as u32; - TypeInfo { - bitsize: bits, - bitalign: bits.next_multiple_of(8).next_power_of_two(), - } - } - Key::SIntType { bits } => { - let bits = bits as u32; - TypeInfo { - bitsize: bits, - bitalign: bits.next_multiple_of(8).next_power_of_two(), - } - } - Key::SimpleType { ty } => match ty { - SimpleType::F32 => TypeInfo { - bitsize: 32, - bitalign: 32, - }, - SimpleType::F64 => TypeInfo { - bitsize: 64, - bitalign: 64, - }, - SimpleType::Bool => TypeInfo { - bitsize: 1, - bitalign: 1, - }, - SimpleType::Void => TypeInfo { - bitsize: 0, - bitalign: 0, - }, - SimpleType::USize => ptr_size, - SimpleType::ISize => ptr_size, - 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, - ..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, - } - } - _ => { - panic!("index was not a type") - } - } - } - - 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::SIntType { bits: i.bits } - } else { - Key::UIntType { bits: 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 } => { - self.get_assume_present(&Key::PointerType { - pointee: self.from_ast1_type(pointer_bits, &pointee), - flags: PointerFlags::new(*constness, false, false), - }) - } - crate::ast::Type::Fn { .. } => { - unimplemented!() - } - _ => { - 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::UIntType { bits } => Type::Integer(IntegralType::new(false, bits)), - Key::SIntType { bits } => Type::Integer(IntegralType::new(true, bits)), - Key::SimpleType { ty } => match ty { - SimpleType::F32 => Type::Floating(crate::ast::FloatingType::Binary32), - SimpleType::F64 => Type::Floating(crate::ast::FloatingType::Binary64), - 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(), - }, - 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; - - impl InternPool { - pub fn create() -> 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>>(&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::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::UIntType { bits } => self.create_item(Tag::UIntType, bits as u32), - Key::SIntType { bits } => self.create_item(Tag::SIntType, bits as u32), - Key::SimpleType { ty } => self.create_item(Tag::SimpleType, ty as u8 as u32), - Key::PointerType { pointee, flags } => { - let flags = flags.pack(); - let i = self.extend_words([pointee.0, flags as u32]); - self.create_item(Tag::PointerType, i) - } - Key::ArrayType { - pointee, - flags, - length, - } => { - let flags = flags.pack(); - let i = self.extend_words([pointee.0, 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.0)); - - 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>(&mut self, b: B) -> u32 { - let idx = self.strings.len() as u32; - self.strings.extend(b.as_ref()); - idx - } - fn extend_words>(&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(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::SIntType => Key::SIntType { - bits: item.index as u16, - }, - Tag::UIntType => Key::UIntType { - bits: item.index as u16, - }, - Tag::SimpleType => { - let ty = item.idx() as u8; - - Key::SimpleType { - ty: unsafe { core::mem::transmute::(ty) }, - } - } - Tag::PointerType => { - let pointee = Index(self.words[item.idx()]); - let flags = PointerFlags::unpack(self.words[item.idx() + 1] as u8); - - Key::PointerType { pointee, flags } - } - Tag::ArrayType => { - let pointee = Index(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(self.words[item.idx()]); - let decl = super::Index::new(self.words[item.idx() + 1]); - 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(n), Index(t))) - .collect::>() - } 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(i)) - .collect::>(); - ( - self.get_assume_present(&Key::SimpleType { - ty: SimpleType::Void, - }), - params, - ) - } else { - let return_type = Index(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(i)) - .collect::>(); - (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 { - 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::SIntType { bits }, - false => Key::UIntType { bits }, - }; - - self.get_or_insert(key) - } - - 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 { - 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 { - self.try_get_index(&Key::SimpleType { ty }) - } - - pub fn get_function_type>( - &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>( - &self, - return_type: Index, - parameters: P, - ) -> Option { - self.try_get_index(&Key::FunctionType { - return_type, - parameters: parameters.into_iter().collect(), - }) - } - - pub fn get_pointer_type(&mut self, pointee: Index, flags: Option) -> 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, - ) -> Option { - self.try_get_index( - &(Key::PointerType { - pointee, - flags: flags.unwrap_or_default(), - }), - ) - } - - pub fn insert_or_replace_struct_type>( - &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 { - 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, - 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, - length: u32, - ) -> Option { - 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 - } - - fn check_bounds(&self, index: Index) -> Option { - (index.0 < self.len()).then_some(index) - } - - fn get_item(&self, index: Index) -> Option { - self.check_bounds(index).map(|i| Item { - tag: self.tags[i.index()], - index: self.indices[i.index()], - }) - } - } -} +pub mod intern; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum Tag {