1use std::cmp;
4
5use cranelift_entity::PrimaryMap;
6use fxhash::FxHashMap;
7use indexmap::IndexMap;
8
9#[derive(Debug, Default)]
10pub struct TypeStore {
11 compounds: PrimaryMap<CompoundType, CompoundTypeData>,
12 rev_types: FxHashMap<CompoundTypeData, CompoundType>,
13 struct_types: IndexMap<String, CompoundType>,
14}
15
16impl TypeStore {
17 pub fn make_ptr(&mut self, ty: Type) -> Type {
18 let ty = self.make_compound(CompoundTypeData::Ptr(ty));
19 Type::Compound(ty)
20 }
21
22 pub fn make_array(&mut self, elem: Type, len: usize) -> Type {
23 let ty = self.make_compound(CompoundTypeData::Array { elem, len });
24 Type::Compound(ty)
25 }
26
27 pub fn make_struct(&mut self, name: &str, fields: &[Type], packed: bool) -> Type {
28 let compound_data = CompoundTypeData::Struct(StructData {
29 name: name.to_string(),
30 fields: fields.to_vec(),
31 packed,
32 });
33 let compound = self.make_compound(compound_data);
34 debug_assert!(
35 !self.struct_types.contains_key(name),
36 "struct {name} is already defined"
37 );
38 self.struct_types.insert(name.to_string(), compound);
39 Type::Compound(compound)
40 }
41
42 pub fn struct_def(&self, ty: Type) -> Option<&StructData> {
44 match ty {
45 Type::Compound(compound) => match self.compounds[compound] {
46 CompoundTypeData::Struct(ref def) => Some(def),
47 _ => None,
48 },
49 _ => None,
50 }
51 }
52
53 pub fn array_def(&self, ty: Type) -> Option<(Type, usize)> {
54 match ty {
55 Type::Compound(compound) => match self.compounds[compound] {
56 CompoundTypeData::Array { elem, len } => Some((elem, len)),
57 _ => None,
58 },
59 _ => None,
60 }
61 }
62
63 pub fn struct_type_by_name(&self, name: &str) -> Option<Type> {
64 self.struct_types.get(name).map(|ty| Type::Compound(*ty))
65 }
66
67 pub fn all_struct_data(&self) -> impl Iterator<Item = &StructData> {
68 self.struct_types
69 .values()
70 .map(|compound_type| match self.compounds[*compound_type] {
71 CompoundTypeData::Struct(ref def) => def,
72 _ => unreachable!(),
73 })
74 }
75
76 pub fn deref(&self, ptr: Type) -> Option<Type> {
77 match ptr {
78 Type::Compound(ty) => {
79 let ty_data = &self.compounds[ty];
80 match ty_data {
81 CompoundTypeData::Ptr(ty) => Some(*ty),
82 _ => None,
83 }
84 }
85 _ => None,
86 }
87 }
88
89 pub fn is_integral(&self, ty: Type) -> bool {
90 ty.is_integral()
91 }
92
93 pub fn is_ptr(&self, ty: Type) -> bool {
94 match ty {
95 Type::Compound(compound) => self.compounds[compound].is_ptr(),
96 _ => false,
97 }
98 }
99
100 pub fn is_array(&self, ty: Type) -> bool {
101 match ty {
102 Type::Compound(compound) => self.compounds[compound].is_array(),
103 _ => false,
104 }
105 }
106
107 pub fn make_compound(&mut self, data: CompoundTypeData) -> CompoundType {
108 if let Some(compound) = self.rev_types.get(&data) {
109 *compound
110 } else {
111 let compound = self.compounds.push(data.clone());
112 self.rev_types.insert(data, compound);
113 compound
114 }
115 }
116
117 pub fn resolve_compound(&self, compound: CompoundType) -> &CompoundTypeData {
118 &self.compounds[compound]
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
124pub enum Type {
125 I1,
126 I8,
127 I16,
128 I32,
129 I64,
130 I128,
131 I256,
132 Compound(CompoundType),
133 Void,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)]
138pub struct CompoundType(u32);
139cranelift_entity::entity_impl!(CompoundType);
140
141#[derive(Debug, Clone, PartialEq, Eq, Hash)]
142pub enum CompoundTypeData {
143 Array { elem: Type, len: usize },
144 Ptr(Type),
145 Struct(StructData),
146}
147
148#[derive(Debug, Clone, PartialEq, Eq, Hash)]
149pub struct StructData {
150 pub name: String,
151 pub fields: Vec<Type>,
152 pub packed: bool,
153}
154
155impl CompoundTypeData {
156 pub fn is_array(&self) -> bool {
157 matches!(self, Self::Array { .. })
158 }
159
160 pub fn is_ptr(&self) -> bool {
161 matches!(self, Self::Ptr(_))
162 }
163}
164
165impl Type {
166 pub fn is_integral(&self) -> bool {
167 matches!(
168 self,
169 Self::I1 | Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 | Self::I256
170 )
171 }
172}
173
174impl cmp::PartialOrd for Type {
175 fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
176 use Type::*;
177
178 if self == rhs {
179 return Some(cmp::Ordering::Equal);
180 }
181
182 if !self.is_integral() || !rhs.is_integral() {
183 return None;
184 }
185
186 match (self, rhs) {
187 (I1, _) => Some(cmp::Ordering::Less),
188 (I8, I1) => Some(cmp::Ordering::Greater),
189 (I8, _) => Some(cmp::Ordering::Less),
190 (I16, I1 | I8) => Some(cmp::Ordering::Greater),
191 (I16, _) => Some(cmp::Ordering::Less),
192 (I32, I1 | I8 | I16) => Some(cmp::Ordering::Greater),
193 (I32, _) => Some(cmp::Ordering::Less),
194 (I64, I128 | I256) => Some(cmp::Ordering::Less),
195 (I64, _) => Some(cmp::Ordering::Greater),
196 (I128, I256) => Some(cmp::Ordering::Less),
197 (I128, _) => Some(cmp::Ordering::Greater),
198 (I256, _) => Some(cmp::Ordering::Greater),
199 (_, _) => unreachable!(),
200 }
201 }
202}