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 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 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 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 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 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 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 fn add_function_attribute(
430 &mut self,
431 function: Option<Self::Function>,
432 attribute: Attribute,
433 loc: FunctionAttributeLocation,
434 );
435}