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