1use crate::{Pointer, Result};
2use ruint::aliases::U256;
3use std::{
4 fmt,
5 path::{Path, PathBuf},
6};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct BackendConfig {
15 pub opt_level: OptimizationLevel,
17 pub is_dumping: bool,
19 pub debug_assertions: bool,
21 pub debug_support: bool,
25 pub profiling_support: bool,
29 pub simple_perf: bool,
41 pub debug_file: Option<PathBuf>,
43}
44
45impl Default for BackendConfig {
46 fn default() -> Self {
47 Self {
48 opt_level: OptimizationLevel::Default,
49 is_dumping: false,
50 debug_assertions: cfg!(debug_assertions),
51 debug_support: true,
52 profiling_support: false,
53 simple_perf: true,
54 debug_file: None,
55 }
56 }
57}
58
59#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
61pub enum OptimizationLevel {
62 None,
64 Less,
66 #[default]
68 Default,
69 Aggressive,
74}
75
76impl std::str::FromStr for OptimizationLevel {
77 type Err = String;
78
79 fn from_str(s: &str) -> Result<Self, Self::Err> {
80 Ok(match s {
81 "0" | "none" => Self::None,
82 "1" | "less" => Self::Less,
83 "2" | "default" => Self::Default,
84 "3" | "aggressive" => Self::Aggressive,
85 _ => return Err(format!("unknown optimization level: {s}")),
86 })
87 }
88}
89
90#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
92pub enum IntCC {
93 Equal,
95 NotEqual,
97 SignedLessThan,
99 SignedGreaterThanOrEqual,
101 SignedGreaterThan,
103 SignedLessThanOrEqual,
105 UnsignedLessThan,
107 UnsignedGreaterThanOrEqual,
109 UnsignedGreaterThan,
111 UnsignedLessThanOrEqual,
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119#[non_exhaustive]
120pub enum Attribute {
121 WillReturn,
123 NoReturn,
124 NoFree,
125 NoRecurse,
126 NoSync,
127 NoUnwind,
128 NonLazyBind,
129 UWTable,
130 AllFramePointers,
131 NativeTargetCpu,
132 Cold,
133 Hot,
134 HintInline,
135 AlwaysInline,
136 NoInline,
137 Speculatable,
138
139 NoAlias,
141 NoCapture,
142 NoUndef,
143 Align(u64),
144 NonNull,
145 Dereferenceable(u64),
146 SRet(u64),
148 ReadNone,
149 ReadOnly,
150 WriteOnly,
151 Writable,
152 ArgMemOnly,
154 Initializes(u64),
156 DeadOnReturn,
159 }
161
162#[derive(Clone, Copy, Debug, PartialEq, Eq)]
164pub enum Linkage {
165 Import,
167 Public,
169 Private,
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq)]
175pub enum FunctionAttributeLocation {
176 Return,
178 Param(u32),
180 Function,
182}
183
184#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
186pub enum CallConv {
187 #[default]
188 Default,
189 Cold,
191}
192
193#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
195pub enum TailCallKind {
196 #[default]
197 None,
198 Tail,
199 MustTail,
200 NoTail,
201}
202
203pub trait BackendTypes: Sized {
204 type Type: Copy + Eq + fmt::Debug;
205 type Value: Copy + Eq + fmt::Debug;
206 type StackSlot: Copy + Eq + fmt::Debug;
207 type BasicBlock: Copy + Eq + fmt::Debug;
208 type Function: Copy + Eq + fmt::Debug;
209}
210
211#[allow(clippy::missing_safety_doc)]
212pub trait Backend: BackendTypes + TypeMethods {
213 type Builder<'a>: Builder<
214 Type = Self::Type,
215 Value = Self::Value,
216 StackSlot = Self::StackSlot,
217 BasicBlock = Self::BasicBlock,
218 Function = Self::Function,
219 >
220 where
221 Self: 'a;
222 type FuncId: Copy + Eq + std::hash::Hash + fmt::Debug;
223
224 fn ir_extension(&self) -> &'static str;
225
226 fn set_module_name(&mut self, name: &str);
227
228 fn config(&self) -> &BackendConfig;
230
231 fn apply_config(&mut self, config: BackendConfig);
235
236 fn finalize_debug_info(&mut self) -> Result<()> {
240 Ok(())
241 }
242 fn dump_ir(&mut self, path: &Path) -> Result<()>;
243 fn dump_disasm(&mut self, path: &Path) -> Result<()>;
244
245 fn is_aot(&self) -> bool;
246
247 fn function_name_is_unique(&self, name: &str) -> bool;
248
249 fn build_function(
250 &mut self,
251 name: &str,
252 ret: Option<Self::Type>,
253 params: &[Self::Type],
254 param_names: &[&str],
255 linkage: Linkage,
256 ) -> Result<(Self::Builder<'_>, Self::FuncId)>;
257 fn verify_module(&mut self) -> Result<()>;
258 fn optimize_module(&mut self) -> Result<()>;
259 fn write_object<W: std::io::Write>(&mut self, w: W) -> Result<()>;
260 fn jit_function(&mut self, id: Self::FuncId) -> Result<usize>;
261
262 fn function_name(&self, id: Self::FuncId) -> Option<&str>;
264
265 fn function_sizes(&self) -> Vec<(String, usize)> {
267 Vec::new()
268 }
269
270 fn clear_ir(&mut self) -> Result<()>;
275
276 unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()>;
277 unsafe fn free_all_functions(&mut self) -> Result<()>;
278}
279
280pub trait TypeMethods: BackendTypes {
281 fn type_ptr(&self) -> Self::Type;
282 fn type_ptr_sized_int(&self) -> Self::Type;
283 fn type_int(&self, bits: u32) -> Self::Type;
284 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type;
285 fn type_bit_width(&self, ty: Self::Type) -> u32;
286}
287
288pub trait Builder: BackendTypes + TypeMethods {
289 fn create_block(&mut self, name: &str) -> Self::BasicBlock;
290 fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock;
291 fn switch_to_block(&mut self, block: Self::BasicBlock);
292 fn seal_block(&mut self, block: Self::BasicBlock);
293 fn seal_all_blocks(&mut self);
294 fn set_current_block_cold(&mut self);
295 fn current_block(&mut self) -> Option<Self::BasicBlock>;
296 fn block_addr(&mut self, block: Self::BasicBlock) -> Option<Self::Value>;
297
298 fn add_comment_to_current_inst(&mut self, comment: &str);
299
300 fn set_debug_location(&mut self, _line: u32, _col: u32) {}
302
303 fn clear_debug_location(&mut self) {}
305
306 fn fn_param(&mut self, index: usize) -> Self::Value;
307 fn num_fn_params(&self) -> usize;
308
309 fn bool_const(&mut self, value: bool) -> Self::Value;
310 fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value;
312 fn uconst(&mut self, ty: Self::Type, value: u64) -> Self::Value;
313 fn iconst_256(&mut self, value: impl TryInto<U256>) -> Self::Value;
314 fn cstr_const(&mut self, value: &std::ffi::CStr) -> Self::Value {
315 self.str_const(value.to_str().unwrap())
316 }
317 fn str_const(&mut self, value: &str) -> Self::Value;
318 fn nullptr(&mut self) -> Self::Value;
319
320 fn new_stack_slot(&mut self, ty: Self::Type, name: &str) -> Pointer<Self> {
321 Pointer::new_stack_slot(self, ty, name)
322 }
323 fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot;
324 fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value;
325 fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot);
326 fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value;
327
328 fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value;
330 fn load_aligned(
332 &mut self,
333 ty: Self::Type,
334 ptr: Self::Value,
335 align: usize,
336 name: &str,
337 ) -> Self::Value;
338 fn store(&mut self, value: Self::Value, ptr: Self::Value);
340 fn store_aligned(&mut self, value: Self::Value, ptr: Self::Value, align: usize);
342
343 fn nop(&mut self);
344 fn ret(&mut self, values: &[Self::Value]);
345 fn assume(&mut self, cond: Self::Value) {
346 let _ = cond;
347 }
348
349 fn icmp(&mut self, cond: IntCC, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
350 fn icmp_imm(&mut self, cond: IntCC, lhs: Self::Value, rhs: i64) -> Self::Value;
351 fn is_null(&mut self, ptr: Self::Value) -> Self::Value;
352 fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value;
353
354 fn br(&mut self, dest: Self::BasicBlock);
355 fn brif(
356 &mut self,
357 cond: Self::Value,
358 then_block: Self::BasicBlock,
359 else_block: Self::BasicBlock,
360 );
361 fn brif_cold(
362 &mut self,
363 cond: Self::Value,
364 then_block: Self::BasicBlock,
365 else_block: Self::BasicBlock,
366 then_is_cold: bool,
367 ) {
368 let _ = then_is_cold;
369 self.brif(cond, then_block, else_block)
370 }
371 fn switch(
372 &mut self,
373 index: Self::Value,
374 default: Self::BasicBlock,
375 targets: &[(u64, Self::BasicBlock)],
376 default_is_cold: bool,
377 );
378 fn br_indirect(&mut self, address: Self::Value, destinations: &[Self::BasicBlock]);
379 fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value;
380 fn select(
381 &mut self,
382 cond: Self::Value,
383 then_value: Self::Value,
384 else_value: Self::Value,
385 ) -> Self::Value;
386 fn lazy_select(
387 &mut self,
388 cond: Self::Value,
389 ty: Self::Type,
390 then_value: impl FnOnce(&mut Self) -> Self::Value,
391 else_value: impl FnOnce(&mut Self) -> Self::Value,
392 ) -> Self::Value;
393
394 fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
395 fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
396 fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
397 fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
398 fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
399 fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
400 fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
401
402 fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
403 fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
404 fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
405
406 fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
408 fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
409
410 fn uadd_sat(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
411
412 fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
413 fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
414 fn bswap(&mut self, value: Self::Value) -> Self::Value;
415
416 fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
417 fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
418 fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
419 fn bitnot(&mut self, value: Self::Value) -> Self::Value;
420 fn clz(&mut self, value: Self::Value) -> Self::Value;
421
422 fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
423 fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
424 fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
425
426 fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
427 fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
428 fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
429
430 fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
431 fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
432 #[doc(alias = "trunc")]
433 fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value;
434
435 fn inttoptr(&mut self, value: Self::Value, ty: Self::Type) -> Self::Value;
437
438 fn gep(
439 &mut self,
440 ty: Self::Type,
441 ptr: Self::Value,
442 indexes: &[Self::Value],
443 name: &str,
444 ) -> Self::Value;
445
446 #[must_use]
447 fn call(&mut self, function: Self::Function, args: &[Self::Value]) -> Option<Self::Value> {
448 self.tail_call(function, args, TailCallKind::None)
449 }
450 #[must_use]
451 fn tail_call(
452 &mut self,
453 function: Self::Function,
454 args: &[Self::Value],
455 tail_call: TailCallKind,
456 ) -> Option<Self::Value>;
457
458 fn is_compile_time_known(&mut self, value: Self::Value) -> Option<Self::Value>;
460
461 fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value);
462 fn memcpy_inline(&mut self, dst: Self::Value, src: Self::Value, len: i64) {
463 let len = self.iconst(self.type_int(64), len);
464 self.memcpy(dst, src, len);
465 }
466
467 fn unreachable(&mut self);
468
469 fn get_or_build_function(
470 &mut self,
471 name: &str,
472 params: &[Self::Type],
473 ret: Option<Self::Type>,
474 linkage: Linkage,
475 build: impl FnOnce(&mut Self),
476 ) -> Self::Function;
477
478 fn get_function(&mut self, name: &str) -> Option<Self::Function>;
479
480 fn get_printf_function(&mut self) -> Self::Function;
481
482 fn add_function(
486 &mut self,
487 name: &str,
488 params: &[Self::Type],
489 ret: Option<Self::Type>,
490 address: Option<usize>,
491 linkage: Linkage,
492 call_conv: CallConv,
493 ) -> Self::Function;
494
495 fn add_function_stub(
497 &mut self,
498 function: Self::Function,
499 call_conv: CallConv,
500 ) -> Self::Function {
501 let _ = call_conv;
502 function
503 }
504
505 fn add_function_attribute(
509 &mut self,
510 function: Option<Self::Function>,
511 attribute: Attribute,
512 loc: FunctionAttributeLocation,
513 );
514}