1575 lines
50 KiB
Rust
1575 lines
50 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,
|
||
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 { .. }
|
||
)
|
||
}
|
||
}
|