revmc_backend/
traits.rs

1use crate::{Pointer, Result};
2use ruint::aliases::U256;
3use std::{fmt, path::Path};
4
5/// Target machine.
6#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum Target {
8    /// The host machine.
9    Native,
10    /// LLVM-style target triple.
11    ///
12    /// Ref: <https://llvm.org/docs/LangRef.html#target-triple>
13    Triple {
14        /// The target triple.
15        triple: String,
16        /// The target CPU.
17        cpu: Option<String>,
18        /// The target features string.
19        features: Option<String>,
20    },
21}
22
23impl Default for Target {
24    fn default() -> Self {
25        Self::Native
26    }
27}
28
29impl std::str::FromStr for Target {
30    type Err = std::convert::Infallible;
31
32    fn from_str(s: &str) -> Result<Self, Self::Err> {
33        Ok(Self::triple(s))
34    }
35}
36
37impl Target {
38    /// Creates a target from a triple string.
39    ///
40    /// `cpu` and `features` are ignored if `triple` is `native`.
41    pub fn new(
42        triple: impl AsRef<str> + Into<String>,
43        cpu: Option<String>,
44        features: Option<String>,
45    ) -> Self {
46        if triple.as_ref() == "native" {
47            return Self::Native;
48        }
49        Self::Triple { triple: triple.into(), cpu, features }
50    }
51
52    /// Creates a target from a triple string.
53    pub fn triple(triple: impl AsRef<str> + Into<String>) -> Self {
54        Self::new(triple, None, None)
55    }
56}
57
58/// Optimization level.
59#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
60pub enum OptimizationLevel {
61    /// No optimizations.
62    None,
63    /// Less optimizations.
64    Less,
65    /// Default optimizations.
66    Default,
67    /// Aggressive optimizations.
68    Aggressive,
69}
70
71impl std::str::FromStr for OptimizationLevel {
72    type Err = String;
73
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        Ok(match s {
76            "0" | "none" => Self::None,
77            "1" | "less" => Self::Less,
78            "2" | "default" => Self::Default,
79            "3" | "aggressive" => Self::Aggressive,
80            _ => return Err(format!("unknown optimization level: {s}")),
81        })
82    }
83}
84
85/// Integer comparison condition.
86#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
87pub enum IntCC {
88    /// `==`.
89    Equal,
90    /// `!=`.
91    NotEqual,
92    /// Signed `<`.
93    SignedLessThan,
94    /// Signed `>=`.
95    SignedGreaterThanOrEqual,
96    /// Signed `>`.
97    SignedGreaterThan,
98    /// Signed `<=`.
99    SignedLessThanOrEqual,
100    /// Unsigned `<`.
101    UnsignedLessThan,
102    /// Unsigned `>=`.
103    UnsignedGreaterThanOrEqual,
104    /// Unsigned `>`.
105    UnsignedGreaterThan,
106    /// Unsigned `<=`.
107    UnsignedLessThanOrEqual,
108}
109
110/// Function or parameter attribute.
111///
112/// Mostly copied from [LLVM](https://llvm.org/docs/LangRef.html).
113#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114#[non_exhaustive]
115pub enum Attribute {
116    // Function attributes.
117    WillReturn,
118    NoReturn,
119    NoFree,
120    NoRecurse,
121    NoSync,
122    NoUnwind,
123    AllFramePointers,
124    NativeTargetCpu,
125    Cold,
126    Hot,
127    HintInline,
128    AlwaysInline,
129    NoInline,
130    Speculatable,
131
132    // Parameter attributes.
133    NoAlias,
134    NoCapture,
135    NoUndef,
136    Align(u64),
137    NonNull,
138    Dereferenceable(u64),
139    /// Size of the return type in bytes.
140    SRet(u64),
141    ReadNone,
142    ReadOnly,
143    WriteOnly,
144    Writable,
145    // TODO: Range?
146}
147
148/// Linkage type.
149#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum Linkage {
151    /// Defined outside of the module.
152    Import,
153    /// Defined in the module and visible outside.
154    Public,
155    /// Defined in the module, but not visible outside.
156    Private,
157}
158
159/// Determines where on a function an attribute is assigned to.
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub enum FunctionAttributeLocation {
162    /// Assign to the function's return type.
163    Return,
164    /// Assign to one of the function's params (0-indexed).
165    Param(u32),
166    /// Assign to the function itself.
167    Function,
168}
169
170pub trait BackendTypes: Sized {
171    type Type: Copy + Eq + fmt::Debug;
172    type Value: Copy + Eq + fmt::Debug;
173    type StackSlot: Copy + Eq + fmt::Debug;
174    type BasicBlock: Copy + Eq + fmt::Debug;
175    type Function: Copy + Eq + fmt::Debug;
176}
177
178#[allow(clippy::missing_safety_doc)]
179pub trait Backend: BackendTypes + TypeMethods {
180    type Builder<'a>: Builder<
181        Type = Self::Type,
182        Value = Self::Value,
183        StackSlot = Self::StackSlot,
184        BasicBlock = Self::BasicBlock,
185        Function = Self::Function,
186    >
187    where
188        Self: 'a;
189    type FuncId: Copy + Eq + std::hash::Hash + fmt::Debug;
190
191    fn ir_extension(&self) -> &'static str;
192
193    fn set_module_name(&mut self, name: &str);
194
195    fn set_is_dumping(&mut self, yes: bool);
196    fn set_debug_assertions(&mut self, yes: bool);
197    fn opt_level(&self) -> OptimizationLevel;
198    fn set_opt_level(&mut self, level: OptimizationLevel);
199    fn dump_ir(&mut self, path: &Path) -> Result<()>;
200    fn dump_disasm(&mut self, path: &Path) -> Result<()>;
201
202    fn is_aot(&self) -> bool;
203
204    fn build_function(
205        &mut self,
206        name: &str,
207        ret: Option<Self::Type>,
208        params: &[Self::Type],
209        param_names: &[&str],
210        linkage: Linkage,
211    ) -> Result<(Self::Builder<'_>, Self::FuncId)>;
212    fn verify_module(&mut self) -> Result<()>;
213    fn optimize_module(&mut self) -> Result<()>;
214    fn write_object<W: std::io::Write>(&mut self, w: W) -> Result<()>;
215    fn jit_function(&mut self, id: Self::FuncId) -> Result<usize>;
216    unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()>;
217    unsafe fn free_all_functions(&mut self) -> Result<()>;
218}
219
220pub trait TypeMethods: BackendTypes {
221    fn type_ptr(&self) -> Self::Type;
222    fn type_ptr_sized_int(&self) -> Self::Type;
223    fn type_int(&self, bits: u32) -> Self::Type;
224    fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type;
225    fn type_bit_width(&self, ty: Self::Type) -> u32;
226}
227
228pub trait Builder: BackendTypes + TypeMethods {
229    fn create_block(&mut self, name: &str) -> Self::BasicBlock;
230    fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock;
231    fn switch_to_block(&mut self, block: Self::BasicBlock);
232    fn seal_block(&mut self, block: Self::BasicBlock);
233    fn seal_all_blocks(&mut self);
234    fn set_current_block_cold(&mut self);
235    fn current_block(&mut self) -> Option<Self::BasicBlock>;
236
237    fn add_comment_to_current_inst(&mut self, comment: &str);
238
239    fn fn_param(&mut self, index: usize) -> Self::Value;
240
241    fn bool_const(&mut self, value: bool) -> Self::Value;
242    fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value;
243    fn iconst_256(&mut self, value: U256) -> Self::Value;
244    fn str_const(&mut self, value: &str) -> Self::Value;
245
246    fn new_stack_slot(&mut self, ty: Self::Type, name: &str) -> Pointer<Self> {
247        Pointer::new_stack_slot(self, ty, name)
248    }
249    fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot;
250    fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value;
251    fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot);
252    fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value;
253
254    fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value;
255    fn store(&mut self, value: Self::Value, ptr: Self::Value);
256
257    fn nop(&mut self);
258    fn ret(&mut self, values: &[Self::Value]);
259
260    fn icmp(&mut self, cond: IntCC, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
261    fn icmp_imm(&mut self, cond: IntCC, lhs: Self::Value, rhs: i64) -> Self::Value;
262    fn is_null(&mut self, ptr: Self::Value) -> Self::Value;
263    fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value;
264
265    fn br(&mut self, dest: Self::BasicBlock);
266    fn brif(
267        &mut self,
268        cond: Self::Value,
269        then_block: Self::BasicBlock,
270        else_block: Self::BasicBlock,
271    );
272    fn brif_cold(
273        &mut self,
274        cond: Self::Value,
275        then_block: Self::BasicBlock,
276        else_block: Self::BasicBlock,
277        then_is_cold: bool,
278    ) {
279        let _ = then_is_cold;
280        self.brif(cond, then_block, else_block)
281    }
282    fn switch(
283        &mut self,
284        index: Self::Value,
285        default: Self::BasicBlock,
286        targets: &[(u64, Self::BasicBlock)],
287        default_is_cold: bool,
288    );
289    fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value;
290    fn select(
291        &mut self,
292        cond: Self::Value,
293        then_value: Self::Value,
294        else_value: Self::Value,
295    ) -> Self::Value;
296    fn lazy_select(
297        &mut self,
298        cond: Self::Value,
299        ty: Self::Type,
300        then_value: impl FnOnce(&mut Self) -> Self::Value,
301        else_value: impl FnOnce(&mut Self) -> Self::Value,
302    ) -> Self::Value;
303
304    fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
305    fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
306    fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
307    fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
308    fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
309    fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
310    fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
311
312    fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
313    fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
314    fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
315
316    // `(result, overflow)`
317    fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
318    fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
319
320    fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
321    fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
322    fn bswap(&mut self, value: Self::Value) -> Self::Value;
323
324    fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
325    fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
326    fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
327    fn bitnot(&mut self, value: Self::Value) -> Self::Value;
328
329    fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
330    fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
331    fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
332
333    fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
334    fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
335    fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
336
337    fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
338    fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
339    #[doc(alias = "trunc")]
340    fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value;
341
342    fn gep(
343        &mut self,
344        ty: Self::Type,
345        ptr: Self::Value,
346        indexes: &[Self::Value],
347        name: &str,
348    ) -> Self::Value;
349
350    fn call(&mut self, function: Self::Function, args: &[Self::Value]) -> Option<Self::Value>;
351
352    fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value);
353    fn memcpy_inline(&mut self, dst: Self::Value, src: Self::Value, len: i64) {
354        let len = self.iconst(self.type_int(64), len);
355        self.memcpy(dst, src, len);
356    }
357
358    fn unreachable(&mut self);
359
360    fn get_or_build_function(
361        &mut self,
362        name: &str,
363        params: &[Self::Type],
364        ret: Option<Self::Type>,
365        linkage: Linkage,
366        build: impl FnOnce(&mut Self),
367    ) -> Self::Function;
368
369    fn get_function(&mut self, name: &str) -> Option<Self::Function>;
370
371    /// Adds a function to the module that's located at `address`.
372    ///
373    /// If `address` is `None`, the function must be built.
374    fn add_function(
375        &mut self,
376        name: &str,
377        params: &[Self::Type],
378        ret: Option<Self::Type>,
379        address: Option<usize>,
380        linkage: Linkage,
381    ) -> Self::Function;
382
383    /// Adds an attribute to a function, one of its parameters, or its return value.
384    ///
385    /// If `function` is `None`, the attribute is added to the current function.
386    fn add_function_attribute(
387        &mut self,
388        function: Option<Self::Function>,
389        attribute: Attribute,
390        loc: FunctionAttributeLocation,
391    );
392}