1use crate::{Pointer, Result};
2use ruint::aliases::U256;
3use std::{fmt, path::Path};
4
5#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum Target {
8 Native,
10 Triple {
14 triple: String,
16 cpu: Option<String>,
18 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 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 pub fn triple(triple: impl AsRef<str> + Into<String>) -> Self {
54 Self::new(triple, None, None)
55 }
56}
57
58#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
60pub enum OptimizationLevel {
61 None,
63 Less,
65 Default,
67 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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
87pub enum IntCC {
88 Equal,
90 NotEqual,
92 SignedLessThan,
94 SignedGreaterThanOrEqual,
96 SignedGreaterThan,
98 SignedLessThanOrEqual,
100 UnsignedLessThan,
102 UnsignedGreaterThanOrEqual,
104 UnsignedGreaterThan,
106 UnsignedLessThanOrEqual,
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114#[non_exhaustive]
115pub enum Attribute {
116 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 NoAlias,
134 NoCapture,
135 NoUndef,
136 Align(u64),
137 NonNull,
138 Dereferenceable(u64),
139 SRet(u64),
141 ReadNone,
142 ReadOnly,
143 WriteOnly,
144 Writable,
145 }
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum Linkage {
151 Import,
153 Public,
155 Private,
157}
158
159#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub enum FunctionAttributeLocation {
162 Return,
164 Param(u32),
166 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 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 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 fn add_function_attribute(
387 &mut self,
388 function: Option<Self::Function>,
389 attribute: Attribute,
390 loc: FunctionAttributeLocation,
391 );
392}