1301 lines
39 KiB
Rust
1301 lines
39 KiB
Rust
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<u8> 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 {
|
|
bit_width: u16,
|
|
},
|
|
SIntType {
|
|
bit_width: u16,
|
|
},
|
|
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,
|
|
}
|
|
|
|
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::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 { bit_width: bits } => bits.hash(state),
|
|
Key::SIntType { bit_width: 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 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(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<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()
|
|
}
|
|
}
|
|
|
|
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!(
|
|
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,},
|
|
I1 => Key::SIntType { bit_width: 1 },
|
|
U1 => Key::UIntType { bit_width: 1 },
|
|
I0 => Key::SIntType { bit_width: 0 },
|
|
U0 => Key::UIntType { bit_width: 0 },
|
|
I8 => Key::SIntType { bit_width: 8 },
|
|
U8 => Key::UIntType { bit_width: 8 },
|
|
I16 => Key::SIntType { bit_width: 16 },
|
|
U16 => Key::UIntType { bit_width: 16 },
|
|
I32 => Key::SIntType { bit_width: 32 },
|
|
U32 => Key::UIntType { bit_width: 32 },
|
|
I64 => Key::SIntType { bit_width: 64 },
|
|
U64 => Key::UIntType { bit_width: 64 },
|
|
I128 => Key::SIntType { bit_width: 128 },
|
|
U128 => Key::UIntType { bit_width: 128 },
|
|
TRUE => Key::TrueValue,
|
|
FALSE => 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 { bit_width: 0 })
|
|
}
|
|
pub fn get_i0_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 0 })
|
|
}
|
|
pub fn get_u1_type(&self) -> Index {
|
|
self.get_assume_present(&Key::UIntType { bit_width: 1 })
|
|
}
|
|
pub fn get_i1_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 1 })
|
|
}
|
|
pub fn get_u8_type(&self) -> Index {
|
|
self.get_assume_present(&Key::UIntType { bit_width: 8 })
|
|
}
|
|
pub fn get_i8_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 8 })
|
|
}
|
|
pub fn get_u16_type(&self) -> Index {
|
|
self.get_assume_present(&Key::UIntType { bit_width: 16 })
|
|
}
|
|
pub fn get_i16_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 16 })
|
|
}
|
|
pub fn get_u32_type(&self) -> Index {
|
|
self.get_assume_present(&Key::UIntType { bit_width: 32 })
|
|
}
|
|
pub fn get_i32_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 32 })
|
|
}
|
|
pub fn get_u64_type(&self) -> Index {
|
|
self.get_assume_present(&Key::UIntType { bit_width: 64 })
|
|
}
|
|
pub fn get_i64_type(&self) -> Index {
|
|
self.get_assume_present(&Key::SIntType { bit_width: 64 })
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct TypeInfo {
|
|
pub bitsize: u32,
|
|
pub bitalign: u32,
|
|
pub signed: bool,
|
|
}
|
|
|
|
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::SIntType { .. }
|
|
| Key::UIntType { .. },
|
|
) => Some(rhs),
|
|
(
|
|
Key::SimpleType {
|
|
ty: SimpleType::F32,
|
|
}
|
|
| Key::SimpleType {
|
|
ty: SimpleType::F64,
|
|
}
|
|
| Key::SimpleType {
|
|
ty: SimpleType::USize,
|
|
}
|
|
| Key::SimpleType {
|
|
ty: SimpleType::ISize,
|
|
}
|
|
| Key::SIntType { .. }
|
|
| Key::UIntType { .. },
|
|
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::UIntType { bit_width: bits } => {
|
|
let bits = bits as u32;
|
|
|
|
Type::from_bitsize_int(bits)
|
|
}
|
|
Key::SIntType { bit_width: bits } => {
|
|
let bits = bits as u32;
|
|
Type::from_bitsize_int(bits)
|
|
}
|
|
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::ComptimeInt => {
|
|
panic!("comptime int can't be turned into a mir type")
|
|
}
|
|
},
|
|
Key::ArrayType { .. } => {
|
|
panic!("arrays can't be directly accessed in mir")
|
|
}
|
|
Key::FunctionType { .. } | 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::UIntType { .. } => false,
|
|
Key::SIntType { .. } => true,
|
|
Key::SimpleType { ty } => match ty {
|
|
SimpleType::USize => false,
|
|
SimpleType::ISize => 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::UIntType { bit_width: bits } => {
|
|
let bits = bits as u32;
|
|
TypeInfo {
|
|
bitsize: bits,
|
|
bitalign: bits.next_multiple_of(8).next_power_of_two(),
|
|
signed: false,
|
|
}
|
|
}
|
|
Key::SIntType { bit_width: bits } => {
|
|
let bits = bits as u32;
|
|
TypeInfo {
|
|
bitsize: bits,
|
|
bitalign: bits.next_multiple_of(8).next_power_of_two(),
|
|
signed: true,
|
|
}
|
|
}
|
|
Key::SimpleType { ty } => match ty {
|
|
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::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 from_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_assume_present(&{
|
|
if i.signed {
|
|
Key::SIntType { bit_width: i.bits }
|
|
} else {
|
|
Key::UIntType { bit_width: 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_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.from_ast1_type(pointer_bits, ty))
|
|
.collect::<Vec<_>>();
|
|
let return_type =
|
|
self.from_ast1_type(pointer_bits, &return_type);
|
|
self.get_function_type(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::UIntType { bit_width: bits } => {
|
|
Type::Integer(IntegralType::new(false, bits))
|
|
}
|
|
Key::SIntType { bit_width: 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;
|
|
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::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 { bit_width: bits } => {
|
|
self.create_item(Tag::UIntType, bits as u32)
|
|
}
|
|
Key::SIntType { bit_width: 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<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(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 {
|
|
bit_width: item.index as u16,
|
|
},
|
|
Tag::UIntType => Key::UIntType {
|
|
bit_width: item.index as u16,
|
|
},
|
|
Tag::SimpleType => {
|
|
let ty = item.idx() as u8;
|
|
|
|
Key::SimpleType {
|
|
ty: unsafe { core::mem::transmute::<u8, SimpleType>(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::<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(i))
|
|
.collect::<Vec<_>>();
|
|
(
|
|
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::<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::SIntType { bit_width: bits },
|
|
false => Key::UIntType { bit_width: 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<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 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
|
|
}
|
|
|
|
fn check_bounds(&self, index: Index) -> Option<Index> {
|
|
(index.0 < self.len()).then_some(index)
|
|
}
|
|
|
|
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()],
|
|
})
|
|
}
|
|
}
|