1use crate::ssa::{SSABlock, SSABuilder, SideEffects};
3use crate::variable::Variable;
4use cranelift_codegen::cursor::{Cursor, FuncCursor};
5use cranelift_codegen::entity::{EntitySet, SecondaryMap};
6use cranelift_codegen::ir;
7use cranelift_codegen::ir::function::DisplayFunction;
8use cranelift_codegen::ir::{
9 types, AbiParam, Block, DataFlowGraph, ExtFuncData, ExternalName, FuncRef, Function,
10 GlobalValue, GlobalValueData, Heap, HeapData, Inst, InstBuilder, InstBuilderBase,
11 InstructionData, JumpTable, JumpTableData, LibCall, MemFlags, SigRef, Signature, StackSlot,
12 StackSlotData, Type, Value, ValueLabel, ValueLabelAssignments, ValueLabelStart,
13};
14use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa};
15use cranelift_codegen::packed_option::PackedOption;
16
17pub struct FunctionBuilderContext {
23 ssa: SSABuilder,
24 blocks: SecondaryMap<Block, BlockData>,
25 types: SecondaryMap<Variable, Type>,
26}
27
28pub struct FunctionBuilder<'a> {
30 pub func: &'a mut Function,
33
34 srcloc: ir::SourceLoc,
36
37 func_ctx: &'a mut FunctionBuilderContext,
38 position: &'a mut Position,
39}
40
41#[derive(Clone, Default)]
42struct BlockData {
43 pristine: bool,
46
47 filled: bool,
52
53 user_param_count: usize,
55}
56
57#[derive(Default)]
59pub struct Position {
60 block: PackedOption<Block>,
61 basic_block: PackedOption<SSABlock>,
62}
63
64impl Position {
65 fn at(block: Block, basic_block: SSABlock) -> Self {
66 Self {
67 block: PackedOption::from(block),
68 basic_block: PackedOption::from(basic_block),
69 }
70 }
71
72 fn is_default(&self) -> bool {
73 self.block.is_none() && self.basic_block.is_none()
74 }
75}
76
77impl FunctionBuilderContext {
78 pub fn new() -> Self {
81 Self {
82 ssa: SSABuilder::new(),
83 blocks: SecondaryMap::new(),
84 types: SecondaryMap::new(),
85 }
86 }
87
88 fn clear(&mut self) {
89 self.ssa.clear();
90 self.blocks.clear();
91 self.types.clear();
92 }
93
94 fn is_empty(&self) -> bool {
95 self.ssa.is_empty() && self.blocks.is_empty() && self.types.is_empty()
96 }
97}
98
99pub struct FuncInstBuilder<'short, 'long: 'short> {
102 builder: &'short mut FunctionBuilder<'long>,
103 block: Block,
104}
105
106impl<'short, 'long> FuncInstBuilder<'short, 'long> {
107 fn new(builder: &'short mut FunctionBuilder<'long>, block: Block) -> Self {
108 Self { builder, block }
109 }
110}
111
112impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> {
113 fn data_flow_graph(&self) -> &DataFlowGraph {
114 &self.builder.func.dfg
115 }
116
117 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
118 &mut self.builder.func.dfg
119 }
120
121 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'short mut DataFlowGraph) {
125 self.builder.ensure_inserted_block();
127
128 let inst = self.builder.func.dfg.make_inst(data.clone());
129 self.builder.func.dfg.make_inst_results(inst, ctrl_typevar);
130 self.builder.func.layout.append_inst(inst, self.block);
131 if !self.builder.srcloc.is_default() {
132 self.builder.func.srclocs[inst] = self.builder.srcloc;
133 }
134
135 if data.opcode().is_branch() {
136 match data.branch_destination() {
137 Some(dest_block) => {
138 self.builder.declare_successor(dest_block, inst);
141 }
142 None => {
143 if let InstructionData::BranchTable {
146 table, destination, ..
147 } = data
148 {
149 let mut unique = EntitySet::<Block>::new();
153 for dest_block in self
154 .builder
155 .func
156 .jump_tables
157 .get(table)
158 .expect("you are referencing an undeclared jump table")
159 .iter()
160 .filter(|&dest_block| unique.insert(*dest_block))
161 {
162 self.builder.func_ctx.ssa.declare_block_predecessor(
163 *dest_block,
164 self.builder.position.basic_block.unwrap(),
165 inst,
166 );
167 }
168 self.builder.func_ctx.ssa.declare_block_predecessor(
169 destination,
170 self.builder.position.basic_block.unwrap(),
171 inst,
172 );
173 }
174 }
175 }
176 }
177 if data.opcode().is_terminator() {
178 self.builder.fill_current_block()
179 } else if data.opcode().is_branch() {
180 self.builder.move_to_next_basic_block()
181 }
182 (inst, &mut self.builder.func.dfg)
183 }
184}
185
186impl<'a> FunctionBuilder<'a> {
220 pub fn new(
223 func: &'a mut Function,
224 func_ctx: &'a mut FunctionBuilderContext,
225 position: &'a mut Position,
226 ) -> Self {
227 Self {
229 func,
230 srcloc: Default::default(),
231 func_ctx,
232 position,
233 }
234 }
235
236 pub fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
238 self.srcloc = srcloc;
239 }
240
241 pub fn create_block(&mut self) -> Block {
243 let block = self.func.dfg.make_block();
244 self.func_ctx.ssa.declare_block_header_block(block);
245 self.func_ctx.blocks[block] = BlockData {
246 filled: false,
247 pristine: true,
248 user_param_count: 0,
249 };
250 block
251 }
252
253 pub fn switch_to_block(&mut self, block: Block) {
261 debug_assert!(
263 self.position.is_default()
264 || self.is_unreachable()
265 || self.is_pristine()
266 || self.is_filled(),
267 "you have to fill your block before switching"
268 );
269 debug_assert!(
271 !self.func_ctx.blocks[block].filled,
272 "you cannot switch to a block which is already filled"
273 );
274
275 let basic_block = self.func_ctx.ssa.header_block(block);
276 *self.position = Position::at(block, basic_block);
278 }
279
280 pub fn seal_block(&mut self, block: Block) {
286 let side_effects = self.func_ctx.ssa.seal_block_header_block(block, self.func);
287 self.handle_ssa_side_effects(side_effects);
288 }
289
290 pub fn seal_all_blocks(&mut self) {
297 let side_effects = self.func_ctx.ssa.seal_all_block_header_blocks(self.func);
298 self.handle_ssa_side_effects(side_effects);
299 }
300
301 pub fn declare_var(&mut self, var: Variable, ty: Type) {
303 self.func_ctx.types[var] = ty;
304 }
305
306 pub fn use_var(&mut self, var: Variable) -> Value {
309 let (val, side_effects) = {
310 let ty = *self.func_ctx.types.get(var).unwrap_or_else(|| {
311 panic!(
312 "variable {:?} is used but its type has not been declared",
313 var
314 )
315 });
316 self.func_ctx
317 .ssa
318 .use_var(self.func, var, ty, self.position.basic_block.unwrap())
319 };
320 self.handle_ssa_side_effects(side_effects);
321 val
322 }
323
324 pub fn def_var(&mut self, var: Variable, val: Value) {
327 debug_assert_eq!(
328 *self.func_ctx.types.get(var).unwrap_or_else(|| panic!(
329 "variable {:?} is used but its type has not been declared",
330 var
331 )),
332 self.func.dfg.value_type(val),
333 "declared type of variable {:?} doesn't match type of value {}",
334 var,
335 val
336 );
337
338 self.func_ctx
339 .ssa
340 .def_var(var, val, self.position.basic_block.unwrap());
341 }
342
343 pub fn set_val_label(&mut self, val: Value, label: ValueLabel) {
347 if let Some(values_labels) = self.func.dfg.values_labels.as_mut() {
348 use crate::hash_map::Entry;
349
350 let start = ValueLabelStart {
351 from: self.srcloc,
352 label,
353 };
354
355 match values_labels.entry(val) {
356 Entry::Occupied(mut e) => match e.get_mut() {
357 ValueLabelAssignments::Starts(starts) => starts.push(start),
358 _ => panic!("Unexpected ValueLabelAssignments at this stage"),
359 },
360 Entry::Vacant(e) => {
361 e.insert(ValueLabelAssignments::Starts(vec![start]));
362 }
363 }
364 }
365 }
366
367 pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
369 self.func.create_jump_table(data)
370 }
371
372 pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
375 self.func.create_stack_slot(data)
376 }
377
378 pub fn import_signature(&mut self, signature: Signature) -> SigRef {
380 self.func.import_signature(signature)
381 }
382
383 pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
385 self.func.import_function(data)
386 }
387
388 pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue {
390 self.func.create_global_value(data)
391 }
392
393 pub fn create_heap(&mut self, data: HeapData) -> Heap {
395 self.func.create_heap(data)
396 }
397
398 pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> {
401 let block = self
402 .position
403 .block
404 .expect("Please call switch_to_block before inserting instructions");
405 FuncInstBuilder::new(self, block)
406 }
407
408 pub fn ensure_inserted_block(&mut self) {
410 let block = self.position.block.unwrap();
411 if self.func_ctx.blocks[block].pristine {
412 if !self.func.layout.is_block_inserted(block) {
413 self.func.layout.append_block(block);
414 }
415 self.func_ctx.blocks[block].pristine = false;
416 } else {
417 debug_assert!(
418 !self.func_ctx.blocks[block].filled,
419 "you cannot add an instruction to a block already filled"
420 );
421 }
422 }
423
424 pub fn cursor(&mut self) -> FuncCursor {
429 self.ensure_inserted_block();
430 FuncCursor::new(self.func)
431 .with_srcloc(self.srcloc)
432 .at_bottom(self.position.block.unwrap())
433 }
434
435 pub fn append_block_params_for_function_params(&mut self, block: Block) {
439 debug_assert!(
440 !self.func_ctx.ssa.has_any_predecessors(block),
441 "block parameters for function parameters should only be added to the entry block"
442 );
443
444 let user_param_count = &mut self.func_ctx.blocks[block].user_param_count;
447 for argtyp in &self.func.signature.params {
448 *user_param_count += 1;
449 self.func.dfg.append_block_param(block, argtyp.value_type);
450 }
451 }
452
453 pub fn append_block_params_for_function_returns(&mut self, block: Block) {
457 let user_param_count = &mut self.func_ctx.blocks[block].user_param_count;
460 for argtyp in &self.func.signature.returns {
461 *user_param_count += 1;
462 self.func.dfg.append_block_param(block, argtyp.value_type);
463 }
464 }
465
466 pub fn finalize(&mut self) {
470 debug_assert!(
472 self.func_ctx.blocks.iter().all(
473 |(block, block_data)| block_data.pristine || self.func_ctx.ssa.is_sealed(block)
474 ),
475 "all blocks should be sealed before dropping a FunctionBuilder"
476 );
477 debug_assert!(
478 self.func_ctx
479 .blocks
480 .values()
481 .all(|block_data| block_data.pristine || block_data.filled),
482 "all blocks should be filled before dropping a FunctionBuilder"
483 );
484
485 #[cfg(debug_assertions)]
487 {
488 for block in self.func_ctx.blocks.keys() {
490 if let Err((inst, _msg)) = self.func.is_block_basic(block) {
491 let inst_str = self.func.dfg.display_inst(inst, None);
492 panic!("{} failed basic block invariants on {}", block, inst_str);
493 }
494 }
495 }
496
497 self.func_ctx.clear();
500
501 self.srcloc = Default::default();
503 *self.position = Position::default();
504 }
505}
506
507impl<'a> FunctionBuilder<'a> {
513 pub fn block_params(&self, block: Block) -> &[Value] {
516 self.func.dfg.block_params(block)
517 }
518
519 pub fn signature(&self, sigref: SigRef) -> Option<&Signature> {
521 self.func.dfg.signatures.get(sigref)
522 }
523
524 pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value {
530 debug_assert!(
531 self.func_ctx.blocks[block].pristine,
532 "You can't add block parameters after adding any instruction"
533 );
534 debug_assert_eq!(
535 self.func_ctx.blocks[block].user_param_count,
536 self.func.dfg.num_block_params(block)
537 );
538 self.func_ctx.blocks[block].user_param_count += 1;
539 self.func.dfg.append_block_param(block, ty)
540 }
541
542 pub fn inst_results(&self, inst: Inst) -> &[Value] {
544 self.func.dfg.inst_results(inst)
545 }
546
547 pub fn change_jump_destination(&mut self, inst: Inst, new_dest: Block) {
552 let old_dest = self.func.dfg[inst]
553 .branch_destination_mut()
554 .expect("you want to change the jump destination of a non-jump instruction");
555 let pred = self.func_ctx.ssa.remove_block_predecessor(*old_dest, inst);
556 *old_dest = new_dest;
557 self.func_ctx
558 .ssa
559 .declare_block_predecessor(new_dest, pred, inst);
560 }
561
562 pub fn is_unreachable(&self) -> bool {
566 let is_entry = match self.func.layout.entry_block() {
567 None => false,
568 Some(entry) => self.position.block.unwrap() == entry,
569 };
570 !is_entry
571 && self.func_ctx.ssa.is_sealed(self.position.block.unwrap())
572 && !self
573 .func_ctx
574 .ssa
575 .has_any_predecessors(self.position.block.unwrap())
576 }
577
578 pub fn is_pristine(&self) -> bool {
581 self.func_ctx.blocks[self.position.block.unwrap()].pristine
582 }
583
584 pub fn is_filled(&self) -> bool {
587 self.func_ctx.blocks[self.position.block.unwrap()].filled
588 }
589
590 #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))]
595 pub fn display<'b, I: Into<Option<&'b dyn TargetIsa>>>(&'b self, isa: I) -> DisplayFunction {
596 self.func.display(isa)
597 }
598}
599
600impl<'a> FunctionBuilder<'a> {
602 pub fn call_memcpy(
609 &mut self,
610 config: TargetFrontendConfig,
611 dest: Value,
612 src: Value,
613 size: Value,
614 ) {
615 let pointer_type = config.pointer_type();
616 let signature = {
617 let mut s = Signature::new(config.default_call_conv);
618 s.params.push(AbiParam::new(pointer_type));
619 s.params.push(AbiParam::new(pointer_type));
620 s.params.push(AbiParam::new(pointer_type));
621 self.import_signature(s)
622 };
623
624 let libc_memcpy = self.import_function(ExtFuncData {
625 name: ExternalName::LibCall(LibCall::Memcpy),
626 signature,
627 colocated: false,
628 });
629
630 self.ins().call(libc_memcpy, &[dest, src, size]);
631 }
632
633 pub fn emit_small_memory_copy(
642 &mut self,
643 config: TargetFrontendConfig,
644 dest: Value,
645 src: Value,
646 size: u64,
647 dest_align: u8,
648 src_align: u8,
649 non_overlapping: bool,
650 ) {
651 const THRESHOLD: u64 = 4;
653
654 if size == 0 {
655 return;
656 }
657
658 let access_size = greatest_divisible_power_of_two(size);
659 assert!(
660 access_size.is_power_of_two(),
661 "`size` is not a power of two"
662 );
663 assert!(
664 access_size >= u64::from(::core::cmp::min(src_align, dest_align)),
665 "`size` is smaller than `dest` and `src`'s alignment value."
666 );
667
668 let (access_size, int_type) = if access_size <= 8 {
669 (access_size, Type::int((access_size * 8) as u16).unwrap())
670 } else {
671 (8, types::I64)
672 };
673
674 let load_and_store_amount = size / access_size;
675
676 if load_and_store_amount > THRESHOLD {
677 let size_value = self.ins().iconst(config.pointer_type(), size as i64);
678 if non_overlapping {
679 self.call_memcpy(config, dest, src, size_value);
680 } else {
681 self.call_memmove(config, dest, src, size_value);
682 }
683 return;
684 }
685
686 let mut flags = MemFlags::new();
687 flags.set_aligned();
688
689 let registers: smallvec::SmallVec<[_; THRESHOLD as usize]> = (0..load_and_store_amount)
692 .map(|i| {
693 let offset = (access_size * i) as i32;
694 (self.ins().load(int_type, flags, src, offset), offset)
695 })
696 .collect();
697
698 for (value, offset) in registers {
699 self.ins().store(flags, value, dest, offset);
700 }
701 }
702
703 pub fn call_memset(
707 &mut self,
708 config: TargetFrontendConfig,
709 buffer: Value,
710 ch: Value,
711 size: Value,
712 ) {
713 let pointer_type = config.pointer_type();
714 let signature = {
715 let mut s = Signature::new(config.default_call_conv);
716 s.params.push(AbiParam::new(pointer_type));
717 s.params.push(AbiParam::new(types::I32));
718 s.params.push(AbiParam::new(pointer_type));
719 self.import_signature(s)
720 };
721
722 let libc_memset = self.import_function(ExtFuncData {
723 name: ExternalName::LibCall(LibCall::Memset),
724 signature,
725 colocated: false,
726 });
727
728 let ch = self.ins().uextend(types::I32, ch);
729 self.ins().call(libc_memset, &[buffer, ch, size]);
730 }
731
732 pub fn emit_small_memset(
736 &mut self,
737 config: TargetFrontendConfig,
738 buffer: Value,
739 ch: u8,
740 size: u64,
741 buffer_align: u8,
742 ) {
743 const THRESHOLD: u64 = 4;
745
746 if size == 0 {
747 return;
748 }
749
750 let access_size = greatest_divisible_power_of_two(size);
751 assert!(
752 access_size.is_power_of_two(),
753 "`size` is not a power of two"
754 );
755 assert!(
756 access_size >= u64::from(buffer_align),
757 "`size` is smaller than `dest` and `src`'s alignment value."
758 );
759
760 let (access_size, int_type) = if access_size <= 8 {
761 (access_size, Type::int((access_size * 8) as u16).unwrap())
762 } else {
763 (8, types::I64)
764 };
765
766 let load_and_store_amount = size / access_size;
767
768 if load_and_store_amount > THRESHOLD {
769 let ch = self.ins().iconst(types::I8, i64::from(ch));
770 let size = self.ins().iconst(config.pointer_type(), size as i64);
771 self.call_memset(config, buffer, ch, size);
772 } else {
773 let mut flags = MemFlags::new();
774 flags.set_aligned();
775
776 let ch = u64::from(ch);
777 let raw_value = if int_type == types::I64 {
778 (ch << 32) | (ch << 16) | (ch << 8) | ch
779 } else if int_type == types::I32 {
780 (ch << 16) | (ch << 8) | ch
781 } else if int_type == types::I16 {
782 (ch << 8) | ch
783 } else {
784 assert_eq!(int_type, types::I8);
785 ch
786 };
787
788 let value = self.ins().iconst(int_type, raw_value as i64);
789 for i in 0..load_and_store_amount {
790 let offset = (access_size * i) as i32;
791 self.ins().store(flags, value, buffer, offset);
792 }
793 }
794 }
795
796 pub fn call_memmove(
801 &mut self,
802 config: TargetFrontendConfig,
803 dest: Value,
804 source: Value,
805 size: Value,
806 ) {
807 let pointer_type = config.pointer_type();
808 let signature = {
809 let mut s = Signature::new(config.default_call_conv);
810 s.params.push(AbiParam::new(pointer_type));
811 s.params.push(AbiParam::new(pointer_type));
812 s.params.push(AbiParam::new(pointer_type));
813 self.import_signature(s)
814 };
815
816 let libc_memmove = self.import_function(ExtFuncData {
817 name: ExternalName::LibCall(LibCall::Memmove),
818 signature,
819 colocated: false,
820 });
821
822 self.ins().call(libc_memmove, &[dest, source, size]);
823 }
824}
825
826fn greatest_divisible_power_of_two(size: u64) -> u64 {
827 (size as i64 & -(size as i64)) as u64
828}
829
830impl<'a> FunctionBuilder<'a> {
832 fn move_to_next_basic_block(&mut self) {
833 self.position.basic_block = PackedOption::from(
834 self.func_ctx
835 .ssa
836 .declare_block_body_block(self.position.basic_block.unwrap()),
837 );
838 }
839
840 fn fill_current_block(&mut self) {
842 self.func_ctx.blocks[self.position.block.unwrap()].filled = true;
843 }
844
845 fn declare_successor(&mut self, dest_block: Block, jump_inst: Inst) {
846 self.func_ctx.ssa.declare_block_predecessor(
847 dest_block,
848 self.position.basic_block.unwrap(),
849 jump_inst,
850 );
851 }
852
853 fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) {
854 for split_block in side_effects.split_blocks_created {
855 self.func_ctx.blocks[split_block].filled = true
856 }
857 for modified_block in side_effects.instructions_added_to_blocks {
858 self.func_ctx.blocks[modified_block].pristine = false
859 }
860 }
861}
862
863#[cfg(test)]
864mod tests {
865 use super::greatest_divisible_power_of_two;
866 use crate::frontend::{FunctionBuilder, FunctionBuilderContext, Position};
867 use crate::Variable;
868 use alloc::string::ToString;
869 use cranelift_codegen::entity::EntityRef;
870 use cranelift_codegen::ir::types::*;
871 use cranelift_codegen::ir::{AbiParam, ExternalName, Function, InstBuilder, Signature};
872 use cranelift_codegen::isa::CallConv;
873 use cranelift_codegen::settings;
874 use cranelift_codegen::verifier::verify_function;
875
876 fn sample_function(lazy_seal: bool) {
877 let mut sig = Signature::new(CallConv::SystemV);
878 sig.returns.push(AbiParam::new(I32));
879 sig.params.push(AbiParam::new(I32));
880
881 let mut fn_ctx = FunctionBuilderContext::new();
882 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
883 let mut position = Position::default();
884 {
885 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
886
887 let block0 = builder.create_block();
888 let block1 = builder.create_block();
889 let block2 = builder.create_block();
890 let block3 = builder.create_block();
891 let x = Variable::new(0);
892 let y = Variable::new(1);
893 let z = Variable::new(2);
894 builder.declare_var(x, I32);
895 builder.declare_var(y, I32);
896 builder.declare_var(z, I32);
897 builder.append_block_params_for_function_params(block0);
898
899 builder.switch_to_block(block0);
900 if !lazy_seal {
901 builder.seal_block(block0);
902 }
903 {
904 let tmp = builder.block_params(block0)[0]; builder.def_var(x, tmp);
906 }
907 {
908 let tmp = builder.ins().iconst(I32, 2);
909 builder.def_var(y, tmp);
910 }
911 {
912 let arg1 = builder.use_var(x);
913 let arg2 = builder.use_var(y);
914 let tmp = builder.ins().iadd(arg1, arg2);
915 builder.def_var(z, tmp);
916 }
917 builder.ins().jump(block1, &[]);
918
919 builder.switch_to_block(block1);
920 {
921 let arg1 = builder.use_var(y);
922 let arg2 = builder.use_var(z);
923 let tmp = builder.ins().iadd(arg1, arg2);
924 builder.def_var(z, tmp);
925 }
926 {
927 let arg = builder.use_var(y);
928 builder.ins().brnz(arg, block3, &[]);
929 }
930 builder.ins().jump(block2, &[]);
931
932 builder.switch_to_block(block2);
933 if !lazy_seal {
934 builder.seal_block(block2);
935 }
936 {
937 let arg1 = builder.use_var(z);
938 let arg2 = builder.use_var(x);
939 let tmp = builder.ins().isub(arg1, arg2);
940 builder.def_var(z, tmp);
941 }
942 {
943 let arg = builder.use_var(y);
944 builder.ins().return_(&[arg]);
945 }
946
947 builder.switch_to_block(block3);
948 if !lazy_seal {
949 builder.seal_block(block3);
950 }
951
952 {
953 let arg1 = builder.use_var(y);
954 let arg2 = builder.use_var(x);
955 let tmp = builder.ins().isub(arg1, arg2);
956 builder.def_var(y, tmp);
957 }
958 builder.ins().jump(block1, &[]);
959 if !lazy_seal {
960 builder.seal_block(block1);
961 }
962
963 if lazy_seal {
964 builder.seal_all_blocks();
965 }
966
967 builder.finalize();
968 }
969
970 let flags = settings::Flags::new(settings::builder());
971 if let Err(errors) = verify_function(&func, &flags) {
973 panic!("{}\n{}", func.display(None), errors)
974 }
975 }
976
977 #[test]
978 fn sample() {
979 sample_function(false)
980 }
981
982 #[test]
983 fn sample_with_lazy_seal() {
984 sample_function(true)
985 }
986
987 #[test]
988 fn memcpy() {
989 use core::str::FromStr;
990 use cranelift_codegen::{isa, settings};
991
992 let shared_builder = settings::builder();
993 let shared_flags = settings::Flags::new(shared_builder);
994
995 let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
996
997 let target = isa::lookup(triple)
998 .ok()
999 .map(|b| b.finish(shared_flags))
1000 .expect("This test requires arm support.");
1001
1002 let mut sig = Signature::new(target.default_call_conv());
1003 sig.returns.push(AbiParam::new(I32));
1004
1005 let mut fn_ctx = FunctionBuilderContext::new();
1006 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1007 let mut position = Position::default();
1008 {
1009 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
1010
1011 let block0 = builder.create_block();
1012 let x = Variable::new(0);
1013 let y = Variable::new(1);
1014 let z = Variable::new(2);
1015 builder.declare_var(x, target.pointer_type());
1016 builder.declare_var(y, target.pointer_type());
1017 builder.declare_var(z, I32);
1018 builder.append_block_params_for_function_params(block0);
1019 builder.switch_to_block(block0);
1020
1021 let src = builder.use_var(x);
1022 let dest = builder.use_var(y);
1023 let size = builder.use_var(y);
1024 builder.call_memcpy(target.frontend_config(), dest, src, size);
1025 builder.ins().return_(&[size]);
1026
1027 builder.seal_all_blocks();
1028 builder.finalize();
1029 }
1030
1031 assert_eq!(
1032 func.display(None).to_string(),
1033 "function %sample() -> i32 system_v {
1034 sig0 = (i32, i32, i32) system_v
1035 fn0 = %Memcpy sig0
1036
1037block0:
1038 v3 = iconst.i32 0
1039 v1 -> v3
1040 v2 = iconst.i32 0
1041 v0 -> v2
1042 call fn0(v1, v0, v1)
1043 return v1
1044}
1045"
1046 );
1047 }
1048
1049 #[test]
1050 fn small_memcpy() {
1051 use core::str::FromStr;
1052 use cranelift_codegen::{isa, settings};
1053
1054 let shared_builder = settings::builder();
1055 let shared_flags = settings::Flags::new(shared_builder);
1056
1057 let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1058
1059 let target = isa::lookup(triple)
1060 .ok()
1061 .map(|b| b.finish(shared_flags))
1062 .expect("This test requires arm support.");
1063
1064 let mut sig = Signature::new(target.default_call_conv());
1065 sig.returns.push(AbiParam::new(I32));
1066
1067 let mut fn_ctx = FunctionBuilderContext::new();
1068 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1069 let mut position = Position::default();
1070 {
1071 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
1072
1073 let block0 = builder.create_block();
1074 let x = Variable::new(0);
1075 let y = Variable::new(16);
1076 builder.declare_var(x, target.pointer_type());
1077 builder.declare_var(y, target.pointer_type());
1078 builder.append_block_params_for_function_params(block0);
1079 builder.switch_to_block(block0);
1080
1081 let src = builder.use_var(x);
1082 let dest = builder.use_var(y);
1083 let size = 8;
1084 builder.emit_small_memory_copy(target.frontend_config(), dest, src, size, 8, 8, true);
1085 builder.ins().return_(&[dest]);
1086
1087 builder.seal_all_blocks();
1088 builder.finalize();
1089 }
1090
1091 assert_eq!(
1092 func.display(None).to_string(),
1093 "function %sample() -> i32 system_v {
1094block0:
1095 v4 = iconst.i32 0
1096 v1 -> v4
1097 v3 = iconst.i32 0
1098 v0 -> v3
1099 v2 = load.i64 aligned v0
1100 store aligned v2, v1
1101 return v1
1102}
1103"
1104 );
1105 }
1106
1107 #[test]
1108 fn not_so_small_memcpy() {
1109 use core::str::FromStr;
1110 use cranelift_codegen::{isa, settings};
1111
1112 let shared_builder = settings::builder();
1113 let shared_flags = settings::Flags::new(shared_builder);
1114
1115 let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1116
1117 let target = isa::lookup(triple)
1118 .ok()
1119 .map(|b| b.finish(shared_flags))
1120 .expect("This test requires arm support.");
1121
1122 let mut sig = Signature::new(target.default_call_conv());
1123 sig.returns.push(AbiParam::new(I32));
1124
1125 let mut fn_ctx = FunctionBuilderContext::new();
1126 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1127 let mut position = Position::default();
1128 {
1129 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
1130
1131 let block0 = builder.create_block();
1132 let x = Variable::new(0);
1133 let y = Variable::new(16);
1134 builder.declare_var(x, target.pointer_type());
1135 builder.declare_var(y, target.pointer_type());
1136 builder.append_block_params_for_function_params(block0);
1137 builder.switch_to_block(block0);
1138
1139 let src = builder.use_var(x);
1140 let dest = builder.use_var(y);
1141 let size = 8192;
1142 builder.emit_small_memory_copy(target.frontend_config(), dest, src, size, 8, 8, true);
1143 builder.ins().return_(&[dest]);
1144
1145 builder.seal_all_blocks();
1146 builder.finalize();
1147 }
1148
1149 assert_eq!(
1150 func.display(None).to_string(),
1151 "function %sample() -> i32 system_v {
1152 sig0 = (i32, i32, i32) system_v
1153 fn0 = %Memcpy sig0
1154
1155block0:
1156 v4 = iconst.i32 0
1157 v1 -> v4
1158 v3 = iconst.i32 0
1159 v0 -> v3
1160 v2 = iconst.i32 8192
1161 call fn0(v1, v0, v2)
1162 return v1
1163}
1164"
1165 );
1166 }
1167
1168 #[test]
1169 fn small_memset() {
1170 use core::str::FromStr;
1171 use cranelift_codegen::{isa, settings};
1172
1173 let shared_builder = settings::builder();
1174 let shared_flags = settings::Flags::new(shared_builder);
1175
1176 let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1177
1178 let target = isa::lookup(triple)
1179 .ok()
1180 .map(|b| b.finish(shared_flags))
1181 .expect("This test requires arm support.");
1182
1183 let mut sig = Signature::new(target.default_call_conv());
1184 sig.returns.push(AbiParam::new(I32));
1185
1186 let mut fn_ctx = FunctionBuilderContext::new();
1187 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1188 let mut position = Position::default();
1189 {
1190 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
1191
1192 let block0 = builder.create_block();
1193 let y = Variable::new(16);
1194 builder.declare_var(y, target.pointer_type());
1195 builder.append_block_params_for_function_params(block0);
1196 builder.switch_to_block(block0);
1197
1198 let dest = builder.use_var(y);
1199 let size = 8;
1200 builder.emit_small_memset(target.frontend_config(), dest, 1, size, 8);
1201 builder.ins().return_(&[dest]);
1202
1203 builder.seal_all_blocks();
1204 builder.finalize();
1205 }
1206
1207 assert_eq!(
1208 func.display(None).to_string(),
1209 "function %sample() -> i32 system_v {
1210block0:
1211 v2 = iconst.i32 0
1212 v0 -> v2
1213 v1 = iconst.i64 0x0001_0001_0101
1214 store aligned v1, v0
1215 return v0
1216}
1217"
1218 );
1219 }
1220
1221 #[test]
1222 fn not_so_small_memset() {
1223 use core::str::FromStr;
1224 use cranelift_codegen::{isa, settings};
1225
1226 let shared_builder = settings::builder();
1227 let shared_flags = settings::Flags::new(shared_builder);
1228
1229 let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1230
1231 let target = isa::lookup(triple)
1232 .ok()
1233 .map(|b| b.finish(shared_flags))
1234 .expect("This test requires arm support.");
1235
1236 let mut sig = Signature::new(target.default_call_conv());
1237 sig.returns.push(AbiParam::new(I32));
1238
1239 let mut fn_ctx = FunctionBuilderContext::new();
1240 let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1241 let mut position = Position::default();
1242 {
1243 let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx, &mut position);
1244
1245 let block0 = builder.create_block();
1246 let y = Variable::new(16);
1247 builder.declare_var(y, target.pointer_type());
1248 builder.append_block_params_for_function_params(block0);
1249 builder.switch_to_block(block0);
1250
1251 let dest = builder.use_var(y);
1252 let size = 8192;
1253 builder.emit_small_memset(target.frontend_config(), dest, 1, size, 8);
1254 builder.ins().return_(&[dest]);
1255
1256 builder.seal_all_blocks();
1257 builder.finalize();
1258 }
1259
1260 assert_eq!(
1261 func.display(None).to_string(),
1262 "function %sample() -> i32 system_v {
1263 sig0 = (i32, i32, i32) system_v
1264 fn0 = %Memset sig0
1265
1266block0:
1267 v4 = iconst.i32 0
1268 v0 -> v4
1269 v1 = iconst.i8 1
1270 v2 = iconst.i32 8192
1271 v3 = uextend.i32 v1
1272 call fn0(v0, v3, v2)
1273 return v0
1274}
1275"
1276 );
1277 }
1278
1279 #[test]
1280 fn test_greatest_divisible_power_of_two() {
1281 assert_eq!(64, greatest_divisible_power_of_two(64));
1282 assert_eq!(16, greatest_divisible_power_of_two(48));
1283 assert_eq!(8, greatest_divisible_power_of_two(24));
1284 assert_eq!(1, greatest_divisible_power_of_two(25));
1285 }
1286}