1use crate::{Pointer, Result};
2use ruint::aliases::U256;
3use std::{fmt, path::Path};
4
5#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum Target {
8 #[default]
10 Native,
11 Triple {
15 triple: String,
17 cpu: Option<String>,
19 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 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 pub fn triple(triple: impl AsRef<str> + Into<String>) -> Self {
49 Self::new(triple, None, None)
50 }
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
55pub enum OptimizationLevel {
56 None,
58 Less,
60 Default,
62 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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
82pub enum IntCC {
83 Equal,
85 NotEqual,
87 SignedLessThan,
89 SignedGreaterThanOrEqual,
91 SignedGreaterThan,
93 SignedLessThanOrEqual,
95 UnsignedLessThan,
97 UnsignedGreaterThanOrEqual,
99 UnsignedGreaterThan,
101 UnsignedLessThanOrEqual,
103}
104
105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109#[non_exhaustive]
110pub enum Attribute {
111 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 NoAlias,
129 NoCapture,
130 NoUndef,
131 Align(u64),
132 NonNull,
133 Dereferenceable(u64),
134 SRet(u64),
136 ReadNone,
137 ReadOnly,
138 WriteOnly,
139 Writable,
140 }
142
143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145pub enum Linkage {
146 Import,
148 Public,
150 Private,
152}
153
154#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156pub enum FunctionAttributeLocation {
157 Return,
159 Param(u32),
161 Function,
163}
164
165#[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
224 fn clear_ir(&mut self) -> Result<()>;
229
230 unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()>;
231 unsafe fn free_all_functions(&mut self) -> Result<()>;
232}
233
234pub trait TypeMethods: BackendTypes {
235 fn type_ptr(&self) -> Self::Type;
236 fn type_ptr_sized_int(&self) -> Self::Type;
237 fn type_int(&self, bits: u32) -> Self::Type;
238 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type;
239 fn type_bit_width(&self, ty: Self::Type) -> u32;
240}
241
242pub trait Builder: BackendTypes + TypeMethods {
243 fn create_block(&mut self, name: &str) -> Self::BasicBlock;
244 fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock;
245 fn switch_to_block(&mut self, block: Self::BasicBlock);
246 fn seal_block(&mut self, block: Self::BasicBlock);
247 fn seal_all_blocks(&mut self);
248 fn set_current_block_cold(&mut self);
249 fn current_block(&mut self) -> Option<Self::BasicBlock>;
250 fn block_addr(&mut self, block: Self::BasicBlock) -> Option<Self::Value>;
251
252 fn add_comment_to_current_inst(&mut self, comment: &str);
253
254 fn fn_param(&mut self, index: usize) -> Self::Value;
255 fn num_fn_params(&self) -> usize;
256
257 fn bool_const(&mut self, value: bool) -> Self::Value;
258 fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value;
260 fn uconst(&mut self, ty: Self::Type, value: u64) -> Self::Value;
261 fn iconst_256(&mut self, value: U256) -> Self::Value;
262 fn cstr_const(&mut self, value: &std::ffi::CStr) -> Self::Value {
263 self.str_const(value.to_str().unwrap())
264 }
265 fn str_const(&mut self, value: &str) -> Self::Value;
266 fn nullptr(&mut self) -> Self::Value;
267
268 fn new_stack_slot(&mut self, ty: Self::Type, name: &str) -> Pointer<Self> {
269 Pointer::new_stack_slot(self, ty, name)
270 }
271 fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot;
272 fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value;
273 fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot);
274 fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value;
275
276 fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
277 self.load_unaligned(ty, ptr, name)
278 }
279 fn load_unaligned(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value;
280 fn store(&mut self, value: Self::Value, ptr: Self::Value) {
281 self.store_unaligned(value, ptr);
282 }
283 fn store_unaligned(&mut self, value: Self::Value, ptr: Self::Value);
284
285 fn nop(&mut self);
286 fn ret(&mut self, values: &[Self::Value]);
287
288 fn icmp(&mut self, cond: IntCC, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
289 fn icmp_imm(&mut self, cond: IntCC, lhs: Self::Value, rhs: i64) -> Self::Value;
290 fn is_null(&mut self, ptr: Self::Value) -> Self::Value;
291 fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value;
292
293 fn br(&mut self, dest: Self::BasicBlock);
294 fn brif(
295 &mut self,
296 cond: Self::Value,
297 then_block: Self::BasicBlock,
298 else_block: Self::BasicBlock,
299 );
300 fn brif_cold(
301 &mut self,
302 cond: Self::Value,
303 then_block: Self::BasicBlock,
304 else_block: Self::BasicBlock,
305 then_is_cold: bool,
306 ) {
307 let _ = then_is_cold;
308 self.brif(cond, then_block, else_block)
309 }
310 fn switch(
311 &mut self,
312 index: Self::Value,
313 default: Self::BasicBlock,
314 targets: &[(u64, Self::BasicBlock)],
315 default_is_cold: bool,
316 );
317 fn br_indirect(&mut self, address: Self::Value, destinations: &[Self::BasicBlock]);
318 fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value;
319 fn select(
320 &mut self,
321 cond: Self::Value,
322 then_value: Self::Value,
323 else_value: Self::Value,
324 ) -> Self::Value;
325 fn lazy_select(
326 &mut self,
327 cond: Self::Value,
328 ty: Self::Type,
329 then_value: impl FnOnce(&mut Self) -> Self::Value,
330 else_value: impl FnOnce(&mut Self) -> Self::Value,
331 ) -> Self::Value;
332
333 fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
334 fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
335 fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
336 fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
337 fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
338 fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
339 fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
340
341 fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
342 fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
343 fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
344
345 fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
347 fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value);
348
349 fn uadd_sat(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
350
351 fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
352 fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
353 fn bswap(&mut self, value: Self::Value) -> Self::Value;
354
355 fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
356 fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
357 fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
358 fn bitnot(&mut self, value: Self::Value) -> Self::Value;
359 fn clz(&mut self, value: Self::Value) -> Self::Value;
360
361 fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
362 fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
363 fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value;
364
365 fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
366 fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
367 fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
368
369 fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
370 fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value;
371 #[doc(alias = "trunc")]
372 fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value;
373
374 fn inttoptr(&mut self, value: Self::Value, ty: Self::Type) -> Self::Value;
376
377 fn gep(
378 &mut self,
379 ty: Self::Type,
380 ptr: Self::Value,
381 indexes: &[Self::Value],
382 name: &str,
383 ) -> Self::Value;
384
385 #[must_use]
386 fn call(&mut self, function: Self::Function, args: &[Self::Value]) -> Option<Self::Value> {
387 self.tail_call(function, args, TailCallKind::None)
388 }
389 #[must_use]
390 fn tail_call(
391 &mut self,
392 function: Self::Function,
393 args: &[Self::Value],
394 tail_call: TailCallKind,
395 ) -> Option<Self::Value>;
396
397 fn is_compile_time_known(&mut self, value: Self::Value) -> Option<Self::Value>;
399
400 fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value);
401 fn memcpy_inline(&mut self, dst: Self::Value, src: Self::Value, len: i64) {
402 let len = self.iconst(self.type_int(64), len);
403 self.memcpy(dst, src, len);
404 }
405
406 fn unreachable(&mut self);
407
408 fn get_or_build_function(
409 &mut self,
410 name: &str,
411 params: &[Self::Type],
412 ret: Option<Self::Type>,
413 linkage: Linkage,
414 build: impl FnOnce(&mut Self),
415 ) -> Self::Function;
416
417 fn get_function(&mut self, name: &str) -> Option<Self::Function>;
418
419 fn get_printf_function(&mut self) -> Self::Function;
420
421 fn add_function(
425 &mut self,
426 name: &str,
427 params: &[Self::Type],
428 ret: Option<Self::Type>,
429 address: Option<usize>,
430 linkage: Linkage,
431 ) -> Self::Function;
432
433 fn add_function_attribute(
437 &mut self,
438 function: Option<Self::Function>,
439 attribute: Attribute,
440 loc: FunctionAttributeLocation,
441 );
442}