1use super::functions::*;
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, PartialEq)]
10pub struct CraneliftInstResult {
11 pub result: Option<CraneliftValue>,
13 pub instr: CraneliftInstr,
15}
16impl CraneliftInstResult {
17 pub fn with_result(result: CraneliftValue, instr: CraneliftInstr) -> Self {
19 CraneliftInstResult {
20 result: Some(result),
21 instr,
22 }
23 }
24 pub fn no_result(instr: CraneliftInstr) -> Self {
26 CraneliftInstResult {
27 result: None,
28 instr,
29 }
30 }
31 pub fn emit(&self) -> String {
33 let instr_str = emit_instr(&self.instr);
34 if let Some(ref v) = self.result {
35 format!("{} = {}", v, instr_str)
36 } else {
37 instr_str
38 }
39 }
40}
41#[derive(Debug, Clone, PartialEq)]
43pub struct Signature {
44 pub call_conv: CallConv,
46 pub params: Vec<CraneliftType>,
48 pub returns: Vec<CraneliftType>,
50}
51impl Signature {
52 pub fn new(
54 call_conv: CallConv,
55 params: Vec<CraneliftType>,
56 returns: Vec<CraneliftType>,
57 ) -> Self {
58 Signature {
59 call_conv,
60 params,
61 returns,
62 }
63 }
64 pub fn c_like(params: Vec<CraneliftType>, returns: Vec<CraneliftType>) -> Self {
66 Signature::new(CallConv::SystemV, params, returns)
67 }
68}
69#[allow(dead_code)]
71pub struct CraneliftTypeCoerce;
72impl CraneliftTypeCoerce {
73 #[allow(dead_code)]
75 pub fn narrow(
76 src_ty: &CraneliftType,
77 dst_ty: &CraneliftType,
78 val: CraneliftValue,
79 ) -> Option<CraneliftInstr> {
80 match (src_ty, dst_ty) {
81 (CraneliftType::I64, CraneliftType::I32)
82 | (CraneliftType::I64, CraneliftType::I16)
83 | (CraneliftType::I64, CraneliftType::I8)
84 | (CraneliftType::I32, CraneliftType::I16)
85 | (CraneliftType::I32, CraneliftType::I8)
86 | (CraneliftType::I16, CraneliftType::I8) => {
87 Some(CraneliftInstr::Ireduce(dst_ty.clone(), val))
88 }
89 (CraneliftType::F64, CraneliftType::F32) => {
90 Some(CraneliftInstr::Fdemote(CraneliftType::F32, val))
91 }
92 _ => None,
93 }
94 }
95 #[allow(dead_code)]
97 pub fn widen_signed(
98 _src_ty: &CraneliftType,
99 dst_ty: &CraneliftType,
100 val: CraneliftValue,
101 ) -> Option<CraneliftInstr> {
102 match dst_ty {
103 CraneliftType::I16 | CraneliftType::I32 | CraneliftType::I64 | CraneliftType::I128 => {
104 Some(CraneliftInstr::Sextend(dst_ty.clone(), val))
105 }
106 CraneliftType::F64 => Some(CraneliftInstr::Fpromote(CraneliftType::F64, val)),
107 _ => None,
108 }
109 }
110 #[allow(dead_code)]
112 pub fn widen_unsigned(
113 _src_ty: &CraneliftType,
114 dst_ty: &CraneliftType,
115 val: CraneliftValue,
116 ) -> Option<CraneliftInstr> {
117 match dst_ty {
118 CraneliftType::I16 | CraneliftType::I32 | CraneliftType::I64 | CraneliftType::I128 => {
119 Some(CraneliftInstr::Uextend(dst_ty.clone(), val))
120 }
121 _ => None,
122 }
123 }
124}
125#[derive(Debug, Clone)]
127#[allow(dead_code)]
128pub enum CraneliftGlobalValueDef {
129 Symbol { name: String, colocated: bool },
131 IAddImm { base: u32, offset: i64 },
133 Load {
135 base: u32,
136 offset: i32,
137 global_type: CraneliftType,
138 readonly: bool,
139 },
140}
141#[derive(Debug)]
143#[allow(dead_code)]
144pub struct CraneliftModuleBuilder {
145 pub(super) module: CraneliftModule,
146}
147impl CraneliftModuleBuilder {
148 #[allow(dead_code)]
150 pub fn new(name: impl Into<String>) -> Self {
151 CraneliftModuleBuilder {
152 module: CraneliftModule::new(name),
153 }
154 }
155 #[allow(dead_code)]
157 pub fn target(mut self, triple: impl Into<String>) -> Self {
158 self.module.target = triple.into();
159 self
160 }
161 #[allow(dead_code)]
163 pub fn extern_func(mut self, name: impl Into<String>, sig: Signature) -> Self {
164 self.module.add_func_decl(name, sig);
165 self
166 }
167 #[allow(dead_code)]
169 pub fn data(mut self, obj: CraneliftDataObject) -> Self {
170 self.module.add_data_object(obj);
171 self
172 }
173 #[allow(dead_code)]
175 pub fn func(mut self, f: CraneliftFunction) -> Self {
176 self.module.add_function(f);
177 self
178 }
179 #[allow(dead_code)]
181 pub fn build(self) -> CraneliftModule {
182 self.module
183 }
184}
185#[derive(Debug)]
187#[allow(dead_code)]
188pub struct CraneliftFunctionBuilder {
189 pub(super) func: CraneliftFunction,
190 pub(super) current_block: Option<u32>,
191}
192impl CraneliftFunctionBuilder {
193 #[allow(dead_code)]
195 pub fn new(name: impl Into<String>, sig: Signature) -> Self {
196 let func = CraneliftFunction::new(name, sig);
197 CraneliftFunctionBuilder {
198 func,
199 current_block: None,
200 }
201 }
202 #[allow(dead_code)]
204 pub fn create_entry_block(mut self) -> Self {
205 let b = self.func.new_block();
206 self.current_block = Some(b);
207 self
208 }
209 #[allow(dead_code)]
211 pub fn create_block(mut self) -> (Self, u32) {
212 let b = self.func.new_block();
213 self.current_block = Some(b);
214 (self, b)
215 }
216 #[allow(dead_code)]
218 pub fn switch_to_block(mut self, block: u32) -> Self {
219 self.current_block = Some(block);
220 self
221 }
222 #[allow(dead_code)]
224 pub fn ins_result(
225 mut self,
226 ty: CraneliftType,
227 instr: CraneliftInstr,
228 ) -> (Self, CraneliftValue) {
229 let val = self.func.fresh_value(ty);
230 if let Some(b_idx) = self.current_block {
231 if let Some(b) = self.func.block_mut(b_idx) {
232 b.push_with_result(val.clone(), instr);
233 }
234 }
235 (self, val)
236 }
237 #[allow(dead_code)]
239 pub fn ins_void(mut self, instr: CraneliftInstr) -> Self {
240 if let Some(b_idx) = self.current_block {
241 if let Some(b) = self.func.block_mut(b_idx) {
242 b.push_void(instr);
243 }
244 }
245 self
246 }
247 #[allow(dead_code)]
249 pub fn block_param(mut self, ty: CraneliftType) -> (Self, CraneliftValue) {
250 let val = self.func.fresh_value(ty);
251 if let Some(b_idx) = self.current_block {
252 if let Some(b) = self.func.block_mut(b_idx) {
253 b.params.push(val.clone());
254 }
255 }
256 (self, val)
257 }
258 #[allow(dead_code)]
260 pub fn finish(self) -> CraneliftFunction {
261 self.func
262 }
263}
264#[derive(Debug, Clone, PartialEq, Eq, Hash)]
266pub enum CraneliftType {
267 B1,
269 I8,
271 I16,
273 I32,
275 I64,
277 I128,
279 F32,
281 F64,
283 R32,
285 R64,
287 Vector(Box<CraneliftType>, u32),
289 Void,
291}
292impl CraneliftType {
293 pub fn byte_width(&self) -> Option<u32> {
295 match self {
296 CraneliftType::B1 => Some(1),
297 CraneliftType::I8 => Some(1),
298 CraneliftType::I16 => Some(2),
299 CraneliftType::I32 => Some(4),
300 CraneliftType::I64 => Some(8),
301 CraneliftType::I128 => Some(16),
302 CraneliftType::F32 => Some(4),
303 CraneliftType::F64 => Some(8),
304 CraneliftType::R32 => Some(4),
305 CraneliftType::R64 => Some(8),
306 CraneliftType::Vector(base, lanes) => base.byte_width().map(|w| w * lanes),
307 CraneliftType::Void => None,
308 }
309 }
310 pub fn is_int(&self) -> bool {
312 matches!(
313 self,
314 CraneliftType::I8
315 | CraneliftType::I16
316 | CraneliftType::I32
317 | CraneliftType::I64
318 | CraneliftType::I128
319 | CraneliftType::B1
320 )
321 }
322 pub fn is_float(&self) -> bool {
324 matches!(self, CraneliftType::F32 | CraneliftType::F64)
325 }
326}
327#[derive(Debug, Clone, PartialEq)]
329pub struct CraneliftBlock {
330 pub id: u32,
332 pub params: Vec<CraneliftValue>,
334 pub instrs: Vec<CraneliftInstResult>,
336}
337impl CraneliftBlock {
338 pub fn new(id: u32) -> Self {
340 CraneliftBlock {
341 id,
342 params: vec![],
343 instrs: vec![],
344 }
345 }
346 pub fn with_params(id: u32, params: Vec<CraneliftValue>) -> Self {
348 CraneliftBlock {
349 id,
350 params,
351 instrs: vec![],
352 }
353 }
354 pub fn block_ref(&self) -> BlockRef {
356 BlockRef::new(self.id)
357 }
358 pub fn push_with_result(&mut self, result: CraneliftValue, instr: CraneliftInstr) {
360 self.instrs
361 .push(CraneliftInstResult::with_result(result, instr));
362 }
363 pub fn push_void(&mut self, instr: CraneliftInstr) {
365 self.instrs.push(CraneliftInstResult::no_result(instr));
366 }
367 pub fn is_terminated(&self) -> bool {
369 self.instrs.last().is_some_and(|ir| {
370 matches!(
371 ir.instr,
372 CraneliftInstr::Jump(_, _)
373 | CraneliftInstr::Brif(_, _, _, _, _)
374 | CraneliftInstr::BrTable(_, _, _)
375 | CraneliftInstr::Return(_)
376 | CraneliftInstr::Trap(_)
377 | CraneliftInstr::Unreachable
378 | CraneliftInstr::ReturnCall(_, _)
379 )
380 })
381 }
382 pub fn emit(&self) -> String {
384 let mut s = String::new();
385 if self.params.is_empty() {
386 s.push_str(&format!("block{}:\n", self.id));
387 } else {
388 let params = self
389 .params
390 .iter()
391 .map(|v| format!("{}: {}", v, v.ty))
392 .collect::<Vec<_>>()
393 .join(", ");
394 s.push_str(&format!("block{}({}):\n", self.id, params));
395 }
396 for ir in &self.instrs {
397 s.push_str(&format!(" {}\n", ir.emit()));
398 }
399 s
400 }
401}
402#[allow(dead_code)]
404pub struct CraneliftInstPattern;
405impl CraneliftInstPattern {
406 #[allow(dead_code)]
408 pub fn is_pure_arith(instr: &CraneliftInstr) -> bool {
409 matches!(
410 instr,
411 CraneliftInstr::Iconst(..)
412 | CraneliftInstr::F32Const(..)
413 | CraneliftInstr::F64Const(..)
414 | CraneliftInstr::Iadd(..)
415 | CraneliftInstr::Isub(..)
416 | CraneliftInstr::Imul(..)
417 | CraneliftInstr::Sdiv(..)
418 | CraneliftInstr::Udiv(..)
419 | CraneliftInstr::Srem(..)
420 | CraneliftInstr::Urem(..)
421 | CraneliftInstr::Ineg(..)
422 | CraneliftInstr::Iabs(..)
423 | CraneliftInstr::IaddImm(..)
424 | CraneliftInstr::ImulImm(..)
425 | CraneliftInstr::Band(..)
426 | CraneliftInstr::Bor(..)
427 | CraneliftInstr::Bxor(..)
428 | CraneliftInstr::Bnot(..)
429 | CraneliftInstr::Ishl(..)
430 | CraneliftInstr::Sshr(..)
431 | CraneliftInstr::Ushr(..)
432 | CraneliftInstr::Rotl(..)
433 | CraneliftInstr::Rotr(..)
434 | CraneliftInstr::Clz(..)
435 | CraneliftInstr::Ctz(..)
436 | CraneliftInstr::Popcnt(..)
437 | CraneliftInstr::Fadd(..)
438 | CraneliftInstr::Fsub(..)
439 | CraneliftInstr::Fmul(..)
440 | CraneliftInstr::Fdiv(..)
441 | CraneliftInstr::Fneg(..)
442 | CraneliftInstr::Fabs(..)
443 | CraneliftInstr::Sqrt(..)
444 | CraneliftInstr::Ceil(..)
445 | CraneliftInstr::Floor(..)
446 | CraneliftInstr::FTrunc(..)
447 | CraneliftInstr::Nearest(..)
448 | CraneliftInstr::Fmin(..)
449 | CraneliftInstr::Fmax(..)
450 | CraneliftInstr::Icmp(..)
451 | CraneliftInstr::Fcmp(..)
452 )
453 }
454 #[allow(dead_code)]
456 pub fn is_terminator(instr: &CraneliftInstr) -> bool {
457 matches!(
458 instr,
459 CraneliftInstr::Return(..)
460 | CraneliftInstr::Jump(..)
461 | CraneliftInstr::Brif(..)
462 | CraneliftInstr::BrTable(..)
463 | CraneliftInstr::Trap(..)
464 )
465 }
466 #[allow(dead_code)]
468 pub fn has_side_effects(instr: &CraneliftInstr) -> bool {
469 matches!(
470 instr,
471 CraneliftInstr::Store(..)
472 | CraneliftInstr::Return(..)
473 | CraneliftInstr::Jump(..)
474 | CraneliftInstr::Brif(..)
475 | CraneliftInstr::BrTable(..)
476 | CraneliftInstr::Trap(..)
477 | CraneliftInstr::Call(..)
478 )
479 }
480 #[allow(dead_code)]
482 pub fn iconst_value(instr: &CraneliftInstr) -> Option<i64> {
483 match instr {
484 CraneliftInstr::Iconst(_, n) => Some(*n),
485 _ => None,
486 }
487 }
488}
489pub struct CraneliftBackend {
491 pub module: CraneliftModule,
493 pub(super) current_func: Option<CraneliftFunction>,
495 pub(super) current_block: Option<u32>,
497}
498impl CraneliftBackend {
499 pub fn new(module_name: impl Into<String>) -> Self {
501 CraneliftBackend {
502 module: CraneliftModule::new(module_name),
503 current_func: None,
504 current_block: None,
505 }
506 }
507 pub fn begin_function(&mut self, name: impl Into<String>, sig: Signature) {
509 let mut func = CraneliftFunction::new(name, sig);
510 let entry_id = func.new_block();
511 for ty in func.sig.params.clone() {
512 let v = func.fresh_value(ty.clone());
513 if let Some(block) = func.blocks.iter_mut().find(|b| b.id == entry_id) {
514 block.params.push(v);
515 }
516 }
517 self.current_func = Some(func);
518 self.current_block = Some(entry_id);
519 }
520 pub fn end_function(&mut self) {
522 if let Some(func) = self.current_func.take() {
523 self.module.add_function(func);
524 }
525 self.current_block = None;
526 }
527 pub fn switch_to_block(&mut self, block_id: u32) {
529 self.current_block = Some(block_id);
530 }
531 pub fn fresh_value(&mut self, ty: CraneliftType) -> Option<CraneliftValue> {
533 self.current_func.as_mut().map(|f| f.fresh_value(ty))
534 }
535 pub fn new_block(&mut self) -> Option<u32> {
537 self.current_func.as_mut().map(|f| f.new_block())
538 }
539 pub fn emit_with_result(
541 &mut self,
542 ty: CraneliftType,
543 instr: CraneliftInstr,
544 ) -> Option<CraneliftValue> {
545 let v = self.fresh_value(ty)?;
546 let block_id = self.current_block?;
547 let func = self.current_func.as_mut()?;
548 if let Some(block) = func.block_mut(block_id) {
549 block.push_with_result(v.clone(), instr);
550 }
551 Some(v)
552 }
553 pub fn emit_void(&mut self, instr: CraneliftInstr) {
555 let block_id = match self.current_block {
556 Some(id) => id,
557 None => return,
558 };
559 if let Some(func) = self.current_func.as_mut() {
560 if let Some(block) = func.block_mut(block_id) {
561 block.push_void(instr);
562 }
563 }
564 }
565 pub fn iconst(&mut self, ty: CraneliftType, val: i64) -> Option<CraneliftValue> {
567 self.emit_with_result(ty.clone(), CraneliftInstr::Iconst(ty, val))
568 }
569 pub fn iadd(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
571 let ty = a.ty.clone();
572 self.emit_with_result(ty, CraneliftInstr::Iadd(a, b))
573 }
574 pub fn isub(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
576 let ty = a.ty.clone();
577 self.emit_with_result(ty, CraneliftInstr::Isub(a, b))
578 }
579 pub fn imul(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
581 let ty = a.ty.clone();
582 self.emit_with_result(ty, CraneliftInstr::Imul(a, b))
583 }
584 pub fn sdiv(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
586 let ty = a.ty.clone();
587 self.emit_with_result(ty, CraneliftInstr::Sdiv(a, b))
588 }
589 pub fn icmp(
591 &mut self,
592 cc: IntCC,
593 a: CraneliftValue,
594 b: CraneliftValue,
595 ) -> Option<CraneliftValue> {
596 self.emit_with_result(CraneliftType::B1, CraneliftInstr::Icmp(cc, a, b))
597 }
598 pub fn fcmp(
600 &mut self,
601 cc: FloatCC,
602 a: CraneliftValue,
603 b: CraneliftValue,
604 ) -> Option<CraneliftValue> {
605 self.emit_with_result(CraneliftType::B1, CraneliftInstr::Fcmp(cc, a, b))
606 }
607 pub fn load(
609 &mut self,
610 ty: CraneliftType,
611 flags: MemFlags,
612 addr: CraneliftValue,
613 offset: i32,
614 ) -> Option<CraneliftValue> {
615 self.emit_with_result(ty.clone(), CraneliftInstr::Load(ty, flags, addr, offset))
616 }
617 pub fn store(
619 &mut self,
620 flags: MemFlags,
621 val: CraneliftValue,
622 addr: CraneliftValue,
623 offset: i32,
624 ) {
625 self.emit_void(CraneliftInstr::Store(flags, val, addr, offset));
626 }
627 pub fn call_single(
629 &mut self,
630 ret_ty: CraneliftType,
631 func: impl Into<String>,
632 args: Vec<CraneliftValue>,
633 ) -> Option<CraneliftValue> {
634 self.emit_with_result(ret_ty, CraneliftInstr::Call(func.into(), args))
635 }
636 pub fn jump(&mut self, target: BlockRef, args: Vec<CraneliftValue>) {
638 self.emit_void(CraneliftInstr::Jump(target, args));
639 }
640 pub fn brif(
642 &mut self,
643 cond: CraneliftValue,
644 t: BlockRef,
645 t_args: Vec<CraneliftValue>,
646 f: BlockRef,
647 f_args: Vec<CraneliftValue>,
648 ) {
649 self.emit_void(CraneliftInstr::Brif(cond, t, t_args, f, f_args));
650 }
651 pub fn emit_return(&mut self, vals: Vec<CraneliftValue>) {
653 self.emit_void(CraneliftInstr::Return(vals));
654 }
655 pub fn emit_module(&self) -> String {
657 self.module.emit()
658 }
659}
660#[derive(Debug, Default)]
662#[allow(dead_code)]
663pub struct CraneliftStackAllocator {
664 pub(super) slots: Vec<CraneliftStackSlot>,
665 pub(super) next_id: u32,
666 pub(super) frame_size: u32,
667}
668impl CraneliftStackAllocator {
669 #[allow(dead_code)]
671 pub fn new() -> Self {
672 CraneliftStackAllocator::default()
673 }
674 #[allow(dead_code)]
676 pub fn alloc(&mut self, size: u32, align: u32) -> &CraneliftStackSlot {
677 let aligned = (self.frame_size + align - 1) & !(align - 1);
678 self.frame_size = aligned + size;
679 let slot = CraneliftStackSlot::new(self.next_id, size, align);
680 self.next_id += 1;
681 self.slots.push(slot);
682 self.slots
683 .last()
684 .expect("slots is non-empty after push; invariant guaranteed by alloc")
685 }
686 #[allow(dead_code)]
688 pub fn alloc_named(
689 &mut self,
690 size: u32,
691 align: u32,
692 name: impl Into<String>,
693 ) -> &CraneliftStackSlot {
694 let aligned = (self.frame_size + align - 1) & !(align - 1);
695 self.frame_size = aligned + size;
696 let slot = CraneliftStackSlot::named(self.next_id, size, align, name);
697 self.next_id += 1;
698 self.slots.push(slot);
699 self.slots
700 .last()
701 .expect("slots is non-empty after push; invariant guaranteed by alloc_named")
702 }
703 #[allow(dead_code)]
705 pub fn slots(&self) -> &[CraneliftStackSlot] {
706 &self.slots
707 }
708 #[allow(dead_code)]
710 pub fn frame_size(&self) -> u32 {
711 self.frame_size
712 }
713 #[allow(dead_code)]
715 pub fn emit_decls(&self) -> String {
716 self.slots
717 .iter()
718 .map(|s| s.emit())
719 .collect::<Vec<_>>()
720 .join("\n")
721 }
722}
723#[derive(Debug, Clone, PartialEq)]
725pub struct CraneliftDataObject {
726 pub name: String,
728 pub is_readonly: bool,
730 pub data: Vec<u8>,
732 pub align: u32,
734}
735impl CraneliftDataObject {
736 pub fn readonly(name: impl Into<String>, data: Vec<u8>, align: u32) -> Self {
738 CraneliftDataObject {
739 name: name.into(),
740 is_readonly: true,
741 data,
742 align,
743 }
744 }
745 pub fn writable(name: impl Into<String>, data: Vec<u8>, align: u32) -> Self {
747 CraneliftDataObject {
748 name: name.into(),
749 is_readonly: false,
750 data,
751 align,
752 }
753 }
754 pub fn emit(&self) -> String {
756 let rw = if self.is_readonly { "rodata" } else { "data" };
757 let hex: String = self.data.iter().map(|b| format!("\\{:02x}", b)).collect();
758 format!(
759 "{} %{} align={} {{\n ascii \"{}\"\n}}\n",
760 rw, self.name, self.align, hex
761 )
762 }
763}
764#[derive(Debug, Clone, PartialEq, Eq)]
766#[allow(dead_code)]
767pub enum CraneliftABIClass {
768 Integer,
770 Float,
772 SSE,
774 Memory,
776 NoValue,
778}
779#[derive(Debug, Clone)]
781#[allow(dead_code)]
782pub struct CraneliftABIParam {
783 pub ty: CraneliftType,
785 pub class: CraneliftABIClass,
787 pub location: i32,
789}
790impl CraneliftABIParam {
791 #[allow(dead_code)]
793 pub fn new(ty: CraneliftType, class: CraneliftABIClass, location: i32) -> Self {
794 CraneliftABIParam {
795 ty,
796 class,
797 location,
798 }
799 }
800 #[allow(dead_code)]
802 pub fn is_register(&self) -> bool {
803 !matches!(
804 self.class,
805 CraneliftABIClass::Memory | CraneliftABIClass::NoValue
806 )
807 }
808}
809#[derive(Debug, Clone)]
811#[allow(dead_code)]
812pub struct CraneliftPassConfig {
813 pub const_folding: bool,
815 pub dce: bool,
817 pub inst_combine: bool,
819 pub branch_opt: bool,
821 pub licm: bool,
823 pub reg_coalescing: bool,
825 pub load_elim: bool,
827 pub tail_call_opt: bool,
829 pub inline_depth: u32,
831 pub debug_info: bool,
833}
834impl CraneliftPassConfig {
835 #[allow(dead_code)]
837 pub fn no_opt() -> Self {
838 CraneliftPassConfig {
839 const_folding: false,
840 dce: false,
841 inst_combine: false,
842 branch_opt: false,
843 licm: false,
844 reg_coalescing: false,
845 load_elim: false,
846 tail_call_opt: false,
847 inline_depth: 0,
848 debug_info: false,
849 }
850 }
851 #[allow(dead_code)]
853 pub fn max_opt() -> Self {
854 CraneliftPassConfig {
855 const_folding: true,
856 dce: true,
857 inst_combine: true,
858 branch_opt: true,
859 licm: true,
860 reg_coalescing: true,
861 load_elim: true,
862 tail_call_opt: true,
863 inline_depth: 10,
864 debug_info: false,
865 }
866 }
867}
868#[derive(Debug, Clone, PartialEq, Eq, Hash)]
870pub struct BlockRef {
871 pub id: u32,
873}
874impl BlockRef {
875 pub fn new(id: u32) -> Self {
877 BlockRef { id }
878 }
879}
880#[derive(Debug, Clone, PartialEq, Eq)]
882pub struct MemFlags {
883 pub aligned: bool,
885 pub notrap: bool,
887 pub readonly: bool,
889}
890impl MemFlags {
891 pub fn new() -> Self {
893 MemFlags {
894 aligned: false,
895 notrap: false,
896 readonly: false,
897 }
898 }
899 pub fn trusted() -> Self {
901 MemFlags {
902 aligned: false,
903 notrap: true,
904 readonly: false,
905 }
906 }
907 pub fn aligned_notrap() -> Self {
909 MemFlags {
910 aligned: true,
911 notrap: true,
912 readonly: false,
913 }
914 }
915}
916#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
918#[allow(dead_code)]
919pub enum CraneliftCallingConvention {
920 SystemV,
922 WindowsFastcall,
924 WasmtimeSystem,
926 Cold,
928 Tail,
930 Fast,
932}
933#[derive(Debug, Clone, Default)]
935#[allow(dead_code)]
936pub struct CraneliftDebugInfo {
937 pub source_file: Option<String>,
939 pub source_function: Option<String>,
941 pub location_map: Vec<(usize, u32, u32)>,
943 pub var_names: HashMap<String, String>,
945}
946impl CraneliftDebugInfo {
947 #[allow(dead_code)]
949 pub fn new(source_file: impl Into<String>, source_function: impl Into<String>) -> Self {
950 CraneliftDebugInfo {
951 source_file: Some(source_file.into()),
952 source_function: Some(source_function.into()),
953 location_map: Vec::new(),
954 var_names: HashMap::new(),
955 }
956 }
957 #[allow(dead_code)]
959 pub fn add_location(&mut self, offset: usize, line: u32, column: u32) {
960 self.location_map.push((offset, line, column));
961 }
962 #[allow(dead_code)]
964 pub fn add_var_name(&mut self, ir_name: impl Into<String>, source_name: impl Into<String>) {
965 self.var_names.insert(ir_name.into(), source_name.into());
966 }
967 #[allow(dead_code)]
969 pub fn emit_comments(&self) -> String {
970 let mut out = String::new();
971 if let Some(ref f) = self.source_file {
972 out.push_str(&format!("; source_file: {}\n", f));
973 }
974 if let Some(ref f) = self.source_function {
975 out.push_str(&format!("; source_function: {}\n", f));
976 }
977 for (offset, line, col) in &self.location_map {
978 out.push_str(&format!("; @{}: {}:{}\n", offset, line, col));
979 }
980 for (ir, src) in &self.var_names {
981 out.push_str(&format!("; var {} => {}\n", ir, src));
982 }
983 out
984 }
985}
986#[derive(Debug, Clone)]
988#[allow(dead_code)]
989pub struct CraneliftGlobalValue {
990 pub id: u32,
992 pub ty: CraneliftType,
994 pub def: CraneliftGlobalValueDef,
996}
997impl CraneliftGlobalValue {
998 #[allow(dead_code)]
1000 pub fn symbol(id: u32, name: impl Into<String>, colocated: bool) -> Self {
1001 CraneliftGlobalValue {
1002 id,
1003 ty: CraneliftType::I64,
1004 def: CraneliftGlobalValueDef::Symbol {
1005 name: name.into(),
1006 colocated,
1007 },
1008 }
1009 }
1010 #[allow(dead_code)]
1012 pub fn emit(&self) -> String {
1013 match &self.def {
1014 CraneliftGlobalValueDef::Symbol { name, colocated } => {
1015 format!(
1016 "gv{} = symbol {}{}",
1017 self.id,
1018 if *colocated { "colocated " } else { "" },
1019 name
1020 )
1021 }
1022 CraneliftGlobalValueDef::IAddImm { base, offset } => {
1023 format!("gv{} = iadd_imm gv{}, {}", self.id, base, offset)
1024 }
1025 CraneliftGlobalValueDef::Load {
1026 base,
1027 offset,
1028 global_type,
1029 readonly,
1030 } => {
1031 format!(
1032 "gv{} = load.{} {}[{}]{}",
1033 self.id,
1034 global_type,
1035 base,
1036 offset,
1037 if *readonly { " readonly" } else { "" }
1038 )
1039 }
1040 }
1041 }
1042}
1043#[derive(Debug, Clone)]
1045#[allow(dead_code)]
1046pub struct CraneliftHeapConfig {
1047 pub base: u32,
1049 pub min_size: u64,
1051 pub max_size: Option<u64>,
1053 pub page_size: u64,
1055 pub needs_bounds_check: bool,
1057 pub guard_size: u64,
1059}
1060impl CraneliftHeapConfig {
1061 #[allow(dead_code)]
1063 pub fn static_4gib() -> Self {
1064 CraneliftHeapConfig {
1065 min_size: 65536,
1066 max_size: Some(4 * 1024 * 1024 * 1024),
1067 guard_size: 2 * 1024 * 1024 * 1024,
1068 needs_bounds_check: false,
1069 ..Default::default()
1070 }
1071 }
1072 #[allow(dead_code)]
1074 pub fn emit_comment(&self) -> String {
1075 format!(
1076 "; heap base=gv{} min={} max={} page={} guard={} bounds_check={}",
1077 self.base,
1078 self.min_size,
1079 self.max_size
1080 .map(|m| m.to_string())
1081 .unwrap_or_else(|| "unlimited".to_string()),
1082 self.page_size,
1083 self.guard_size,
1084 self.needs_bounds_check,
1085 )
1086 }
1087}
1088#[derive(Debug, Clone)]
1090#[allow(dead_code)]
1091pub struct CraneliftStackSlot {
1092 pub id: u32,
1094 pub size: u32,
1096 pub align: u32,
1098 pub name: Option<String>,
1100}
1101impl CraneliftStackSlot {
1102 #[allow(dead_code)]
1104 pub fn new(id: u32, size: u32, align: u32) -> Self {
1105 CraneliftStackSlot {
1106 id,
1107 size,
1108 align,
1109 name: None,
1110 }
1111 }
1112 #[allow(dead_code)]
1114 pub fn named(id: u32, size: u32, align: u32, name: impl Into<String>) -> Self {
1115 CraneliftStackSlot {
1116 id,
1117 size,
1118 align,
1119 name: Some(name.into()),
1120 }
1121 }
1122 #[allow(dead_code)]
1124 pub fn emit(&self) -> String {
1125 let name_comment = self
1126 .name
1127 .as_ref()
1128 .map(|n| format!(" ; {}", n))
1129 .unwrap_or_default();
1130 format!(
1131 "ss{} = explicit_slot {}, align = {}{}",
1132 self.id, self.size, self.align, name_comment
1133 )
1134 }
1135 #[allow(dead_code)]
1137 pub fn addr_expr(&self, offset: i32) -> String {
1138 format!("stack_addr.i64 ss{}, {}", self.id, offset)
1139 }
1140}
1141#[derive(Debug, Clone, PartialEq)]
1143pub enum CraneliftInstr {
1144 Iconst(CraneliftType, i64),
1146 Bconst(bool),
1148 F32Const(f32),
1150 F64Const(f64),
1152 Iadd(CraneliftValue, CraneliftValue),
1154 Isub(CraneliftValue, CraneliftValue),
1156 Imul(CraneliftValue, CraneliftValue),
1158 Sdiv(CraneliftValue, CraneliftValue),
1160 Udiv(CraneliftValue, CraneliftValue),
1162 Srem(CraneliftValue, CraneliftValue),
1164 Urem(CraneliftValue, CraneliftValue),
1166 Ineg(CraneliftValue),
1168 Iabs(CraneliftValue),
1170 IaddImm(CraneliftValue, i64),
1172 ImulImm(CraneliftValue, i64),
1174 Band(CraneliftValue, CraneliftValue),
1176 Bor(CraneliftValue, CraneliftValue),
1178 Bxor(CraneliftValue, CraneliftValue),
1180 Bnot(CraneliftValue),
1182 Ishl(CraneliftValue, CraneliftValue),
1184 Sshr(CraneliftValue, CraneliftValue),
1186 Ushr(CraneliftValue, CraneliftValue),
1188 Rotl(CraneliftValue, CraneliftValue),
1190 Rotr(CraneliftValue, CraneliftValue),
1192 Clz(CraneliftValue),
1194 Ctz(CraneliftValue),
1196 Popcnt(CraneliftValue),
1198 Fadd(CraneliftValue, CraneliftValue),
1200 Fsub(CraneliftValue, CraneliftValue),
1202 Fmul(CraneliftValue, CraneliftValue),
1204 Fdiv(CraneliftValue, CraneliftValue),
1206 Fneg(CraneliftValue),
1208 Fabs(CraneliftValue),
1210 Sqrt(CraneliftValue),
1212 Fma(CraneliftValue, CraneliftValue, CraneliftValue),
1214 Fmin(CraneliftValue, CraneliftValue),
1216 Fmax(CraneliftValue, CraneliftValue),
1218 Floor(CraneliftValue),
1220 Ceil(CraneliftValue),
1222 FTrunc(CraneliftValue),
1224 Nearest(CraneliftValue),
1226 Icmp(IntCC, CraneliftValue, CraneliftValue),
1228 Fcmp(FloatCC, CraneliftValue, CraneliftValue),
1230 Select(CraneliftValue, CraneliftValue, CraneliftValue),
1232 Sextend(CraneliftType, CraneliftValue),
1234 Uextend(CraneliftType, CraneliftValue),
1236 Ireduce(CraneliftType, CraneliftValue),
1238 Fpromote(CraneliftType, CraneliftValue),
1240 Fdemote(CraneliftType, CraneliftValue),
1242 FcvtToSint(CraneliftType, CraneliftValue),
1244 FcvtToUint(CraneliftType, CraneliftValue),
1246 FcvtFromSint(CraneliftType, CraneliftValue),
1248 FcvtFromUint(CraneliftType, CraneliftValue),
1250 Bitcast(CraneliftType, CraneliftValue),
1252 Load(CraneliftType, MemFlags, CraneliftValue, i32),
1254 Store(MemFlags, CraneliftValue, CraneliftValue, i32),
1256 StackAddr(CraneliftType, u32),
1258 GlobalValue(CraneliftType, u32),
1260 Jump(BlockRef, Vec<CraneliftValue>),
1262 Brif(
1264 CraneliftValue,
1265 BlockRef,
1266 Vec<CraneliftValue>,
1267 BlockRef,
1268 Vec<CraneliftValue>,
1269 ),
1270 BrTable(CraneliftValue, BlockRef, Vec<BlockRef>),
1272 Return(Vec<CraneliftValue>),
1274 Trap(String),
1276 Trapif(IntCC, CraneliftValue, String),
1278 Unreachable,
1280 Call(String, Vec<CraneliftValue>),
1282 CallIndirect(u32, CraneliftValue, Vec<CraneliftValue>),
1284 ReturnCall(String, Vec<CraneliftValue>),
1286 FuncAddr(CraneliftType, String),
1288 Null(CraneliftType),
1290 Splat(CraneliftType, CraneliftValue),
1292 ExtractLane(CraneliftValue, u8),
1294 InsertLane(CraneliftValue, u8, CraneliftValue),
1296 Copy(CraneliftValue),
1298 Nop,
1300}
1301#[derive(Debug, Clone, PartialEq, Eq)]
1303pub enum FloatCC {
1304 Equal,
1306 NotEqual,
1308 LessThan,
1310 LessThanOrEqual,
1312 GreaterThan,
1314 GreaterThanOrEqual,
1316 Ordered,
1318 Unordered,
1320 UnorderedOrEqual,
1322 UnorderedOrLessThan,
1324 UnorderedOrGreaterThan,
1326}
1327#[derive(Debug, Clone, PartialEq, Eq)]
1329pub enum IntCC {
1330 Equal,
1332 NotEqual,
1334 SignedLessThan,
1336 SignedLessThanOrEqual,
1338 SignedGreaterThan,
1340 SignedGreaterThanOrEqual,
1342 UnsignedLessThan,
1344 UnsignedLessThanOrEqual,
1346 UnsignedGreaterThan,
1348 UnsignedGreaterThanOrEqual,
1350 Overflow,
1352 NotOverflow,
1354}
1355#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1357pub struct CraneliftValue {
1358 pub id: u32,
1360 pub ty: CraneliftType,
1362}
1363impl CraneliftValue {
1364 pub fn new(id: u32, ty: CraneliftType) -> Self {
1366 CraneliftValue { id, ty }
1367 }
1368}
1369#[derive(Debug, Clone, PartialEq, Eq)]
1371pub enum CallConv {
1372 Fast,
1374 Cold,
1376 SystemV,
1378 WindowsFastcall,
1380 WasmtimeSystemV,
1382}
1383#[derive(Debug, Clone, Default)]
1385#[allow(dead_code)]
1386pub struct CraneliftCodeMetrics {
1387 pub num_blocks: usize,
1389 pub total_instructions: usize,
1391 pub num_value_instructions: usize,
1393 pub num_void_instructions: usize,
1395 pub total_block_params: usize,
1397 pub num_calls: usize,
1399 pub num_loads: usize,
1401 pub num_stores: usize,
1403 pub num_branches: usize,
1405}
1406impl CraneliftCodeMetrics {
1407 #[allow(dead_code)]
1409 pub fn compute(func: &CraneliftFunction) -> Self {
1410 let mut m = CraneliftCodeMetrics {
1411 num_blocks: func.blocks.len(),
1412 ..Default::default()
1413 };
1414 for block in &func.blocks {
1415 m.total_block_params += block.params.len();
1416 for inst in &block.instrs {
1417 m.total_instructions += 1;
1418 if inst.result.is_some() {
1419 m.num_value_instructions += 1;
1420 } else {
1421 m.num_void_instructions += 1;
1422 }
1423 match &inst.instr {
1424 CraneliftInstr::Call(..) => {
1425 m.num_calls += 1;
1426 }
1427 CraneliftInstr::Load(..) => {
1428 m.num_loads += 1;
1429 }
1430 CraneliftInstr::Store(..) => {
1431 m.num_stores += 1;
1432 }
1433 CraneliftInstr::Brif(..)
1434 | CraneliftInstr::BrTable(..)
1435 | CraneliftInstr::Jump(..) => {
1436 m.num_branches += 1;
1437 }
1438 _ => {}
1439 }
1440 }
1441 }
1442 m
1443 }
1444 #[allow(dead_code)]
1446 pub fn summary(&self) -> String {
1447 format!(
1448 "blocks={} total_instrs={} values={} voids={} params={} calls={} loads={} stores={} branches={}",
1449 self.num_blocks, self.total_instructions, self.num_value_instructions, self
1450 .num_void_instructions, self.total_block_params, self.num_calls, self
1451 .num_loads, self.num_stores, self.num_branches,
1452 )
1453 }
1454}
1455#[derive(Debug, Clone)]
1457#[allow(dead_code)]
1458pub struct CraneliftInlineAsm {
1459 pub template: String,
1461 pub inputs: Vec<(String, CraneliftValue)>,
1463 pub outputs: Vec<(String, CraneliftValue)>,
1465 pub volatile: bool,
1467 pub can_trap: bool,
1469}
1470impl CraneliftInlineAsm {
1471 #[allow(dead_code)]
1473 pub fn new(template: impl Into<String>) -> Self {
1474 CraneliftInlineAsm {
1475 template: template.into(),
1476 inputs: Vec::new(),
1477 outputs: Vec::new(),
1478 volatile: true,
1479 can_trap: false,
1480 }
1481 }
1482 #[allow(dead_code)]
1484 pub fn add_input(&mut self, constraint: impl Into<String>, val: CraneliftValue) {
1485 self.inputs.push((constraint.into(), val));
1486 }
1487 #[allow(dead_code)]
1489 pub fn add_output(&mut self, constraint: impl Into<String>, val: CraneliftValue) {
1490 self.outputs.push((constraint.into(), val));
1491 }
1492 #[allow(dead_code)]
1494 pub fn emit_comment(&self) -> String {
1495 format!(
1496 "; inline_asm template={:?} inputs={} outputs={} volatile={}",
1497 self.template,
1498 self.inputs.len(),
1499 self.outputs.len(),
1500 self.volatile,
1501 )
1502 }
1503}
1504#[derive(Debug, Clone, PartialEq)]
1506pub struct CraneliftFunction {
1507 pub name: String,
1509 pub sig: Signature,
1511 pub stack_slots: Vec<(u32, u32)>,
1513 pub global_values: Vec<(u32, String)>,
1515 pub sig_refs: Vec<(u32, Signature)>,
1517 pub func_refs: Vec<(u32, String, u32)>,
1519 pub blocks: Vec<CraneliftBlock>,
1521 pub(super) next_value: u32,
1523 pub(super) next_block: u32,
1525}
1526impl CraneliftFunction {
1527 pub fn new(name: impl Into<String>, sig: Signature) -> Self {
1529 CraneliftFunction {
1530 name: name.into(),
1531 sig,
1532 stack_slots: vec![],
1533 global_values: vec![],
1534 sig_refs: vec![],
1535 func_refs: vec![],
1536 blocks: vec![],
1537 next_value: 0,
1538 next_block: 0,
1539 }
1540 }
1541 pub fn fresh_value(&mut self, ty: CraneliftType) -> CraneliftValue {
1543 let v = CraneliftValue::new(self.next_value, ty);
1544 self.next_value += 1;
1545 v
1546 }
1547 pub fn new_block(&mut self) -> u32 {
1549 let id = self.next_block;
1550 self.next_block += 1;
1551 self.blocks.push(CraneliftBlock::new(id));
1552 id
1553 }
1554 pub fn new_block_with_params(&mut self, param_types: &[CraneliftType]) -> u32 {
1556 let id = self.next_block;
1557 self.next_block += 1;
1558 let params = param_types
1559 .iter()
1560 .map(|ty| {
1561 let v = CraneliftValue::new(self.next_value, ty.clone());
1562 self.next_value += 1;
1563 v
1564 })
1565 .collect();
1566 self.blocks.push(CraneliftBlock::with_params(id, params));
1567 id
1568 }
1569 pub fn block_mut(&mut self, id: u32) -> Option<&mut CraneliftBlock> {
1571 self.blocks.iter_mut().find(|b| b.id == id)
1572 }
1573 pub fn add_stack_slot(&mut self, size_bytes: u32) -> u32 {
1575 let id = self.stack_slots.len() as u32;
1576 self.stack_slots.push((id, size_bytes));
1577 id
1578 }
1579 pub fn emit(&self) -> String {
1581 let mut s = String::new();
1582 s.push_str(&format!("function %{}(", self.name));
1583 for (i, ty) in self.sig.params.iter().enumerate() {
1584 if i > 0 {
1585 s.push_str(", ");
1586 }
1587 s.push_str(&ty.to_string());
1588 }
1589 s.push_str(") -> ");
1590 for (i, ty) in self.sig.returns.iter().enumerate() {
1591 if i > 0 {
1592 s.push_str(", ");
1593 }
1594 s.push_str(&ty.to_string());
1595 }
1596 s.push_str(" system_v {\n");
1597 for (id, size) in &self.stack_slots {
1598 s.push_str(&format!(" ss{} = explicit_slot {}\n", id, size));
1599 }
1600 for (id, name) in &self.global_values {
1601 s.push_str(&format!(" gv{} = symbol colocated %{}\n", id, name));
1602 }
1603 for (id, sig) in &self.sig_refs {
1604 s.push_str(&format!(" sig{} = {}\n", id, sig));
1605 }
1606 for (id, name, sig_id) in &self.func_refs {
1607 s.push_str(&format!(
1608 " fn{} = colocated %{} sig{}\n",
1609 id, name, sig_id
1610 ));
1611 }
1612 if !self.stack_slots.is_empty()
1613 || !self.global_values.is_empty()
1614 || !self.func_refs.is_empty()
1615 {
1616 s.push('\n');
1617 }
1618 for block in &self.blocks {
1619 s.push_str(&block.emit());
1620 }
1621 s.push_str("}\n");
1622 s
1623 }
1624}
1625#[derive(Debug, Clone)]
1627pub struct CraneliftModule {
1628 pub name: String,
1630 pub target: String,
1632 pub functions: Vec<CraneliftFunction>,
1634 pub func_decls: Vec<(String, Signature)>,
1636 pub data_objects: Vec<CraneliftDataObject>,
1638 pub global_values: HashMap<String, u32>,
1640}
1641impl CraneliftModule {
1642 pub fn new(name: impl Into<String>) -> Self {
1644 CraneliftModule {
1645 name: name.into(),
1646 target: "x86_64-unknown-linux-gnu".to_string(),
1647 functions: vec![],
1648 func_decls: vec![],
1649 data_objects: vec![],
1650 global_values: HashMap::new(),
1651 }
1652 }
1653 pub fn add_function(&mut self, func: CraneliftFunction) {
1655 self.functions.push(func);
1656 }
1657 pub fn add_func_decl(&mut self, name: impl Into<String>, sig: Signature) {
1659 self.func_decls.push((name.into(), sig));
1660 }
1661 pub fn add_data_object(&mut self, obj: CraneliftDataObject) {
1663 self.data_objects.push(obj);
1664 }
1665 pub fn emit(&self) -> String {
1667 let mut s = String::new();
1668 s.push_str(&format!("; target = \"{}\"\n\n", self.target));
1669 for (name, sig) in &self.func_decls {
1670 s.push_str(&format!("declare %{}{};\n", name, sig));
1671 }
1672 if !self.func_decls.is_empty() {
1673 s.push('\n');
1674 }
1675 for obj in &self.data_objects {
1676 s.push_str(&obj.emit());
1677 s.push('\n');
1678 }
1679 for func in &self.functions {
1680 s.push_str(&func.emit());
1681 s.push('\n');
1682 }
1683 s
1684 }
1685}