1 //! A frontend for building Cranelift IR from other languages.
2 use crate::ssa::{Block, SSABuilder, SideEffects};
3 use crate::variable::Variable;
4 use cranelift_codegen::cursor::{Cursor, FuncCursor};
5 use cranelift_codegen::entity::{EntitySet, SecondaryMap};
6 use cranelift_codegen::ir;
7 use cranelift_codegen::ir::function::DisplayFunction;
8 use cranelift_codegen::ir::{
9     types, AbiParam, DataFlowGraph, Ebb, ExtFuncData, ExternalName, FuncRef, Function, GlobalValue,
10     GlobalValueData, Heap, HeapData, Inst, InstBuilder, InstBuilderBase, InstructionData,
11     JumpTable, JumpTableData, LibCall, MemFlags, SigRef, Signature, StackSlot, StackSlotData, Type,
12     Value, ValueLabel, ValueLabelAssignments, ValueLabelStart,
13 };
14 use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa};
15 use cranelift_codegen::packed_option::PackedOption;
16 use std::vec::Vec;
17 
18 /// Structure used for translating a series of functions into Cranelift IR.
19 ///
20 /// In order to reduce memory reallocations when compiling multiple functions,
21 /// `FunctionBuilderContext` holds various data structures which are cleared between
22 /// functions, rather than dropped, preserving the underlying allocations.
23 pub struct FunctionBuilderContext {
24     ssa: SSABuilder,
25     ebbs: SecondaryMap<Ebb, EbbData>,
26     types: SecondaryMap<Variable, Type>,
27 }
28 
29 /// Temporary object used to build a single Cranelift IR `Function`.
30 pub struct FunctionBuilder<'a> {
31     /// The function currently being built.
32     /// This field is public so the function can be re-borrowed.
33     pub func: &'a mut Function,
34 
35     /// Source location to assign to all new instructions.
36     srcloc: ir::SourceLoc,
37 
38     func_ctx: &'a mut FunctionBuilderContext,
39     position: Position,
40 }
41 
42 #[derive(Clone, Default)]
43 struct EbbData {
44     /// An Ebb is "pristine" iff no instructions have been added since the last
45     /// call to `switch_to_block()`.
46     pristine: bool,
47 
48     /// An Ebb is "filled" iff a terminator instruction has been inserted since
49     /// the last call to `switch_to_block()`.
50     ///
51     /// A filled block cannot be pristine.
52     filled: bool,
53 
54     /// Count of parameters not supplied implicitly by the SSABuilder.
55     user_param_count: usize,
56 }
57 
58 #[derive(Default)]
59 struct Position {
60     ebb: PackedOption<Ebb>,
61     basic_block: PackedOption<Block>,
62 }
63 
64 impl Position {
at(ebb: Ebb, basic_block: Block) -> Self65     fn at(ebb: Ebb, basic_block: Block) -> Self {
66         Self {
67             ebb: PackedOption::from(ebb),
68             basic_block: PackedOption::from(basic_block),
69         }
70     }
71 
is_default(&self) -> bool72     fn is_default(&self) -> bool {
73         self.ebb.is_none() && self.basic_block.is_none()
74     }
75 }
76 
77 impl FunctionBuilderContext {
78     /// Creates a FunctionBuilderContext structure. The structure is automatically cleared after
79     /// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function.
new() -> Self80     pub fn new() -> Self {
81         Self {
82             ssa: SSABuilder::new(),
83             ebbs: SecondaryMap::new(),
84             types: SecondaryMap::new(),
85         }
86     }
87 
clear(&mut self)88     fn clear(&mut self) {
89         self.ssa.clear();
90         self.ebbs.clear();
91         self.types.clear();
92     }
93 
is_empty(&self) -> bool94     fn is_empty(&self) -> bool {
95         self.ssa.is_empty() && self.ebbs.is_empty() && self.types.is_empty()
96     }
97 }
98 
99 /// Implementation of the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) that has
100 /// one convenience method per Cranelift IR instruction.
101 pub struct FuncInstBuilder<'short, 'long: 'short> {
102     builder: &'short mut FunctionBuilder<'long>,
103     ebb: Ebb,
104 }
105 
106 impl<'short, 'long> FuncInstBuilder<'short, 'long> {
new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self107     fn new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self {
108         Self { builder, ebb }
109     }
110 }
111 
112 impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> {
data_flow_graph(&self) -> &DataFlowGraph113     fn data_flow_graph(&self) -> &DataFlowGraph {
114         &self.builder.func.dfg
115     }
116 
data_flow_graph_mut(&mut self) -> &mut DataFlowGraph117     fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
118         &mut self.builder.func.dfg
119     }
120 
121     // This implementation is richer than `InsertBuilder` because we use the data of the
122     // instruction being inserted to add related info to the DFG and the SSA building system,
123     // and perform debug sanity checks.
build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'short mut DataFlowGraph)124     fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'short mut DataFlowGraph) {
125         // We only insert the Ebb in the layout when an instruction is added to it
126         self.builder.ensure_inserted_ebb();
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.ebb);
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_ebb) => {
138                     // If the user has supplied jump arguments we must adapt the arguments of
139                     // the destination ebb
140                     self.builder.declare_successor(dest_ebb, inst);
141                 }
142                 None => {
143                     // branch_destination() doesn't detect jump_tables
144                     // If jump table we declare all entries successor
145                     if let InstructionData::BranchTable {
146                         table, destination, ..
147                     } = data
148                     {
149                         // Unlike all other jumps/branches, jump tables are
150                         // capable of having the same successor appear
151                         // multiple times, so we must deduplicate.
152                         let mut unique = EntitySet::<Ebb>::new();
153                         for dest_ebb 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_ebb| unique.insert(*dest_ebb))
161                         {
162                             self.builder.func_ctx.ssa.declare_ebb_predecessor(
163                                 *dest_ebb,
164                                 self.builder.position.basic_block.unwrap(),
165                                 inst,
166                             );
167                         }
168                         self.builder.func_ctx.ssa.declare_ebb_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 
186 /// This module allows you to create a function in Cranelift IR in a straightforward way, hiding
187 /// all the complexity of its internal representation.
188 ///
189 /// The module is parametrized by one type which is the representation of variables in your
190 /// origin language. It offers a way to conveniently append instruction to your program flow.
191 /// You are responsible to split your instruction flow into extended blocks (declared with
192 /// `create_ebb`) whose properties are:
193 ///
194 /// - branch and jump instructions can only point at the top of extended blocks;
195 /// - the last instruction of each block is a terminator instruction which has no natural successor,
196 ///   and those instructions can only appear at the end of extended blocks.
197 ///
198 /// The parameters of Cranelift IR instructions are Cranelift IR values, which can only be created
199 /// as results of other Cranelift IR instructions. To be able to create variables redefined multiple
200 /// times in your program, use the `def_var` and `use_var` command, that will maintain the
201 /// correspondence between your variables and Cranelift IR SSA values.
202 ///
203 /// The first block for which you call `switch_to_block` will be assumed to be the beginning of
204 /// the function.
205 ///
206 /// At creation, a `FunctionBuilder` instance borrows an already allocated `Function` which it
207 /// modifies with the information stored in the mutable borrowed
208 /// [`FunctionBuilderContext`](struct.FunctionBuilderContext.html). The function passed in
209 /// argument should be newly created with
210 /// [`Function::with_name_signature()`](Function::with_name_signature), whereas the
211 /// `FunctionBuilderContext` can be kept as is between two function translations.
212 ///
213 /// # Errors
214 ///
215 /// The functions below will panic in debug mode whenever you try to modify the Cranelift IR
216 /// function in a way that violate the coherence of the code. For instance: switching to a new
217 /// `Ebb` when you haven't filled the current one with a terminator instruction, inserting a
218 /// return instruction with arguments that don't match the function's signature.
219 impl<'a> FunctionBuilder<'a> {
220     /// Creates a new FunctionBuilder structure that will operate on a `Function` using a
221     /// `FunctionBuilderContext`.
new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self222     pub fn new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self {
223         debug_assert!(func_ctx.is_empty());
224         Self {
225             func,
226             srcloc: Default::default(),
227             func_ctx,
228             position: Position::default(),
229         }
230     }
231 
232     /// Set the source location that should be assigned to all new instructions.
set_srcloc(&mut self, srcloc: ir::SourceLoc)233     pub fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
234         self.srcloc = srcloc;
235     }
236 
237     /// Creates a new `Ebb` and returns its reference.
create_ebb(&mut self) -> Ebb238     pub fn create_ebb(&mut self) -> Ebb {
239         let ebb = self.func.dfg.make_ebb();
240         self.func_ctx.ssa.declare_ebb_header_block(ebb);
241         self.func_ctx.ebbs[ebb] = EbbData {
242             filled: false,
243             pristine: true,
244             user_param_count: 0,
245         };
246         ebb
247     }
248 
249     /// After the call to this function, new instructions will be inserted into the designated
250     /// block, in the order they are declared. You must declare the types of the Ebb arguments
251     /// you will use here.
252     ///
253     /// When inserting the terminator instruction (which doesn't have a fallthrough to its immediate
254     /// successor), the block will be declared filled and it will not be possible to append
255     /// instructions to it.
switch_to_block(&mut self, ebb: Ebb)256     pub fn switch_to_block(&mut self, ebb: Ebb) {
257         // First we check that the previous block has been filled.
258         debug_assert!(
259             self.position.is_default()
260                 || self.is_unreachable()
261                 || self.is_pristine()
262                 || self.is_filled(),
263             "you have to fill your block before switching"
264         );
265         // We cannot switch to a filled block
266         debug_assert!(
267             !self.func_ctx.ebbs[ebb].filled,
268             "you cannot switch to a block which is already filled"
269         );
270 
271         let basic_block = self.func_ctx.ssa.header_block(ebb);
272         // Then we change the cursor position.
273         self.position = Position::at(ebb, basic_block);
274     }
275 
276     /// Declares that all the predecessors of this block are known.
277     ///
278     /// Function to call with `ebb` as soon as the last branch instruction to `ebb` has been
279     /// created. Forgetting to call this method on every block will cause inconsistencies in the
280     /// produced functions.
seal_block(&mut self, ebb: Ebb)281     pub fn seal_block(&mut self, ebb: Ebb) {
282         let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, self.func);
283         self.handle_ssa_side_effects(side_effects);
284     }
285 
286     /// Effectively calls seal_block on all blocks in the function.
287     ///
288     /// It's more efficient to seal `Ebb`s as soon as possible, during
289     /// translation, but for frontends where this is impractical to do, this
290     /// function can be used at the end of translating all blocks to ensure
291     /// that everything is sealed.
seal_all_blocks(&mut self)292     pub fn seal_all_blocks(&mut self) {
293         let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(self.func);
294         self.handle_ssa_side_effects(side_effects);
295     }
296 
297     /// In order to use a variable in a `use_var`, you need to declare its type with this method.
declare_var(&mut self, var: Variable, ty: Type)298     pub fn declare_var(&mut self, var: Variable, ty: Type) {
299         self.func_ctx.types[var] = ty;
300     }
301 
302     /// Returns the Cranelift IR value corresponding to the utilization at the current program
303     /// position of a previously defined user variable.
use_var(&mut self, var: Variable) -> Value304     pub fn use_var(&mut self, var: Variable) -> Value {
305         let (val, side_effects) = {
306             let ty = *self.func_ctx.types.get(var).unwrap_or_else(|| {
307                 panic!(
308                     "variable {:?} is used but its type has not been declared",
309                     var
310                 )
311             });
312             self.func_ctx
313                 .ssa
314                 .use_var(self.func, var, ty, self.position.basic_block.unwrap())
315         };
316         self.handle_ssa_side_effects(side_effects);
317         val
318     }
319 
320     /// Register a new definition of a user variable. The type of the value must be
321     /// the same as the type registered for the variable.
def_var(&mut self, var: Variable, val: Value)322     pub fn def_var(&mut self, var: Variable, val: Value) {
323         debug_assert_eq!(
324             *self.func_ctx.types.get(var).unwrap_or_else(|| panic!(
325                 "variable {:?} is used but its type has not been declared",
326                 var
327             )),
328             self.func.dfg.value_type(val),
329             "declared type of variable {:?} doesn't match type of value {}",
330             var,
331             val
332         );
333 
334         self.func_ctx
335             .ssa
336             .def_var(var, val, self.position.basic_block.unwrap());
337     }
338 
339     /// Set label for Value
340     ///
341     /// This will not do anything unless `func.dfg.collect_debug_info` is called first.
set_val_label(&mut self, val: Value, label: ValueLabel)342     pub fn set_val_label(&mut self, val: Value, label: ValueLabel) {
343         if let Some(values_labels) = self.func.dfg.values_labels.as_mut() {
344             use std::collections::hash_map::Entry;
345 
346             let start = ValueLabelStart {
347                 from: self.srcloc,
348                 label,
349             };
350 
351             match values_labels.entry(val) {
352                 Entry::Occupied(mut e) => match e.get_mut() {
353                     ValueLabelAssignments::Starts(starts) => starts.push(start),
354                     _ => panic!("Unexpected ValueLabelAssignments at this stage"),
355                 },
356                 Entry::Vacant(e) => {
357                     e.insert(ValueLabelAssignments::Starts(vec![start]));
358                 }
359             }
360         }
361     }
362 
363     /// Creates a jump table in the function, to be used by `br_table` instructions.
create_jump_table(&mut self, data: JumpTableData) -> JumpTable364     pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
365         self.func.create_jump_table(data)
366     }
367 
368     /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
369     /// `stack_addr` instructions.
create_stack_slot(&mut self, data: StackSlotData) -> StackSlot370     pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
371         self.func.create_stack_slot(data)
372     }
373 
374     /// Adds a signature which can later be used to declare an external function import.
import_signature(&mut self, signature: Signature) -> SigRef375     pub fn import_signature(&mut self, signature: Signature) -> SigRef {
376         self.func.import_signature(signature)
377     }
378 
379     /// Declare an external function import.
import_function(&mut self, data: ExtFuncData) -> FuncRef380     pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
381         self.func.import_function(data)
382     }
383 
384     /// Declares a global value accessible to the function.
create_global_value(&mut self, data: GlobalValueData) -> GlobalValue385     pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue {
386         self.func.create_global_value(data)
387     }
388 
389     /// Declares a heap accessible to the function.
create_heap(&mut self, data: HeapData) -> Heap390     pub fn create_heap(&mut self, data: HeapData) -> Heap {
391         self.func.create_heap(data)
392     }
393 
394     /// Returns an object with the [`InstBuilder`](cranelift_codegen::ir::InstBuilder)
395     /// trait that allows to conveniently append an instruction to the current `Ebb` being built.
ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a>396     pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> {
397         let ebb = self
398             .position
399             .ebb
400             .expect("Please call switch_to_block before inserting instructions");
401         FuncInstBuilder::new(self, ebb)
402     }
403 
404     /// Make sure that the current EBB is inserted in the layout.
ensure_inserted_ebb(&mut self)405     pub fn ensure_inserted_ebb(&mut self) {
406         let ebb = self.position.ebb.unwrap();
407         if self.func_ctx.ebbs[ebb].pristine {
408             if !self.func.layout.is_ebb_inserted(ebb) {
409                 self.func.layout.append_ebb(ebb);
410             }
411             self.func_ctx.ebbs[ebb].pristine = false;
412         } else {
413             debug_assert!(
414                 !self.func_ctx.ebbs[ebb].filled,
415                 "you cannot add an instruction to a block already filled"
416             );
417         }
418     }
419 
420     /// Returns a `FuncCursor` pointed at the current position ready for inserting instructions.
421     ///
422     /// This can be used to insert SSA code that doesn't need to access locals and that doesn't
423     /// need to know about `FunctionBuilder` at all.
cursor(&mut self) -> FuncCursor424     pub fn cursor(&mut self) -> FuncCursor {
425         self.ensure_inserted_ebb();
426         FuncCursor::new(self.func)
427             .with_srcloc(self.srcloc)
428             .at_bottom(self.position.ebb.unwrap())
429     }
430 
431     /// Append parameters to the given `Ebb` corresponding to the function
432     /// parameters. This can be used to set up the ebb parameters for the
433     /// entry block.
append_ebb_params_for_function_params(&mut self, ebb: Ebb)434     pub fn append_ebb_params_for_function_params(&mut self, ebb: Ebb) {
435         debug_assert!(
436             !self.func_ctx.ssa.has_any_predecessors(ebb),
437             "ebb parameters for function parameters should only be added to the entry block"
438         );
439 
440         // These parameters count as "user" parameters here because they aren't
441         // inserted by the SSABuilder.
442         let user_param_count = &mut self.func_ctx.ebbs[ebb].user_param_count;
443         for argtyp in &self.func.signature.params {
444             *user_param_count += 1;
445             self.func.dfg.append_ebb_param(ebb, argtyp.value_type);
446         }
447     }
448 
449     /// Append parameters to the given `Ebb` corresponding to the function
450     /// return values. This can be used to set up the ebb parameters for a
451     /// function exit block.
append_ebb_params_for_function_returns(&mut self, ebb: Ebb)452     pub fn append_ebb_params_for_function_returns(&mut self, ebb: Ebb) {
453         // These parameters count as "user" parameters here because they aren't
454         // inserted by the SSABuilder.
455         let user_param_count = &mut self.func_ctx.ebbs[ebb].user_param_count;
456         for argtyp in &self.func.signature.returns {
457             *user_param_count += 1;
458             self.func.dfg.append_ebb_param(ebb, argtyp.value_type);
459         }
460     }
461 
462     /// Declare that translation of the current function is complete. This
463     /// resets the state of the `FunctionBuilder` in preparation to be used
464     /// for another function.
finalize(&mut self)465     pub fn finalize(&mut self) {
466         // Check that all the `Ebb`s are filled and sealed.
467         debug_assert!(
468             self.func_ctx
469                 .ebbs
470                 .iter()
471                 .all(|(ebb, ebb_data)| ebb_data.pristine || self.func_ctx.ssa.is_sealed(ebb)),
472             "all blocks should be sealed before dropping a FunctionBuilder"
473         );
474         debug_assert!(
475             self.func_ctx
476                 .ebbs
477                 .values()
478                 .all(|ebb_data| ebb_data.pristine || ebb_data.filled),
479             "all blocks should be filled before dropping a FunctionBuilder"
480         );
481 
482         // In debug mode, check that all blocks are valid basic blocks.
483         #[cfg(feature = "basic-blocks")]
484         #[cfg(debug_assertions)]
485         {
486             // Iterate manually to provide more helpful error messages.
487             for ebb in self.func_ctx.ebbs.keys() {
488                 if let Err((inst, _msg)) = self.func.is_ebb_basic(ebb) {
489                     let inst_str = self.func.dfg.display_inst(inst, None);
490                     panic!("{} failed basic block invariants on {}", ebb, inst_str);
491                 }
492             }
493         }
494 
495         // Clear the state (but preserve the allocated buffers) in preparation
496         // for translation another function.
497         self.func_ctx.clear();
498 
499         // Reset srcloc and position to initial states.
500         self.srcloc = Default::default();
501         self.position = Position::default();
502     }
503 }
504 
505 /// All the functions documented in the previous block are write-only and help you build a valid
506 /// Cranelift IR functions via multiple debug asserts. However, you might need to improve the
507 /// performance of your translation perform more complex transformations to your Cranelift IR
508 /// function. The functions below help you inspect the function you're creating and modify it
509 /// in ways that can be unsafe if used incorrectly.
510 impl<'a> FunctionBuilder<'a> {
511     /// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions
512     /// inserted that target it and the SSA construction.
ebb_params(&self, ebb: Ebb) -> &[Value]513     pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
514         self.func.dfg.ebb_params(ebb)
515     }
516 
517     /// Retrieves the signature with reference `sigref` previously added with `import_signature`.
signature(&self, sigref: SigRef) -> Option<&Signature>518     pub fn signature(&self, sigref: SigRef) -> Option<&Signature> {
519         self.func.dfg.signatures.get(sigref)
520     }
521 
522     /// Creates a parameter for a specific `Ebb` by appending it to the list of already existing
523     /// parameters.
524     ///
525     /// **Note:** this function has to be called at the creation of the `Ebb` before adding
526     /// instructions to it, otherwise this could interfere with SSA construction.
append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value527     pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
528         debug_assert!(
529             self.func_ctx.ebbs[ebb].pristine,
530             "You can't add EBB parameters after adding any instruction"
531         );
532         debug_assert_eq!(
533             self.func_ctx.ebbs[ebb].user_param_count,
534             self.func.dfg.num_ebb_params(ebb)
535         );
536         self.func_ctx.ebbs[ebb].user_param_count += 1;
537         self.func.dfg.append_ebb_param(ebb, ty)
538     }
539 
540     /// Returns the result values of an instruction.
inst_results(&self, inst: Inst) -> &[Value]541     pub fn inst_results(&self, inst: Inst) -> &[Value] {
542         self.func.dfg.inst_results(inst)
543     }
544 
545     /// Changes the destination of a jump instruction after creation.
546     ///
547     /// **Note:** You are responsible for maintaining the coherence with the arguments of
548     /// other jump instructions.
change_jump_destination(&mut self, inst: Inst, new_dest: Ebb)549     pub fn change_jump_destination(&mut self, inst: Inst, new_dest: Ebb) {
550         let old_dest = self.func.dfg[inst]
551             .branch_destination_mut()
552             .expect("you want to change the jump destination of a non-jump instruction");
553         let pred = self.func_ctx.ssa.remove_ebb_predecessor(*old_dest, inst);
554         *old_dest = new_dest;
555         self.func_ctx
556             .ssa
557             .declare_ebb_predecessor(new_dest, pred, inst);
558     }
559 
560     /// Returns `true` if and only if the current `Ebb` is sealed and has no predecessors declared.
561     ///
562     /// The entry block of a function is never unreachable.
is_unreachable(&self) -> bool563     pub fn is_unreachable(&self) -> bool {
564         let is_entry = match self.func.layout.entry_block() {
565             None => false,
566             Some(entry) => self.position.ebb.unwrap() == entry,
567         };
568         !is_entry
569             && self.func_ctx.ssa.is_sealed(self.position.ebb.unwrap())
570             && !self
571                 .func_ctx
572                 .ssa
573                 .has_any_predecessors(self.position.ebb.unwrap())
574     }
575 
576     /// Returns `true` if and only if no instructions have been added since the last call to
577     /// `switch_to_block`.
is_pristine(&self) -> bool578     pub fn is_pristine(&self) -> bool {
579         self.func_ctx.ebbs[self.position.ebb.unwrap()].pristine
580     }
581 
582     /// Returns `true` if and only if a terminator instruction has been inserted since the
583     /// last call to `switch_to_block`.
is_filled(&self) -> bool584     pub fn is_filled(&self) -> bool {
585         self.func_ctx.ebbs[self.position.ebb.unwrap()].filled
586     }
587 
588     /// Returns a displayable object for the function as it is.
589     ///
590     /// Useful for debug purposes. Use it with `None` for standard printing.
591     // Clippy thinks the lifetime that follows is needless, but rustc needs it
592     #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))]
display<'b, I: Into<Option<&'b dyn TargetIsa>>>(&'b self, isa: I) -> DisplayFunction593     pub fn display<'b, I: Into<Option<&'b dyn TargetIsa>>>(&'b self, isa: I) -> DisplayFunction {
594         self.func.display(isa)
595     }
596 }
597 
598 /// Helper functions
599 impl<'a> FunctionBuilder<'a> {
600     /// Calls libc.memcpy
601     ///
602     /// Copies the `size` bytes from `src` to `dest`, assumes that `src + size`
603     /// won't overlap onto `dest`. If `dest` and `src` overlap, the behavior is
604     /// undefined. Applications in which `dest` and `src` might overlap should
605     /// use `call_memmove` instead.
call_memcpy( &mut self, config: TargetFrontendConfig, dest: Value, src: Value, size: Value, )606     pub fn call_memcpy(
607         &mut self,
608         config: TargetFrontendConfig,
609         dest: Value,
610         src: Value,
611         size: Value,
612     ) {
613         let pointer_type = config.pointer_type();
614         let signature = {
615             let mut s = Signature::new(config.default_call_conv);
616             s.params.push(AbiParam::new(pointer_type));
617             s.params.push(AbiParam::new(pointer_type));
618             s.params.push(AbiParam::new(pointer_type));
619             self.import_signature(s)
620         };
621 
622         let libc_memcpy = self.import_function(ExtFuncData {
623             name: ExternalName::LibCall(LibCall::Memcpy),
624             signature,
625             colocated: false,
626         });
627 
628         self.ins().call(libc_memcpy, &[dest, src, size]);
629     }
630 
631     /// Optimised memcpy for small copies.
emit_small_memcpy( &mut self, config: TargetFrontendConfig, dest: Value, src: Value, size: u64, dest_align: u8, src_align: u8, )632     pub fn emit_small_memcpy(
633         &mut self,
634         config: TargetFrontendConfig,
635         dest: Value,
636         src: Value,
637         size: u64,
638         dest_align: u8,
639         src_align: u8,
640     ) {
641         // Currently the result of guess work, not actual profiling.
642         const THRESHOLD: u64 = 4;
643 
644         if size == 0 {
645             return;
646         }
647 
648         let access_size = greatest_divisible_power_of_two(size);
649         assert!(
650             access_size.is_power_of_two(),
651             "`size` is not a power of two"
652         );
653         assert!(
654             access_size >= u64::from(::core::cmp::min(src_align, dest_align)),
655             "`size` is smaller than `dest` and `src`'s alignment value."
656         );
657 
658         let (access_size, int_type) = if access_size <= 8 {
659             (access_size, Type::int((access_size * 8) as u16).unwrap())
660         } else {
661             (8, types::I64)
662         };
663 
664         let load_and_store_amount = size / access_size;
665 
666         if load_and_store_amount > THRESHOLD {
667             let size_value = self.ins().iconst(config.pointer_type(), size as i64);
668             self.call_memcpy(config, dest, src, size_value);
669             return;
670         }
671 
672         let mut flags = MemFlags::new();
673         flags.set_aligned();
674 
675         for i in 0..load_and_store_amount {
676             let offset = (access_size * i) as i32;
677             let value = self.ins().load(int_type, flags, src, offset);
678             self.ins().store(flags, value, dest, offset);
679         }
680     }
681 
682     /// Calls libc.memset
683     ///
684     /// Writes `size` bytes of i8 value `ch` to memory starting at `buffer`.
call_memset( &mut self, config: TargetFrontendConfig, buffer: Value, ch: Value, size: Value, )685     pub fn call_memset(
686         &mut self,
687         config: TargetFrontendConfig,
688         buffer: Value,
689         ch: Value,
690         size: Value,
691     ) {
692         let pointer_type = config.pointer_type();
693         let signature = {
694             let mut s = Signature::new(config.default_call_conv);
695             s.params.push(AbiParam::new(pointer_type));
696             s.params.push(AbiParam::new(types::I32));
697             s.params.push(AbiParam::new(pointer_type));
698             self.import_signature(s)
699         };
700 
701         let libc_memset = self.import_function(ExtFuncData {
702             name: ExternalName::LibCall(LibCall::Memset),
703             signature,
704             colocated: false,
705         });
706 
707         let ch = self.ins().uextend(types::I32, ch);
708         self.ins().call(libc_memset, &[buffer, ch, size]);
709     }
710 
711     /// Calls libc.memset
712     ///
713     /// Writes `size` bytes of value `ch` to memory starting at `buffer`.
emit_small_memset( &mut self, config: TargetFrontendConfig, buffer: Value, ch: u8, size: u64, buffer_align: u8, )714     pub fn emit_small_memset(
715         &mut self,
716         config: TargetFrontendConfig,
717         buffer: Value,
718         ch: u8,
719         size: u64,
720         buffer_align: u8,
721     ) {
722         // Currently the result of guess work, not actual profiling.
723         const THRESHOLD: u64 = 4;
724 
725         if size == 0 {
726             return;
727         }
728 
729         let access_size = greatest_divisible_power_of_two(size);
730         assert!(
731             access_size.is_power_of_two(),
732             "`size` is not a power of two"
733         );
734         assert!(
735             access_size >= u64::from(buffer_align),
736             "`size` is smaller than `dest` and `src`'s alignment value."
737         );
738 
739         let (access_size, int_type) = if access_size <= 8 {
740             (access_size, Type::int((access_size * 8) as u16).unwrap())
741         } else {
742             (8, types::I64)
743         };
744 
745         let load_and_store_amount = size / access_size;
746 
747         if load_and_store_amount > THRESHOLD {
748             let ch = self.ins().iconst(types::I8, i64::from(ch));
749             let size = self.ins().iconst(config.pointer_type(), size as i64);
750             self.call_memset(config, buffer, ch, size);
751         } else {
752             let mut flags = MemFlags::new();
753             flags.set_aligned();
754 
755             let ch = u64::from(ch);
756             let raw_value = if int_type == types::I64 {
757                 (ch << 32) | (ch << 16) | (ch << 8) | ch
758             } else if int_type == types::I32 {
759                 (ch << 16) | (ch << 8) | ch
760             } else if int_type == types::I16 {
761                 (ch << 8) | ch
762             } else {
763                 assert_eq!(int_type, types::I8);
764                 ch
765             };
766 
767             let value = self.ins().iconst(int_type, raw_value as i64);
768             for i in 0..load_and_store_amount {
769                 let offset = (access_size * i) as i32;
770                 self.ins().store(flags, value, buffer, offset);
771             }
772         }
773     }
774 
775     /// Calls libc.memmove
776     ///
777     /// Copies `size` bytes from memory starting at `source` to memory starting
778     /// at `dest`. `source` is always read before writing to `dest`.
call_memmove( &mut self, config: TargetFrontendConfig, dest: Value, source: Value, size: Value, )779     pub fn call_memmove(
780         &mut self,
781         config: TargetFrontendConfig,
782         dest: Value,
783         source: Value,
784         size: Value,
785     ) {
786         let pointer_type = config.pointer_type();
787         let signature = {
788             let mut s = Signature::new(config.default_call_conv);
789             s.params.push(AbiParam::new(pointer_type));
790             s.params.push(AbiParam::new(pointer_type));
791             s.params.push(AbiParam::new(pointer_type));
792             self.import_signature(s)
793         };
794 
795         let libc_memmove = self.import_function(ExtFuncData {
796             name: ExternalName::LibCall(LibCall::Memmove),
797             signature,
798             colocated: false,
799         });
800 
801         self.ins().call(libc_memmove, &[dest, source, size]);
802     }
803 
804     /// Optimised memmove for small moves.
emit_small_memmove( &mut self, config: TargetFrontendConfig, dest: Value, src: Value, size: u64, dest_align: u8, src_align: u8, )805     pub fn emit_small_memmove(
806         &mut self,
807         config: TargetFrontendConfig,
808         dest: Value,
809         src: Value,
810         size: u64,
811         dest_align: u8,
812         src_align: u8,
813     ) {
814         // Currently the result of guess work, not actual profiling.
815         const THRESHOLD: u64 = 4;
816 
817         let access_size = greatest_divisible_power_of_two(size);
818         assert!(
819             access_size.is_power_of_two(),
820             "`size` is not a power of two"
821         );
822         assert!(
823             access_size >= u64::from(::core::cmp::min(src_align, dest_align)),
824             "`size` is smaller than `dest` and `src`'s alignment value."
825         );
826         let load_and_store_amount = size / access_size;
827 
828         if load_and_store_amount > THRESHOLD {
829             let size_value = self.ins().iconst(config.pointer_type(), size as i64);
830             self.call_memmove(config, dest, src, size_value);
831             return;
832         }
833 
834         let mut flags = MemFlags::new();
835         flags.set_aligned();
836 
837         // Load all of the memory first in case `dest` overlaps.
838         let registers: Vec<_> = (0..load_and_store_amount)
839             .map(|i| {
840                 let offset = (access_size * i) as i32;
841                 (
842                     self.ins().load(config.pointer_type(), flags, src, offset),
843                     offset,
844                 )
845             })
846             .collect();
847 
848         for (value, offset) in registers {
849             self.ins().store(flags, value, dest, offset);
850         }
851     }
852 }
853 
greatest_divisible_power_of_two(size: u64) -> u64854 fn greatest_divisible_power_of_two(size: u64) -> u64 {
855     (size as i64 & -(size as i64)) as u64
856 }
857 
858 // Helper functions
859 impl<'a> FunctionBuilder<'a> {
move_to_next_basic_block(&mut self)860     fn move_to_next_basic_block(&mut self) {
861         self.position.basic_block = PackedOption::from(
862             self.func_ctx
863                 .ssa
864                 .declare_ebb_body_block(self.position.basic_block.unwrap()),
865         );
866     }
867 
868     /// An Ebb is 'filled' when a terminator instruction is present.
fill_current_block(&mut self)869     fn fill_current_block(&mut self) {
870         self.func_ctx.ebbs[self.position.ebb.unwrap()].filled = true;
871     }
872 
declare_successor(&mut self, dest_ebb: Ebb, jump_inst: Inst)873     fn declare_successor(&mut self, dest_ebb: Ebb, jump_inst: Inst) {
874         self.func_ctx.ssa.declare_ebb_predecessor(
875             dest_ebb,
876             self.position.basic_block.unwrap(),
877             jump_inst,
878         );
879     }
880 
handle_ssa_side_effects(&mut self, side_effects: SideEffects)881     fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) {
882         for split_ebb in side_effects.split_ebbs_created {
883             self.func_ctx.ebbs[split_ebb].filled = true
884         }
885         for modified_ebb in side_effects.instructions_added_to_ebbs {
886             self.func_ctx.ebbs[modified_ebb].pristine = false
887         }
888     }
889 }
890 
891 #[cfg(test)]
892 mod tests {
893     use super::greatest_divisible_power_of_two;
894     use crate::frontend::{FunctionBuilder, FunctionBuilderContext};
895     use crate::Variable;
896     use cranelift_codegen::entity::EntityRef;
897     use cranelift_codegen::ir::types::*;
898     use cranelift_codegen::ir::{AbiParam, ExternalName, Function, InstBuilder, Signature};
899     use cranelift_codegen::isa::CallConv;
900     use cranelift_codegen::settings;
901     use cranelift_codegen::verifier::verify_function;
902     use std::string::ToString;
903 
sample_function(lazy_seal: bool)904     fn sample_function(lazy_seal: bool) {
905         let mut sig = Signature::new(CallConv::SystemV);
906         sig.returns.push(AbiParam::new(I32));
907         sig.params.push(AbiParam::new(I32));
908 
909         let mut fn_ctx = FunctionBuilderContext::new();
910         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
911         {
912             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
913 
914             let block0 = builder.create_ebb();
915             let block1 = builder.create_ebb();
916             let block2 = builder.create_ebb();
917             let block3 = builder.create_ebb();
918             let x = Variable::new(0);
919             let y = Variable::new(1);
920             let z = Variable::new(2);
921             builder.declare_var(x, I32);
922             builder.declare_var(y, I32);
923             builder.declare_var(z, I32);
924             builder.append_ebb_params_for_function_params(block0);
925 
926             builder.switch_to_block(block0);
927             if !lazy_seal {
928                 builder.seal_block(block0);
929             }
930             {
931                 let tmp = builder.ebb_params(block0)[0]; // the first function parameter
932                 builder.def_var(x, tmp);
933             }
934             {
935                 let tmp = builder.ins().iconst(I32, 2);
936                 builder.def_var(y, tmp);
937             }
938             {
939                 let arg1 = builder.use_var(x);
940                 let arg2 = builder.use_var(y);
941                 let tmp = builder.ins().iadd(arg1, arg2);
942                 builder.def_var(z, tmp);
943             }
944             builder.ins().jump(block1, &[]);
945 
946             builder.switch_to_block(block1);
947             {
948                 let arg1 = builder.use_var(y);
949                 let arg2 = builder.use_var(z);
950                 let tmp = builder.ins().iadd(arg1, arg2);
951                 builder.def_var(z, tmp);
952             }
953             {
954                 let arg = builder.use_var(y);
955                 builder.ins().brnz(arg, block3, &[]);
956             }
957             builder.ins().jump(block2, &[]);
958 
959             builder.switch_to_block(block2);
960             if !lazy_seal {
961                 builder.seal_block(block2);
962             }
963             {
964                 let arg1 = builder.use_var(z);
965                 let arg2 = builder.use_var(x);
966                 let tmp = builder.ins().isub(arg1, arg2);
967                 builder.def_var(z, tmp);
968             }
969             {
970                 let arg = builder.use_var(y);
971                 builder.ins().return_(&[arg]);
972             }
973 
974             builder.switch_to_block(block3);
975             if !lazy_seal {
976                 builder.seal_block(block3);
977             }
978 
979             {
980                 let arg1 = builder.use_var(y);
981                 let arg2 = builder.use_var(x);
982                 let tmp = builder.ins().isub(arg1, arg2);
983                 builder.def_var(y, tmp);
984             }
985             builder.ins().jump(block1, &[]);
986             if !lazy_seal {
987                 builder.seal_block(block1);
988             }
989 
990             if lazy_seal {
991                 builder.seal_all_blocks();
992             }
993 
994             builder.finalize();
995         }
996 
997         let flags = settings::Flags::new(settings::builder());
998         // println!("{}", func.display(None));
999         if let Err(errors) = verify_function(&func, &flags) {
1000             panic!("{}\n{}", func.display(None), errors)
1001         }
1002     }
1003 
1004     #[test]
sample()1005     fn sample() {
1006         sample_function(false)
1007     }
1008 
1009     #[test]
sample_with_lazy_seal()1010     fn sample_with_lazy_seal() {
1011         sample_function(true)
1012     }
1013 
1014     #[test]
memcpy()1015     fn memcpy() {
1016         use core::str::FromStr;
1017         use cranelift_codegen::{isa, settings};
1018 
1019         let shared_builder = settings::builder();
1020         let shared_flags = settings::Flags::new(shared_builder);
1021 
1022         let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1023 
1024         let target = isa::lookup(triple)
1025             .ok()
1026             .map(|b| b.finish(shared_flags))
1027             .expect("This test requires arm support.");
1028 
1029         let mut sig = Signature::new(target.default_call_conv());
1030         sig.returns.push(AbiParam::new(I32));
1031 
1032         let mut fn_ctx = FunctionBuilderContext::new();
1033         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1034         {
1035             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
1036 
1037             let block0 = builder.create_ebb();
1038             let x = Variable::new(0);
1039             let y = Variable::new(1);
1040             let z = Variable::new(2);
1041             builder.declare_var(x, target.pointer_type());
1042             builder.declare_var(y, target.pointer_type());
1043             builder.declare_var(z, I32);
1044             builder.append_ebb_params_for_function_params(block0);
1045             builder.switch_to_block(block0);
1046 
1047             let src = builder.use_var(x);
1048             let dest = builder.use_var(y);
1049             let size = builder.use_var(y);
1050             builder.call_memcpy(target.frontend_config(), dest, src, size);
1051             builder.ins().return_(&[size]);
1052 
1053             builder.seal_all_blocks();
1054             builder.finalize();
1055         }
1056 
1057         assert_eq!(
1058             func.display(None).to_string(),
1059             "function %sample() -> i32 system_v {
1060     sig0 = (i32, i32, i32) system_v
1061     fn0 = %Memcpy sig0
1062 
1063 ebb0:
1064     v3 = iconst.i32 0
1065     v1 -> v3
1066     v2 = iconst.i32 0
1067     v0 -> v2
1068     call fn0(v1, v0, v1)
1069     return v1
1070 }
1071 "
1072         );
1073     }
1074 
1075     #[test]
small_memcpy()1076     fn small_memcpy() {
1077         use core::str::FromStr;
1078         use cranelift_codegen::{isa, settings};
1079 
1080         let shared_builder = settings::builder();
1081         let shared_flags = settings::Flags::new(shared_builder);
1082 
1083         let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1084 
1085         let target = isa::lookup(triple)
1086             .ok()
1087             .map(|b| b.finish(shared_flags))
1088             .expect("This test requires arm support.");
1089 
1090         let mut sig = Signature::new(target.default_call_conv());
1091         sig.returns.push(AbiParam::new(I32));
1092 
1093         let mut fn_ctx = FunctionBuilderContext::new();
1094         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1095         {
1096             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
1097 
1098             let block0 = builder.create_ebb();
1099             let x = Variable::new(0);
1100             let y = Variable::new(16);
1101             builder.declare_var(x, target.pointer_type());
1102             builder.declare_var(y, target.pointer_type());
1103             builder.append_ebb_params_for_function_params(block0);
1104             builder.switch_to_block(block0);
1105 
1106             let src = builder.use_var(x);
1107             let dest = builder.use_var(y);
1108             let size = 8;
1109             builder.emit_small_memcpy(target.frontend_config(), dest, src, size, 8, 8);
1110             builder.ins().return_(&[dest]);
1111 
1112             builder.seal_all_blocks();
1113             builder.finalize();
1114         }
1115 
1116         assert_eq!(
1117             func.display(None).to_string(),
1118             "function %sample() -> i32 system_v {
1119 ebb0:
1120     v4 = iconst.i32 0
1121     v1 -> v4
1122     v3 = iconst.i32 0
1123     v0 -> v3
1124     v2 = load.i64 aligned v0
1125     store aligned v2, v1
1126     return v1
1127 }
1128 "
1129         );
1130     }
1131 
1132     #[test]
not_so_small_memcpy()1133     fn not_so_small_memcpy() {
1134         use core::str::FromStr;
1135         use cranelift_codegen::{isa, settings};
1136 
1137         let shared_builder = settings::builder();
1138         let shared_flags = settings::Flags::new(shared_builder);
1139 
1140         let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1141 
1142         let target = isa::lookup(triple)
1143             .ok()
1144             .map(|b| b.finish(shared_flags))
1145             .expect("This test requires arm support.");
1146 
1147         let mut sig = Signature::new(target.default_call_conv());
1148         sig.returns.push(AbiParam::new(I32));
1149 
1150         let mut fn_ctx = FunctionBuilderContext::new();
1151         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1152         {
1153             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
1154 
1155             let block0 = builder.create_ebb();
1156             let x = Variable::new(0);
1157             let y = Variable::new(16);
1158             builder.declare_var(x, target.pointer_type());
1159             builder.declare_var(y, target.pointer_type());
1160             builder.append_ebb_params_for_function_params(block0);
1161             builder.switch_to_block(block0);
1162 
1163             let src = builder.use_var(x);
1164             let dest = builder.use_var(y);
1165             let size = 8192;
1166             builder.emit_small_memcpy(target.frontend_config(), dest, src, size, 8, 8);
1167             builder.ins().return_(&[dest]);
1168 
1169             builder.seal_all_blocks();
1170             builder.finalize();
1171         }
1172 
1173         assert_eq!(
1174             func.display(None).to_string(),
1175             "function %sample() -> i32 system_v {
1176     sig0 = (i32, i32, i32) system_v
1177     fn0 = %Memcpy sig0
1178 
1179 ebb0:
1180     v4 = iconst.i32 0
1181     v1 -> v4
1182     v3 = iconst.i32 0
1183     v0 -> v3
1184     v2 = iconst.i32 8192
1185     call fn0(v1, v0, v2)
1186     return v1
1187 }
1188 "
1189         );
1190     }
1191 
1192     #[test]
small_memset()1193     fn small_memset() {
1194         use core::str::FromStr;
1195         use cranelift_codegen::{isa, settings};
1196 
1197         let shared_builder = settings::builder();
1198         let shared_flags = settings::Flags::new(shared_builder);
1199 
1200         let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1201 
1202         let target = isa::lookup(triple)
1203             .ok()
1204             .map(|b| b.finish(shared_flags))
1205             .expect("This test requires arm support.");
1206 
1207         let mut sig = Signature::new(target.default_call_conv());
1208         sig.returns.push(AbiParam::new(I32));
1209 
1210         let mut fn_ctx = FunctionBuilderContext::new();
1211         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1212         {
1213             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
1214 
1215             let block0 = builder.create_ebb();
1216             let y = Variable::new(16);
1217             builder.declare_var(y, target.pointer_type());
1218             builder.append_ebb_params_for_function_params(block0);
1219             builder.switch_to_block(block0);
1220 
1221             let dest = builder.use_var(y);
1222             let size = 8;
1223             builder.emit_small_memset(target.frontend_config(), dest, 1, size, 8);
1224             builder.ins().return_(&[dest]);
1225 
1226             builder.seal_all_blocks();
1227             builder.finalize();
1228         }
1229 
1230         assert_eq!(
1231             func.display(None).to_string(),
1232             "function %sample() -> i32 system_v {
1233 ebb0:
1234     v2 = iconst.i32 0
1235     v0 -> v2
1236     v1 = iconst.i64 0x0001_0001_0101
1237     store aligned v1, v0
1238     return v0
1239 }
1240 "
1241         );
1242     }
1243 
1244     #[test]
not_so_small_memset()1245     fn not_so_small_memset() {
1246         use core::str::FromStr;
1247         use cranelift_codegen::{isa, settings};
1248 
1249         let shared_builder = settings::builder();
1250         let shared_flags = settings::Flags::new(shared_builder);
1251 
1252         let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
1253 
1254         let target = isa::lookup(triple)
1255             .ok()
1256             .map(|b| b.finish(shared_flags))
1257             .expect("This test requires arm support.");
1258 
1259         let mut sig = Signature::new(target.default_call_conv());
1260         sig.returns.push(AbiParam::new(I32));
1261 
1262         let mut fn_ctx = FunctionBuilderContext::new();
1263         let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
1264         {
1265             let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
1266 
1267             let block0 = builder.create_ebb();
1268             let y = Variable::new(16);
1269             builder.declare_var(y, target.pointer_type());
1270             builder.append_ebb_params_for_function_params(block0);
1271             builder.switch_to_block(block0);
1272 
1273             let dest = builder.use_var(y);
1274             let size = 8192;
1275             builder.emit_small_memset(target.frontend_config(), dest, 1, size, 8);
1276             builder.ins().return_(&[dest]);
1277 
1278             builder.seal_all_blocks();
1279             builder.finalize();
1280         }
1281 
1282         assert_eq!(
1283             func.display(None).to_string(),
1284             "function %sample() -> i32 system_v {
1285     sig0 = (i32, i32, i32) system_v
1286     fn0 = %Memset sig0
1287 
1288 ebb0:
1289     v4 = iconst.i32 0
1290     v0 -> v4
1291     v1 = iconst.i8 1
1292     v2 = iconst.i32 8192
1293     v3 = uextend.i32 v1
1294     call fn0(v0, v3, v2)
1295     return v0
1296 }
1297 "
1298         );
1299     }
1300 
1301     #[test]
test_greatest_divisible_power_of_two()1302     fn test_greatest_divisible_power_of_two() {
1303         assert_eq!(64, greatest_divisible_power_of_two(64));
1304         assert_eq!(16, greatest_divisible_power_of_two(48));
1305         assert_eq!(8, greatest_divisible_power_of_two(24));
1306         assert_eq!(1, greatest_divisible_power_of_two(25));
1307     }
1308 }
1309