Skip to main content

sonatina_ir/
types.rs

1//! This module contains Sonatina IR types definitions.
2
3use 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    /// Returns `[StructDef]` if the given type is a struct type.
43    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/// Sonatina IR types definition.
123#[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/// An opaque reference to [`CompoundTypeData`].
137#[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}