1 //! This implements the VCode container: a CFG of Insts that have been lowered.
2 //!
3 //! VCode is virtual-register code. An instruction in VCode is almost a machine
4 //! instruction; however, its register slots can refer to virtual registers in
5 //! addition to real machine registers.
6 //!
7 //! VCode is structured with traditional basic blocks, and
8 //! each block must be terminated by an unconditional branch (one target), a
9 //! conditional branch (two targets), or a return (no targets). Note that this
10 //! slightly differs from the machine code of most ISAs: in most ISAs, a
11 //! conditional branch has one target (and the not-taken case falls through).
12 //! However, we expect that machine backends will elide branches to the following
13 //! block (i.e., zero-offset jumps), and will be able to codegen a branch-cond /
14 //! branch-uncond pair if *both* targets are not fallthrough. This allows us to
15 //! play with layout prior to final binary emission, as well, if we want.
16 //!
17 //! See the main module comment in `mod.rs` for more details on the VCode-based
18 //! backend pipeline.
19 
20 use crate::fx::FxHashMap;
21 use crate::fx::FxHashSet;
22 use crate::ir::RelSourceLoc;
23 use crate::ir::{self, types, Constant, ConstantData, DynamicStackSlot, ValueLabel};
24 use crate::machinst::*;
25 use crate::timing;
26 use crate::trace;
27 use crate::CodegenError;
28 use crate::{LabelValueLoc, ValueLocRange};
29 use cranelift_control::ControlPlane;
30 use regalloc2::{
31     Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PRegSet,
32     RegClass, VReg,
33 };
34 
35 use alloc::vec::Vec;
36 use cranelift_entity::{entity_impl, Keys, PrimaryMap};
37 use std::collections::hash_map::Entry;
38 use std::collections::HashMap;
39 use std::fmt;
40 
41 /// Index referring to an instruction in VCode.
42 pub type InsnIndex = regalloc2::Inst;
43 
44 /// Index referring to a basic block in VCode.
45 pub type BlockIndex = regalloc2::Block;
46 
47 /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
48 /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
49 pub trait VCodeInst: MachInst + MachInstEmit {}
50 impl<I: MachInst + MachInstEmit> VCodeInst for I {}
51 
52 /// A function in "VCode" (virtualized-register code) form, after
53 /// lowering.  This is essentially a standard CFG of basic blocks,
54 /// where each basic block consists of lowered instructions produced
55 /// by the machine-specific backend.
56 ///
57 /// Note that the VCode is immutable once produced, and is not
58 /// modified by register allocation in particular. Rather, register
59 /// allocation on the `VCode` produces a separate `regalloc2::Output`
60 /// struct, and this can be passed to `emit`. `emit` in turn does not
61 /// modify the vcode, but produces an `EmitResult`, which contains the
62 /// machine code itself, and the associated disassembly and/or
63 /// metadata as requested.
64 pub struct VCode<I: VCodeInst> {
65     /// VReg IR-level types.
66     vreg_types: Vec<Type>,
67 
68     /// Lowered machine instructions in order corresponding to the original IR.
69     insts: Vec<I>,
70 
71     /// Operands: pre-regalloc references to virtual registers with
72     /// constraints, in one flattened array. This allows the regalloc
73     /// to efficiently access all operands without requiring expensive
74     /// matches or method invocations on insts.
75     operands: Vec<Operand>,
76 
77     /// Operand index ranges: for each instruction in `insts`, there
78     /// is a tuple here providing the range in `operands` for that
79     /// instruction's operands.
80     operand_ranges: Vec<(u32, u32)>,
81 
82     /// Clobbers: a sparse map from instruction indices to clobber masks.
83     clobbers: FxHashMap<InsnIndex, PRegSet>,
84 
85     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
86     /// reasonable to keep one of these per instruction.)
87     srclocs: Vec<RelSourceLoc>,
88 
89     /// Entry block.
90     entry: BlockIndex,
91 
92     /// Block instruction indices.
93     block_ranges: Vec<(InsnIndex, InsnIndex)>,
94 
95     /// Block successors: index range in the `block_succs_preds` list.
96     block_succ_range: Vec<(u32, u32)>,
97 
98     /// Block predecessors: index range in the `block_succs_preds` list.
99     block_pred_range: Vec<(u32, u32)>,
100 
101     /// Block successor and predecessor lists, concatenated into one
102     /// Vec. The `block_succ_range` and `block_pred_range` lists of
103     /// tuples above give (start, end) ranges within this list that
104     /// correspond to each basic block's successors or predecessors,
105     /// respectively.
106     block_succs_preds: Vec<regalloc2::Block>,
107 
108     /// Block parameters: index range in `block_params` below.
109     block_params_range: Vec<(u32, u32)>,
110 
111     /// Block parameter lists, concatenated into one vec. The
112     /// `block_params_range` list of tuples above gives (start, end)
113     /// ranges within this list that correspond to each basic block's
114     /// blockparam vregs.
115     block_params: Vec<regalloc2::VReg>,
116 
117     /// Outgoing block arguments on branch instructions, concatenated
118     /// into one list.
119     ///
120     /// Note that this is conceptually a 3D array: we have a VReg list
121     /// per block, per successor. We flatten those three dimensions
122     /// into this 1D vec, then store index ranges in two levels of
123     /// indirection.
124     ///
125     /// Indexed by the indices in `branch_block_arg_succ_range`.
126     branch_block_args: Vec<regalloc2::VReg>,
127 
128     /// Array of sequences of (start, end) tuples in
129     /// `branch_block_args`, one for each successor; these sequences
130     /// for each block are concatenated.
131     ///
132     /// Indexed by the indices in `branch_block_arg_succ_range`.
133     branch_block_arg_range: Vec<(u32, u32)>,
134 
135     /// For a given block, indices in `branch_block_arg_range`
136     /// corresponding to all of its successors.
137     branch_block_arg_succ_range: Vec<(u32, u32)>,
138 
139     /// VReg aliases. Each key in this table is translated to its
140     /// value when gathering Operands from instructions. Aliases are
141     /// not chased transitively (we do not further look up the
142     /// translated reg to see if it is another alias).
143     ///
144     /// We use these aliases to rename an instruction's expected
145     /// result vregs to the returned vregs from lowering, which are
146     /// usually freshly-allocated temps.
147     ///
148     /// Operands and branch arguments will already have been
149     /// translated through this alias table; but it helps to make
150     /// sense of instructions when pretty-printed, for example.
151     vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>,
152 
153     /// Block-order information.
154     block_order: BlockLoweringOrder,
155 
156     /// ABI object.
157     pub(crate) abi: Callee<I::ABIMachineSpec>,
158 
159     /// Constant information used during code emission. This should be
160     /// immutable across function compilations within the same module.
161     emit_info: I::Info,
162 
163     /// Reference-typed `regalloc2::VReg`s. The regalloc requires
164     /// these in a dense slice (as opposed to querying the
165     /// reftype-status of each vreg) for efficient iteration.
166     reftyped_vregs: Vec<VReg>,
167 
168     /// Constants.
169     constants: VCodeConstants,
170 
171     /// Value labels for debuginfo attached to vregs.
172     debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>,
173 
174     pub(crate) sigs: SigSet,
175 }
176 
177 /// The result of `VCode::emit`. Contains all information computed
178 /// during emission: actual machine code, optionally a disassembly,
179 /// and optionally metadata about the code layout.
180 pub struct EmitResult {
181     /// The MachBuffer containing the machine code.
182     pub buffer: MachBufferFinalized<Stencil>,
183 
184     /// Offset of each basic block, recorded during emission. Computed
185     /// only if `debug_value_labels` is non-empty.
186     pub bb_offsets: Vec<CodeOffset>,
187 
188     /// Final basic-block edges, in terms of code offsets of
189     /// bb-starts. Computed only if `debug_value_labels` is non-empty.
190     pub bb_edges: Vec<(CodeOffset, CodeOffset)>,
191 
192     /// Final instruction offsets, recorded during emission. Computed
193     /// only if `debug_value_labels` is non-empty.
194     pub inst_offsets: Vec<CodeOffset>,
195 
196     /// Final length of function body.
197     pub func_body_len: CodeOffset,
198 
199     /// The pretty-printed disassembly, if any. This uses the same
200     /// pretty-printing for MachInsts as the pre-regalloc VCode Debug
201     /// implementation, but additionally includes the prologue and
202     /// epilogue(s), and makes use of the regalloc results.
203     pub disasm: Option<String>,
204 
205     /// Offsets of sized stackslots.
206     pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>,
207 
208     /// Offsets of dynamic stackslots.
209     pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>,
210 
211     /// Value-labels information (debug metadata).
212     pub value_labels_ranges: ValueLabelsRanges,
213 
214     /// Stack frame size.
215     pub frame_size: u32,
216 }
217 
218 /// A builder for a VCode function body.
219 ///
220 /// This builder has the ability to accept instructions in either
221 /// forward or reverse order, depending on the pass direction that
222 /// produces the VCode. The lowering from CLIF to VCode<MachInst>
223 /// ordinarily occurs in reverse order (in order to allow instructions
224 /// to be lowered only if used, and not merged) so a reversal will
225 /// occur at the end of lowering to ensure the VCode is in machine
226 /// order.
227 ///
228 /// If built in reverse, block and instruction indices used once the
229 /// VCode is built are relative to the final (reversed) order, not the
230 /// order of construction. Note that this means we do not know the
231 /// final block or instruction indices when building, so we do not
232 /// hand them out. (The user is assumed to know them when appending
233 /// terminator instructions with successor blocks.)
234 pub struct VCodeBuilder<I: VCodeInst> {
235     /// In-progress VCode.
236     pub(crate) vcode: VCode<I>,
237 
238     /// In what direction is the build occuring?
239     direction: VCodeBuildDirection,
240 
241     /// Index of the last block-start in the vcode.
242     block_start: usize,
243 
244     /// Start of succs for the current block in the concatenated succs list.
245     succ_start: usize,
246 
247     /// Start of blockparams for the current block in the concatenated
248     /// blockparams list.
249     block_params_start: usize,
250 
251     /// Start of successor blockparam arg list entries in
252     /// the concatenated branch_block_arg_range list.
253     branch_block_arg_succ_start: usize,
254 
255     /// Current source location.
256     cur_srcloc: RelSourceLoc,
257 
258     /// Debug-value label in-progress map, keyed by label. For each
259     /// label, we keep disjoint ranges mapping to vregs. We'll flatten
260     /// this into (vreg, range, label) tuples when done.
261     debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>,
262 }
263 
264 /// Direction in which a VCodeBuilder builds VCode.
265 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
266 pub enum VCodeBuildDirection {
267     // TODO: add `Forward` once we need it and can test it adequately.
268     /// Backward-build pass: we expect the producer to call `emit()`
269     /// with instructions in reverse program order within each block.
270     Backward,
271 }
272 
273 impl<I: VCodeInst> VCodeBuilder<I> {
274     /// Create a new VCodeBuilder.
275     pub fn new(
276         sigs: SigSet,
277         abi: Callee<I::ABIMachineSpec>,
278         emit_info: I::Info,
279         block_order: BlockLoweringOrder,
280         constants: VCodeConstants,
281         direction: VCodeBuildDirection,
282     ) -> VCodeBuilder<I> {
283         let vcode = VCode::new(sigs, abi, emit_info, block_order, constants);
284 
285         VCodeBuilder {
286             vcode,
287             direction,
288             block_start: 0,
289             succ_start: 0,
290             block_params_start: 0,
291             branch_block_arg_succ_start: 0,
292             cur_srcloc: Default::default(),
293             debug_info: FxHashMap::default(),
294         }
295     }
296 
297     pub fn init_abi(&mut self, temps: Vec<Writable<Reg>>) {
298         self.vcode.abi.init(&self.vcode.sigs, temps);
299     }
300 
301     /// Access the ABI object.
302     pub fn abi(&self) -> &Callee<I::ABIMachineSpec> {
303         &self.vcode.abi
304     }
305 
306     /// Access the ABI object.
307     pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> {
308         &mut self.vcode.abi
309     }
310 
311     pub fn sigs(&self) -> &SigSet {
312         &self.vcode.sigs
313     }
314 
315     pub fn sigs_mut(&mut self) -> &mut SigSet {
316         &mut self.vcode.sigs
317     }
318 
319     /// Access to the BlockLoweringOrder object.
320     pub fn block_order(&self) -> &BlockLoweringOrder {
321         &self.vcode.block_order
322     }
323 
324     /// Set the current block as the entry block.
325     pub fn set_entry(&mut self, block: BlockIndex) {
326         self.vcode.entry = block;
327     }
328 
329     /// End the current basic block. Must be called after emitting vcode insts
330     /// for IR insts and prior to ending the function (building the VCode).
331     pub fn end_bb(&mut self) {
332         let start_idx = self.block_start;
333         let end_idx = self.vcode.insts.len();
334         self.block_start = end_idx;
335         // Add the instruction index range to the list of blocks.
336         self.vcode
337             .block_ranges
338             .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx)));
339         // End the successors list.
340         let succ_end = self.vcode.block_succs_preds.len();
341         self.vcode
342             .block_succ_range
343             .push((self.succ_start as u32, succ_end as u32));
344         self.succ_start = succ_end;
345         // End the blockparams list.
346         let block_params_end = self.vcode.block_params.len();
347         self.vcode
348             .block_params_range
349             .push((self.block_params_start as u32, block_params_end as u32));
350         self.block_params_start = block_params_end;
351         // End the branch blockparam args list.
352         let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len();
353         self.vcode.branch_block_arg_succ_range.push((
354             self.branch_block_arg_succ_start as u32,
355             branch_block_arg_succ_end as u32,
356         ));
357         self.branch_block_arg_succ_start = branch_block_arg_succ_end;
358     }
359 
360     pub fn add_block_param(&mut self, param: VirtualReg) {
361         self.vcode.block_params.push(param.into());
362     }
363 
364     fn add_branch_args_for_succ(&mut self, args: &[Reg]) {
365         let start = self.vcode.branch_block_args.len();
366         self.vcode
367             .branch_block_args
368             .extend(args.iter().map(|&arg| VReg::from(arg)));
369         let end = self.vcode.branch_block_args.len();
370         self.vcode
371             .branch_block_arg_range
372             .push((start as u32, end as u32));
373     }
374 
375     /// Push an instruction for the current BB and current IR inst
376     /// within the BB.
377     pub fn push(&mut self, insn: I) {
378         self.vcode.insts.push(insn);
379         self.vcode.srclocs.push(self.cur_srcloc);
380     }
381 
382     /// Add a successor block with branch args.
383     pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) {
384         self.vcode.block_succs_preds.push(block);
385         self.add_branch_args_for_succ(args);
386     }
387 
388     /// Set the current source location.
389     pub fn set_srcloc(&mut self, srcloc: RelSourceLoc) {
390         self.cur_srcloc = srcloc;
391     }
392 
393     /// Add a debug value label to a register.
394     pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) {
395         // We'll fix up labels in reverse(). Because we're generating
396         // code bottom-to-top, the liverange of the label goes *from*
397         // the last index at which was defined (or 0, which is the end
398         // of the eventual function) *to* just this instruction, and
399         // no further.
400         let inst = InsnIndex::new(self.vcode.insts.len());
401         let labels = self.debug_info.entry(label).or_insert_with(|| vec![]);
402         let last = labels
403             .last()
404             .map(|(_start, end, _vreg)| *end)
405             .unwrap_or(InsnIndex::new(0));
406         labels.push((last, inst, reg.into()));
407     }
408 
409     pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) {
410         let from = from.into();
411         let resolved_to = self.resolve_vreg_alias(to.into());
412         // Disallow cycles (see below).
413         assert_ne!(resolved_to, from);
414         self.vcode.vreg_aliases.insert(from, resolved_to);
415     }
416 
417     pub fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg {
418         Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, from)
419     }
420 
421     fn resolve_vreg_alias_impl(
422         aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>,
423         from: regalloc2::VReg,
424     ) -> regalloc2::VReg {
425         // We prevent cycles from existing by resolving targets of
426         // aliases eagerly before setting them. If the target resolves
427         // to the origin of the alias, then a cycle would be created
428         // and the alias is disallowed. Because of the structure of
429         // SSA code (one instruction can refer to another's defs but
430         // not vice-versa, except indirectly through
431         // phis/blockparams), cycles should not occur as we use
432         // aliases to redirect vregs to the temps that actually define
433         // them.
434 
435         let mut vreg = from;
436         while let Some(to) = aliases.get(&vreg) {
437             vreg = *to;
438         }
439         vreg
440     }
441 
442     /// Access the constants.
443     pub fn constants(&mut self) -> &mut VCodeConstants {
444         &mut self.vcode.constants
445     }
446 
447     fn compute_preds_from_succs(&mut self) {
448         // Compute predecessors from successors. In order to gather
449         // all preds for a block into a contiguous sequence, we build
450         // a list of (succ, pred) tuples and then sort.
451         let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> =
452             Vec::with_capacity(self.vcode.block_succs_preds.len());
453         for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() {
454             let pred = BlockIndex::new(pred);
455             for i in start..end {
456                 let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index());
457                 succ_pred_edges.push((succ, pred));
458             }
459         }
460         succ_pred_edges.sort_unstable();
461 
462         let mut i = 0;
463         for succ in 0..self.vcode.num_blocks() {
464             let succ = BlockIndex::new(succ);
465             let start = self.vcode.block_succs_preds.len();
466             while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ {
467                 let pred = succ_pred_edges[i].1;
468                 self.vcode.block_succs_preds.push(pred);
469                 i += 1;
470             }
471             let end = self.vcode.block_succs_preds.len();
472             self.vcode.block_pred_range.push((start as u32, end as u32));
473         }
474     }
475 
476     /// Called once, when a build in Backward order is complete, to
477     /// perform the overall reversal (into final forward order) and
478     /// finalize metadata accordingly.
479     fn reverse_and_finalize(&mut self) {
480         let n_insts = self.vcode.insts.len();
481         if n_insts == 0 {
482             return;
483         }
484 
485         // Reverse the per-block and per-inst sequences.
486         self.vcode.block_ranges.reverse();
487         // block_params_range is indexed by block (and blocks were
488         // traversed in reverse) so we reverse it; but block-param
489         // sequences in the concatenated vec can remain in reverse
490         // order (it is effectively an arena of arbitrarily-placed
491         // referenced sequences).
492         self.vcode.block_params_range.reverse();
493         // Likewise, we reverse block_succ_range, but the block_succ
494         // concatenated array can remain as-is.
495         self.vcode.block_succ_range.reverse();
496         self.vcode.insts.reverse();
497         self.vcode.srclocs.reverse();
498         // Likewise, branch_block_arg_succ_range is indexed by block
499         // so must be reversed.
500         self.vcode.branch_block_arg_succ_range.reverse();
501 
502         // To translate an instruction index *endpoint* in reversed
503         // order to forward order, compute `n_insts - i`.
504         //
505         // Why not `n_insts - 1 - i`? That would be correct to
506         // translate an individual instruction index (for ten insts 0
507         // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes
508         // 0). But for the usual inclusive-start, exclusive-end range
509         // idiom, inclusive starts become exclusive ends and
510         // vice-versa, so e.g. an (inclusive) start of 0 becomes an
511         // (exclusive) end of 10.
512         let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index());
513 
514         // Edit the block-range instruction indices.
515         for tuple in &mut self.vcode.block_ranges {
516             let (start, end) = *tuple;
517             *tuple = (translate(end), translate(start)); // Note reversed order.
518         }
519 
520         // Generate debug-value labels based on per-label maps.
521         for (label, tuples) in &self.debug_info {
522             for &(start, end, vreg) in tuples {
523                 let vreg = self.resolve_vreg_alias(vreg);
524                 let fwd_start = translate(end);
525                 let fwd_end = translate(start);
526                 self.vcode
527                     .debug_value_labels
528                     .push((vreg, fwd_start, fwd_end, label.as_u32()));
529             }
530         }
531 
532         // Now sort debug value labels by VReg, as required
533         // by regalloc2.
534         self.vcode
535             .debug_value_labels
536             .sort_unstable_by_key(|(vreg, _, _, _)| *vreg);
537     }
538 
539     fn collect_operands(&mut self, allocatable: PRegSet) {
540         for (i, insn) in self.vcode.insts.iter().enumerate() {
541             // Push operands from the instruction onto the operand list.
542             //
543             // We rename through the vreg alias table as we collect
544             // the operands. This is better than a separate post-pass
545             // over operands, because it has more cache locality:
546             // operands only need to pass through L1 once. This is
547             // also better than renaming instructions'
548             // operands/registers while lowering, because here we only
549             // need to do the `match` over the instruction to visit
550             // its register fields (which is slow, branchy code) once.
551 
552             let vreg_aliases = &self.vcode.vreg_aliases;
553             let mut op_collector =
554                 OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| {
555                     Self::resolve_vreg_alias_impl(vreg_aliases, vreg)
556                 });
557             insn.get_operands(&mut op_collector);
558             let (ops, clobbers) = op_collector.finish();
559             self.vcode.operand_ranges.push(ops);
560 
561             if clobbers != PRegSet::default() {
562                 self.vcode.clobbers.insert(InsnIndex::new(i), clobbers);
563             }
564 
565             if let Some((dst, src)) = insn.is_move() {
566                 // We should never see non-virtual registers present in move
567                 // instructions.
568                 assert!(
569                     src.is_virtual(),
570                     "the real register {:?} was used as the source of a move instruction",
571                     src
572                 );
573                 assert!(
574                     dst.to_reg().is_virtual(),
575                     "the real register {:?} was used as the destination of a move instruction",
576                     dst.to_reg()
577                 );
578             }
579         }
580 
581         // Translate blockparam args via the vreg aliases table as well.
582         for arg in &mut self.vcode.branch_block_args {
583             let new_arg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg);
584             trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg);
585             *arg = new_arg;
586         }
587     }
588 
589     /// Build the final VCode.
590     pub fn build(mut self, allocatable: PRegSet, vregs: VRegAllocator<I>) -> VCode<I> {
591         self.vcode.vreg_types = vregs.vreg_types;
592         self.vcode.reftyped_vregs = vregs.reftyped_vregs;
593 
594         if self.direction == VCodeBuildDirection::Backward {
595             self.reverse_and_finalize();
596         }
597         self.collect_operands(allocatable);
598 
599         // Apply register aliases to the `reftyped_vregs` list since this list
600         // will be returned directly to `regalloc2` eventually and all
601         // operands/results of instructions will use the alias-resolved vregs
602         // from `regalloc2`'s perspective.
603         //
604         // Also note that `reftyped_vregs` can't have duplicates, so after the
605         // aliases are applied duplicates are removed.
606         for reg in self.vcode.reftyped_vregs.iter_mut() {
607             *reg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg);
608         }
609         self.vcode.reftyped_vregs.sort();
610         self.vcode.reftyped_vregs.dedup();
611 
612         self.compute_preds_from_succs();
613         self.vcode.debug_value_labels.sort_unstable();
614         self.vcode
615     }
616 }
617 
618 /// Is this type a reference type?
619 fn is_reftype(ty: Type) -> bool {
620     ty == types::R64 || ty == types::R32
621 }
622 
623 impl<I: VCodeInst> VCode<I> {
624     /// New empty VCode.
625     fn new(
626         sigs: SigSet,
627         abi: Callee<I::ABIMachineSpec>,
628         emit_info: I::Info,
629         block_order: BlockLoweringOrder,
630         constants: VCodeConstants,
631     ) -> VCode<I> {
632         let n_blocks = block_order.lowered_order().len();
633         VCode {
634             sigs,
635             vreg_types: vec![],
636             insts: Vec::with_capacity(10 * n_blocks),
637             operands: Vec::with_capacity(30 * n_blocks),
638             operand_ranges: Vec::with_capacity(10 * n_blocks),
639             clobbers: FxHashMap::default(),
640             srclocs: Vec::with_capacity(10 * n_blocks),
641             entry: BlockIndex::new(0),
642             block_ranges: Vec::with_capacity(n_blocks),
643             block_succ_range: Vec::with_capacity(n_blocks),
644             block_succs_preds: Vec::with_capacity(2 * n_blocks),
645             block_pred_range: Vec::with_capacity(n_blocks),
646             block_params_range: Vec::with_capacity(n_blocks),
647             block_params: Vec::with_capacity(5 * n_blocks),
648             branch_block_args: Vec::with_capacity(10 * n_blocks),
649             branch_block_arg_range: Vec::with_capacity(2 * n_blocks),
650             branch_block_arg_succ_range: Vec::with_capacity(n_blocks),
651             block_order,
652             abi,
653             emit_info,
654             reftyped_vregs: vec![],
655             constants,
656             debug_value_labels: vec![],
657             vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()),
658         }
659     }
660 
661     /// Get the number of blocks. Block indices will be in the range `0 ..
662     /// (self.num_blocks() - 1)`.
663     pub fn num_blocks(&self) -> usize {
664         self.block_ranges.len()
665     }
666 
667     /// The number of lowered instructions.
668     pub fn num_insts(&self) -> usize {
669         self.insts.len()
670     }
671 
672     /// Get the successors for a block.
673     pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] {
674         let (start, end) = self.block_succ_range[block.index()];
675         &self.block_succs_preds[start as usize..end as usize]
676     }
677 
678     fn compute_clobbers(&self, regalloc: &regalloc2::Output) -> Vec<Writable<RealReg>> {
679         // Compute clobbered registers.
680         let mut clobbered = vec![];
681         let mut clobbered_set = FxHashSet::default();
682 
683         // All moves are included in clobbers.
684         for edit in &regalloc.edits {
685             let Edit::Move { to, .. } = edit.1;
686             if let Some(preg) = to.as_reg() {
687                 let reg = RealReg::from(preg);
688                 if clobbered_set.insert(reg) {
689                     clobbered.push(Writable::from_reg(reg));
690                 }
691             }
692         }
693 
694         for (i, (start, end)) in self.operand_ranges.iter().enumerate() {
695             // Skip this instruction if not "included in clobbers" as
696             // per the MachInst. (Some backends use this to implement
697             // ABI specifics; e.g., excluding calls of the same ABI as
698             // the current function from clobbers, because by
699             // definition everything clobbered by the call can be
700             // clobbered by this function without saving as well.)
701             if !self.insts[i].is_included_in_clobbers() {
702                 continue;
703             }
704 
705             let start = *start as usize;
706             let end = *end as usize;
707             let operands = &self.operands[start..end];
708             let allocs = &regalloc.allocs[start..end];
709             for (operand, alloc) in operands.iter().zip(allocs.iter()) {
710                 // We're interested only in writes (Mods or Defs).
711                 if operand.kind() == OperandKind::Use {
712                     continue;
713                 }
714                 if let Some(preg) = alloc.as_reg() {
715                     let reg = RealReg::from(preg);
716                     if clobbered_set.insert(reg) {
717                         clobbered.push(Writable::from_reg(reg));
718                     }
719                 }
720             }
721 
722             // Also add explicitly-clobbered registers.
723             for preg in self
724                 .clobbers
725                 .get(&InsnIndex::new(i))
726                 .cloned()
727                 .unwrap_or_default()
728             {
729                 let reg = RealReg::from(preg);
730                 if clobbered_set.insert(reg) {
731                     clobbered.push(Writable::from_reg(reg));
732                 }
733             }
734         }
735 
736         clobbered
737     }
738 
739     /// Emit the instructions to a `MachBuffer`, containing fixed-up
740     /// code and external reloc/trap/etc. records ready for use. Takes
741     /// the regalloc results as well.
742     ///
743     /// Returns the machine code itself, and optionally metadata
744     /// and/or a disassembly, as an `EmitResult`. The `VCode` itself
745     /// is consumed by the emission process.
746     pub fn emit(
747         mut self,
748         regalloc: &regalloc2::Output,
749         want_disasm: bool,
750         flags: &settings::Flags,
751         ctrl_plane: &mut ControlPlane,
752     ) -> EmitResult
753     where
754         I: VCodeInst,
755     {
756         // To write into disasm string.
757         use core::fmt::Write;
758 
759         let _tt = timing::vcode_emit();
760         let mut buffer = MachBuffer::new();
761         let mut bb_starts: Vec<Option<CodeOffset>> = vec![];
762 
763         // The first M MachLabels are reserved for block indices.
764         buffer.reserve_labels_for_blocks(self.num_blocks());
765 
766         // Register all allocated constants with the `MachBuffer` to ensure that
767         // any references to the constants during instructions can be handled
768         // correctly.
769         buffer.register_constants(&self.constants);
770 
771         // Construct the final order we emit code in: cold blocks at the end.
772         let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![];
773         let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![];
774         for block in 0..self.num_blocks() {
775             let block = BlockIndex::new(block);
776             if self.block_order.is_cold(block) {
777                 cold_blocks.push(block);
778             } else {
779                 final_order.push(block);
780             }
781         }
782         final_order.extend(cold_blocks.clone());
783 
784         // Compute/save info we need for the prologue: clobbers and
785         // number of spillslots.
786         //
787         // We clone `abi` here because we will mutate it as we
788         // generate the prologue and set other info, but we can't
789         // mutate `VCode`. The info it usually carries prior to
790         // setting clobbers is fairly minimal so this should be
791         // relatively cheap.
792         let clobbers = self.compute_clobbers(regalloc);
793         self.abi.set_num_spillslots(regalloc.num_spillslots);
794         self.abi.set_clobbered(clobbers);
795 
796         // We need to generate the prologue in order to get the ABI
797         // object into the right state first. We'll emit it when we
798         // hit the right block below.
799         let prologue_insts = self.abi.gen_prologue(&self.sigs);
800 
801         // Emit blocks.
802         let mut cur_srcloc = None;
803         let mut last_offset = None;
804         let mut inst_offsets = vec![];
805         let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane));
806 
807         let mut disasm = String::new();
808 
809         if !self.debug_value_labels.is_empty() {
810             inst_offsets.resize(self.insts.len(), 0);
811         }
812 
813         // Count edits per block ahead of time; this is needed for
814         // lookahead island emission. (We could derive it per-block
815         // with binary search in the edit list, but it's more
816         // efficient to do it in one pass here.)
817         let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![];
818         let mut edit_idx = 0;
819         for block in 0..self.num_blocks() {
820             let end_inst = self.block_ranges[block].1;
821             let start_edit_idx = edit_idx;
822             while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst {
823                 edit_idx += 1;
824             }
825             let end_edit_idx = edit_idx;
826             ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32);
827         }
828 
829         let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled();
830         let mut bb_padding = match flags.bb_padding_log2_minus_one() {
831             0 => Vec::new(),
832             n => vec![0; 1 << (n - 1)],
833         };
834         let mut total_bb_padding = 0;
835 
836         for (block_order_idx, &block) in final_order.iter().enumerate() {
837             trace!("emitting block {:?}", block);
838 
839             // Call the new block hook for state
840             state.on_new_block();
841 
842             // Emit NOPs to align the block.
843             let new_offset = I::align_basic_block(buffer.cur_offset());
844             while new_offset > buffer.cur_offset() {
845                 // Pad with NOPs up to the aligned block offset.
846                 let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
847                 nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default());
848             }
849             assert_eq!(buffer.cur_offset(), new_offset);
850 
851             let do_emit = |inst: &I,
852                            allocs: &[Allocation],
853                            disasm: &mut String,
854                            buffer: &mut MachBuffer<I>,
855                            state: &mut I::State| {
856                 if want_disasm && !inst.is_args() {
857                     let mut s = state.clone();
858                     writeln!(disasm, "  {}", inst.pretty_print_inst(allocs, &mut s)).unwrap();
859                 }
860                 inst.emit(allocs, buffer, &self.emit_info, state);
861             };
862 
863             // Is this the first block? Emit the prologue directly if so.
864             if block == self.entry {
865                 trace!(" -> entry block");
866                 buffer.start_srcloc(Default::default());
867                 state.pre_sourceloc(Default::default());
868                 for inst in &prologue_insts {
869                     do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state);
870                 }
871                 buffer.end_srcloc();
872             }
873 
874             // Now emit the regular block body.
875 
876             buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut());
877 
878             if want_disasm {
879                 writeln!(&mut disasm, "block{}:", block.index()).unwrap();
880             }
881 
882             if flags.machine_code_cfg_info() {
883                 // Track BB starts. If we have backed up due to MachBuffer
884                 // branch opts, note that the removed blocks were removed.
885                 let cur_offset = buffer.cur_offset();
886                 if last_offset.is_some() && cur_offset <= last_offset.unwrap() {
887                     for i in (0..bb_starts.len()).rev() {
888                         if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() {
889                             break;
890                         }
891                         bb_starts[i] = None;
892                     }
893                 }
894                 bb_starts.push(Some(cur_offset));
895                 last_offset = Some(cur_offset);
896             }
897 
898             if let Some(block_start) = I::gen_block_start(
899                 self.block_order.is_indirect_branch_target(block),
900                 is_forward_edge_cfi_enabled,
901             ) {
902                 do_emit(&block_start, &[], &mut disasm, &mut buffer, &mut state);
903             }
904 
905             for inst_or_edit in regalloc.block_insts_and_edits(&self, block) {
906                 match inst_or_edit {
907                     InstOrEdit::Inst(iix) => {
908                         if !self.debug_value_labels.is_empty() {
909                             // If we need to produce debug info,
910                             // record the offset of each instruction
911                             // so that we can translate value-label
912                             // ranges to machine-code offsets.
913 
914                             // Cold blocks violate monotonicity
915                             // assumptions elsewhere (that
916                             // instructions in inst-index order are in
917                             // order in machine code), so we omit
918                             // their offsets here. Value-label range
919                             // generation below will skip empty ranges
920                             // and ranges with to-offsets of zero.
921                             if !self.block_order.is_cold(block) {
922                                 inst_offsets[iix.index()] = buffer.cur_offset();
923                             }
924                         }
925 
926                         // Update the srcloc at this point in the buffer.
927                         let srcloc = self.srclocs[iix.index()];
928                         if cur_srcloc != Some(srcloc) {
929                             if cur_srcloc.is_some() {
930                                 buffer.end_srcloc();
931                             }
932                             buffer.start_srcloc(srcloc);
933                             cur_srcloc = Some(srcloc);
934                         }
935                         state.pre_sourceloc(cur_srcloc.unwrap_or_default());
936 
937                         // If this is a safepoint, compute a stack map
938                         // and pass it to the emit state.
939                         if self.insts[iix.index()].is_safepoint() {
940                             let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![];
941                             // Find the contiguous range of
942                             // (progpoint, allocation) safepoint slot
943                             // records in `regalloc.safepoint_slots`
944                             // for this instruction index.
945                             let safepoint_slots_start = regalloc
946                                 .safepoint_slots
947                                 .binary_search_by(|(progpoint, _alloc)| {
948                                     if progpoint.inst() >= iix {
949                                         std::cmp::Ordering::Greater
950                                     } else {
951                                         std::cmp::Ordering::Less
952                                     }
953                                 })
954                                 .unwrap_err();
955 
956                             for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..]
957                                 .iter()
958                                 .take_while(|(progpoint, _)| progpoint.inst() == iix)
959                             {
960                                 let slot = alloc.as_stack().unwrap();
961                                 safepoint_slots.push(slot);
962                             }
963                             if !safepoint_slots.is_empty() {
964                                 let stack_map = self
965                                     .abi
966                                     .spillslots_to_stack_map(&safepoint_slots[..], &state);
967                                 state.pre_safepoint(stack_map);
968                             }
969                         }
970 
971                         // Get the allocations for this inst from the regalloc result.
972                         let allocs = regalloc.inst_allocs(iix);
973 
974                         // If the instruction we are about to emit is
975                         // a return, place an epilogue at this point
976                         // (and don't emit the return; the actual
977                         // epilogue will contain it).
978                         if self.insts[iix.index()].is_term() == MachTerminator::Ret {
979                             for inst in self.abi.gen_epilogue(&self.sigs) {
980                                 do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state);
981                             }
982                         } else {
983                             // Emit the instruction!
984                             do_emit(
985                                 &self.insts[iix.index()],
986                                 allocs,
987                                 &mut disasm,
988                                 &mut buffer,
989                                 &mut state,
990                             );
991                         }
992                     }
993 
994                     InstOrEdit::Edit(Edit::Move { from, to }) => {
995                         // Create a move/spill/reload instruction and
996                         // immediately emit it.
997                         match (from.as_reg(), to.as_reg()) {
998                             (Some(from), Some(to)) => {
999                                 // Reg-to-reg move.
1000                                 let from_rreg = Reg::from(from);
1001                                 let to_rreg = Writable::from_reg(Reg::from(to));
1002                                 debug_assert_eq!(from.class(), to.class());
1003                                 let ty = I::canonical_type_for_rc(from.class());
1004                                 let mv = I::gen_move(to_rreg, from_rreg, ty);
1005                                 do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state);
1006                             }
1007                             (Some(from), None) => {
1008                                 // Spill from register to spillslot.
1009                                 let to = to.as_stack().unwrap();
1010                                 let from_rreg = RealReg::from(from);
1011                                 let spill = self.abi.gen_spill(to, from_rreg);
1012                                 do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state);
1013                             }
1014                             (None, Some(to)) => {
1015                                 // Load from spillslot to register.
1016                                 let from = from.as_stack().unwrap();
1017                                 let to_rreg = Writable::from_reg(RealReg::from(to));
1018                                 let reload = self.abi.gen_reload(to_rreg, from);
1019                                 do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state);
1020                             }
1021                             (None, None) => {
1022                                 panic!("regalloc2 should have eliminated stack-to-stack moves!");
1023                             }
1024                         }
1025                     }
1026                 }
1027             }
1028 
1029             if cur_srcloc.is_some() {
1030                 buffer.end_srcloc();
1031                 cur_srcloc = None;
1032             }
1033 
1034             // Do we need an island? Get the worst-case size of the next BB, add
1035             // it to the optional padding behind the block, and pass this to the
1036             // `MachBuffer` to determine if an island is necessary.
1037             let worst_case_next_bb = if block_order_idx < final_order.len() - 1 {
1038                 let next_block = final_order[block_order_idx + 1];
1039                 let next_block_range = self.block_ranges[next_block.index()];
1040                 let next_block_size =
1041                     (next_block_range.1.index() - next_block_range.0.index()) as u32;
1042                 let next_block_ra_insertions = ra_edits_per_block[next_block.index()];
1043                 I::worst_case_size() * (next_block_size + next_block_ra_insertions)
1044             } else {
1045                 0
1046             };
1047             let padding = if bb_padding.is_empty() {
1048                 0
1049             } else {
1050                 bb_padding.len() as u32 + I::LabelUse::ALIGN - 1
1051             };
1052             if buffer.island_needed(padding + worst_case_next_bb) {
1053                 buffer.emit_island(ctrl_plane);
1054             }
1055 
1056             // Insert padding, if configured, to stress the `MachBuffer`'s
1057             // relocation and island calculations.
1058             //
1059             // Padding can get quite large during fuzzing though so place a
1060             // total cap on it where when a per-function threshold is exceeded
1061             // the padding is turned back down to zero. This avoids a small-ish
1062             // test case generating a GB+ memory footprint in Cranelift for
1063             // example.
1064             if !bb_padding.is_empty() {
1065                 buffer.put_data(&bb_padding);
1066                 buffer.align_to(I::LabelUse::ALIGN);
1067                 total_bb_padding += bb_padding.len();
1068                 if total_bb_padding > (150 << 20) {
1069                     bb_padding = Vec::new();
1070                 }
1071             }
1072         }
1073 
1074         // emission state is not needed anymore, move control plane back out
1075         *ctrl_plane = state.take_ctrl_plane();
1076 
1077         let func_body_len = buffer.cur_offset();
1078 
1079         // Create `bb_edges` and final (filtered) `bb_starts`.
1080         let mut bb_edges = vec![];
1081         let mut bb_offsets = vec![];
1082         if flags.machine_code_cfg_info() {
1083             for block in 0..self.num_blocks() {
1084                 if bb_starts[block].is_none() {
1085                     // Block was deleted by MachBuffer; skip.
1086                     continue;
1087                 }
1088                 let from = bb_starts[block].unwrap();
1089 
1090                 bb_offsets.push(from);
1091                 // Resolve each `succ` label and add edges.
1092                 let succs = self.block_succs(BlockIndex::new(block));
1093                 for &succ in succs.iter() {
1094                     let to = buffer.resolve_label_offset(MachLabel::from_block(succ));
1095                     bb_edges.push((from, to));
1096                 }
1097             }
1098         }
1099 
1100         let value_labels_ranges =
1101             self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len);
1102         let frame_size = self.abi.frame_size();
1103 
1104         EmitResult {
1105             buffer: buffer.finish(&self.constants, ctrl_plane),
1106             bb_offsets,
1107             bb_edges,
1108             inst_offsets,
1109             func_body_len,
1110             disasm: if want_disasm { Some(disasm) } else { None },
1111             sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(),
1112             dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(),
1113             value_labels_ranges,
1114             frame_size,
1115         }
1116     }
1117 
1118     fn compute_value_labels_ranges(
1119         &self,
1120         regalloc: &regalloc2::Output,
1121         inst_offsets: &[CodeOffset],
1122         func_body_len: u32,
1123     ) -> ValueLabelsRanges {
1124         if self.debug_value_labels.is_empty() {
1125             return ValueLabelsRanges::default();
1126         }
1127 
1128         let mut value_labels_ranges: ValueLabelsRanges = HashMap::new();
1129         for &(label, from, to, alloc) in &regalloc.debug_locations {
1130             let ranges = value_labels_ranges
1131                 .entry(ValueLabel::from_u32(label))
1132                 .or_insert_with(|| vec![]);
1133             let from_offset = inst_offsets[from.inst().index()];
1134             let to_offset = if to.inst().index() == inst_offsets.len() {
1135                 func_body_len
1136             } else {
1137                 inst_offsets[to.inst().index()]
1138             };
1139 
1140             // Empty range or to-offset of zero can happen because of
1141             // cold blocks (see above).
1142             if to_offset == 0 || from_offset == to_offset {
1143                 continue;
1144             }
1145 
1146             let loc = if let Some(preg) = alloc.as_reg() {
1147                 LabelValueLoc::Reg(Reg::from(preg))
1148             } else {
1149                 // We can't translate spillslot locations at the
1150                 // moment because ValueLabelLoc requires an
1151                 // instantaneous SP offset, and this can *change*
1152                 // within the range we have here because of callsites
1153                 // adjusting SP temporarily. To avoid the complexity
1154                 // of accurately plumbing through nominal-SP
1155                 // adjustment sites, we just omit debug info for
1156                 // values that are spilled. Not ideal, but debug info
1157                 // is best-effort.
1158                 continue;
1159             };
1160 
1161             ranges.push(ValueLocRange {
1162                 loc,
1163                 // ValueLocRanges are recorded by *instruction-end
1164                 // offset*. `from_offset` is the *start* of the
1165                 // instruction; that is the same as the end of another
1166                 // instruction, so we only want to begin coverage once
1167                 // we are past the previous instruction's end.
1168                 start: from_offset + 1,
1169                 // Likewise, `end` is exclusive, but we want to
1170                 // *include* the end of the last
1171                 // instruction. `to_offset` is the start of the
1172                 // `to`-instruction, which is the exclusive end, i.e.,
1173                 // the first instruction not covered. That
1174                 // instruction's start is the same as the end of the
1175                 // last instruction that is included, so we go one
1176                 // byte further to be sure to include it.
1177                 end: to_offset + 1,
1178             });
1179         }
1180 
1181         value_labels_ranges
1182     }
1183 
1184     /// Get the IR block for a BlockIndex, if one exists.
1185     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
1186         self.block_order.lowered_order()[block.index()].orig_block()
1187     }
1188 
1189     #[inline]
1190     fn assert_no_vreg_aliases<'a>(&self, list: &'a [VReg]) -> &'a [VReg] {
1191         for vreg in list {
1192             self.assert_not_vreg_alias(*vreg);
1193         }
1194         list
1195     }
1196 
1197     #[inline]
1198     fn assert_not_vreg_alias(&self, vreg: VReg) -> VReg {
1199         debug_assert!(VCodeBuilder::<I>::resolve_vreg_alias_impl(&self.vreg_aliases, vreg) == vreg);
1200         vreg
1201     }
1202 
1203     #[inline]
1204     fn assert_operand_not_vreg_alias(&self, op: Operand) -> Operand {
1205         // It should be true by construction that `Operand`s do not contain any
1206         // aliased vregs since they're all collected and mapped when the VCode
1207         // is itself constructed.
1208         self.assert_not_vreg_alias(op.vreg());
1209         op
1210     }
1211 }
1212 
1213 impl<I: VCodeInst> RegallocFunction for VCode<I> {
1214     fn num_insts(&self) -> usize {
1215         self.insts.len()
1216     }
1217 
1218     fn num_blocks(&self) -> usize {
1219         self.block_ranges.len()
1220     }
1221 
1222     fn entry_block(&self) -> BlockIndex {
1223         self.entry
1224     }
1225 
1226     fn block_insns(&self, block: BlockIndex) -> InstRange {
1227         let (start, end) = self.block_ranges[block.index()];
1228         InstRange::forward(start, end)
1229     }
1230 
1231     fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] {
1232         let (start, end) = self.block_succ_range[block.index()];
1233         &self.block_succs_preds[start as usize..end as usize]
1234     }
1235 
1236     fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] {
1237         let (start, end) = self.block_pred_range[block.index()];
1238         &self.block_succs_preds[start as usize..end as usize]
1239     }
1240 
1241     fn block_params(&self, block: BlockIndex) -> &[VReg] {
1242         // As a special case we don't return block params for the entry block, as all the arguments
1243         // will be defined by the `Inst::Args` instruction.
1244         if block == self.entry {
1245             return &[];
1246         }
1247 
1248         let (start, end) = self.block_params_range[block.index()];
1249         let ret = &self.block_params[start as usize..end as usize];
1250         // Currently block params are never aliased to another vreg, but
1251         // double-check just to be sure.
1252         self.assert_no_vreg_aliases(ret)
1253     }
1254 
1255     fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] {
1256         let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()];
1257         let succ_ranges =
1258             &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize];
1259         let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx];
1260         let ret = &self.branch_block_args
1261             [branch_block_args_start as usize..branch_block_args_end as usize];
1262         self.assert_no_vreg_aliases(ret)
1263     }
1264 
1265     fn is_ret(&self, insn: InsnIndex) -> bool {
1266         match self.insts[insn.index()].is_term() {
1267             // We treat blocks terminated by an unconditional trap like a return for regalloc.
1268             MachTerminator::None => self.insts[insn.index()].is_trap(),
1269             MachTerminator::Ret | MachTerminator::RetCall => true,
1270             MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false,
1271         }
1272     }
1273 
1274     fn is_branch(&self, insn: InsnIndex) -> bool {
1275         match self.insts[insn.index()].is_term() {
1276             MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true,
1277             _ => false,
1278         }
1279     }
1280 
1281     fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool {
1282         self.insts[insn.index()].is_safepoint()
1283     }
1284 
1285     fn inst_operands(&self, insn: InsnIndex) -> &[Operand] {
1286         let (start, end) = self.operand_ranges[insn.index()];
1287         let ret = &self.operands[start as usize..end as usize];
1288         for op in ret {
1289             self.assert_operand_not_vreg_alias(*op);
1290         }
1291         ret
1292     }
1293 
1294     fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet {
1295         self.clobbers.get(&insn).cloned().unwrap_or_default()
1296     }
1297 
1298     fn num_vregs(&self) -> usize {
1299         std::cmp::max(self.vreg_types.len(), first_user_vreg_index())
1300     }
1301 
1302     fn reftype_vregs(&self) -> &[VReg] {
1303         self.assert_no_vreg_aliases(&self.reftyped_vregs[..])
1304     }
1305 
1306     fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] {
1307         // VRegs here are inserted into `debug_value_labels` after code is
1308         // generated and aliases are fully defined, so no double-check that
1309         // aliases are not lingering.
1310         for (vreg, ..) in self.debug_value_labels.iter() {
1311             self.assert_not_vreg_alias(*vreg);
1312         }
1313         &self.debug_value_labels[..]
1314     }
1315 
1316     fn spillslot_size(&self, regclass: RegClass) -> usize {
1317         self.abi.get_spillslot_size(regclass) as usize
1318     }
1319 
1320     fn allow_multiple_vreg_defs(&self) -> bool {
1321         // At least the s390x backend requires this, because the
1322         // `Loop` pseudo-instruction aggregates all Operands so pinned
1323         // vregs (RealRegs) may occur more than once.
1324         true
1325     }
1326 }
1327 
1328 impl<I: VCodeInst> fmt::Debug for VCode<I> {
1329     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1330         writeln!(f, "VCode {{")?;
1331         writeln!(f, "  Entry block: {}", self.entry.index())?;
1332 
1333         let mut state = Default::default();
1334 
1335         let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>();
1336         alias_keys.sort_unstable();
1337         for key in alias_keys {
1338             let dest = self.vreg_aliases.get(&key).unwrap();
1339             writeln!(f, "  {:?} := {:?}", Reg::from(key), Reg::from(*dest))?;
1340         }
1341 
1342         for block in 0..self.num_blocks() {
1343             let block = BlockIndex::new(block);
1344             writeln!(f, "Block {}:", block.index())?;
1345             if let Some(bb) = self.bindex_to_bb(block) {
1346                 writeln!(f, "    (original IR block: {})", bb)?;
1347             }
1348             for succ in self.succs(block) {
1349                 writeln!(f, "    (successor: Block {})", succ.index())?;
1350             }
1351             let (start, end) = self.block_ranges[block.index()];
1352             writeln!(
1353                 f,
1354                 "    (instruction range: {} .. {})",
1355                 start.index(),
1356                 end.index()
1357             )?;
1358             for inst in start.index()..end.index() {
1359                 writeln!(
1360                     f,
1361                     "  Inst {}: {}",
1362                     inst,
1363                     self.insts[inst].pretty_print_inst(&[], &mut state)
1364                 )?;
1365             }
1366         }
1367 
1368         writeln!(f, "}}")?;
1369         Ok(())
1370     }
1371 }
1372 
1373 /// This structure manages VReg allocation during the lifetime of the VCodeBuilder.
1374 pub struct VRegAllocator<I> {
1375     /// Next virtual register number to allocate.
1376     next_vreg: usize,
1377 
1378     /// VReg IR-level types.
1379     vreg_types: Vec<Type>,
1380 
1381     /// A set with the same contents as `reftyped_vregs`, in order to
1382     /// avoid inserting more than once.
1383     reftyped_vregs_set: FxHashSet<VReg>,
1384 
1385     /// Reference-typed `regalloc2::VReg`s. The regalloc requires
1386     /// these in a dense slice (as opposed to querying the
1387     /// reftype-status of each vreg) for efficient iteration.
1388     reftyped_vregs: Vec<VReg>,
1389 
1390     /// The type of instruction that this allocator makes registers for.
1391     _inst: core::marker::PhantomData<I>,
1392 }
1393 
1394 impl<I: VCodeInst> VRegAllocator<I> {
1395     /// Make a new VRegAllocator.
1396     pub fn new() -> Self {
1397         Self {
1398             next_vreg: first_user_vreg_index(),
1399             vreg_types: vec![],
1400             reftyped_vregs_set: FxHashSet::default(),
1401             reftyped_vregs: vec![],
1402             _inst: core::marker::PhantomData::default(),
1403         }
1404     }
1405 
1406     /// Allocate a fresh ValueRegs.
1407     pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> {
1408         let v = self.next_vreg;
1409         let (regclasses, tys) = I::rc_for_type(ty)?;
1410         self.next_vreg += regclasses.len();
1411         if self.next_vreg >= VReg::MAX {
1412             return Err(CodegenError::CodeTooLarge);
1413         }
1414 
1415         let regs: ValueRegs<Reg> = match regclasses {
1416             &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()),
1417             &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()),
1418             // We can extend this if/when we support 32-bit targets; e.g.,
1419             // an i128 on a 32-bit machine will need up to four machine regs
1420             // for a `Value`.
1421             _ => panic!("Value must reside in 1 or 2 registers"),
1422         };
1423         for (&reg_ty, &reg) in tys.iter().zip(regs.regs().iter()) {
1424             self.set_vreg_type(reg.to_virtual_reg().unwrap(), reg_ty);
1425         }
1426         Ok(regs)
1427     }
1428 
1429     /// Set the type of this virtual register.
1430     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
1431         if self.vreg_types.len() <= vreg.index() {
1432             self.vreg_types.resize(vreg.index() + 1, ir::types::INVALID);
1433         }
1434         self.vreg_types[vreg.index()] = ty;
1435         if is_reftype(ty) {
1436             let vreg: VReg = vreg.into();
1437             if self.reftyped_vregs_set.insert(vreg) {
1438                 self.reftyped_vregs.push(vreg);
1439             }
1440         }
1441     }
1442 }
1443 
1444 /// This structure tracks the large constants used in VCode that will be emitted separately by the
1445 /// [MachBuffer].
1446 ///
1447 /// First, during the lowering phase, constants are inserted using
1448 /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are
1449 /// used in this phase. Some deduplication is performed, when possible, as constant
1450 /// values are inserted.
1451 ///
1452 /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the
1453 /// constants so that instructions can refer to the value's memory location. The [MachBuffer]
1454 /// then writes the constant values to the buffer.
1455 #[derive(Default)]
1456 pub struct VCodeConstants {
1457     constants: PrimaryMap<VCodeConstant, VCodeConstantData>,
1458     pool_uses: HashMap<Constant, VCodeConstant>,
1459     well_known_uses: HashMap<*const [u8], VCodeConstant>,
1460     u64s: HashMap<[u8; 8], VCodeConstant>,
1461 }
1462 impl VCodeConstants {
1463     /// Initialize the structure with the expected number of constants.
1464     pub fn with_capacity(expected_num_constants: usize) -> Self {
1465         Self {
1466             constants: PrimaryMap::with_capacity(expected_num_constants),
1467             pool_uses: HashMap::with_capacity(expected_num_constants),
1468             well_known_uses: HashMap::new(),
1469             u64s: HashMap::new(),
1470         }
1471     }
1472 
1473     /// Insert a constant; using this method indicates that a constant value will be used and thus
1474     /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants
1475     /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not
1476     /// [VCodeConstantData::Generated].
1477     pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant {
1478         match data {
1479             VCodeConstantData::Generated(_) => self.constants.push(data),
1480             VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) {
1481                 None => {
1482                     let vcode_constant = self.constants.push(data);
1483                     self.pool_uses.insert(constant, vcode_constant);
1484                     vcode_constant
1485                 }
1486                 Some(&vcode_constant) => vcode_constant,
1487             },
1488             VCodeConstantData::WellKnown(data_ref) => {
1489                 match self.well_known_uses.entry(data_ref as *const [u8]) {
1490                     Entry::Vacant(v) => {
1491                         let vcode_constant = self.constants.push(data);
1492                         v.insert(vcode_constant);
1493                         vcode_constant
1494                     }
1495                     Entry::Occupied(o) => *o.get(),
1496                 }
1497             }
1498             VCodeConstantData::U64(value) => match self.u64s.entry(value) {
1499                 Entry::Vacant(v) => {
1500                     let vcode_constant = self.constants.push(data);
1501                     v.insert(vcode_constant);
1502                     vcode_constant
1503                 }
1504                 Entry::Occupied(o) => *o.get(),
1505             },
1506         }
1507     }
1508 
1509     /// Return the number of constants inserted.
1510     pub fn len(&self) -> usize {
1511         self.constants.len()
1512     }
1513 
1514     /// Iterate over the [VCodeConstant] keys inserted in this structure.
1515     pub fn keys(&self) -> Keys<VCodeConstant> {
1516         self.constants.keys()
1517     }
1518 
1519     /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this
1520     /// structure.
1521     pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> {
1522         self.constants.iter()
1523     }
1524 
1525     /// Returns the data associated with the specified constant.
1526     pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData {
1527         &self.constants[c]
1528     }
1529 }
1530 
1531 /// A use of a constant by one or more VCode instructions; see [VCodeConstants].
1532 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1533 pub struct VCodeConstant(u32);
1534 entity_impl!(VCodeConstant);
1535 
1536 /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking
1537 /// these separately instead of as raw byte buffers allows us to avoid some duplication.
1538 pub enum VCodeConstantData {
1539     /// A constant already present in the Cranelift IR
1540     /// [ConstantPool](crate::ir::constant::ConstantPool).
1541     Pool(Constant, ConstantData),
1542     /// A reference to a well-known constant value that is statically encoded within the compiler.
1543     WellKnown(&'static [u8]),
1544     /// A constant value generated during lowering; the value may depend on the instruction context
1545     /// which makes it difficult to de-duplicate--if possible, use other variants.
1546     Generated(ConstantData),
1547     /// A constant of at most 64 bits. These are deduplicated as
1548     /// well. Stored as a fixed-size array of `u8` so that we do not
1549     /// encounter endianness problems when cross-compiling.
1550     U64([u8; 8]),
1551 }
1552 impl VCodeConstantData {
1553     /// Retrieve the constant data as a byte slice.
1554     pub fn as_slice(&self) -> &[u8] {
1555         match self {
1556             VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(),
1557             VCodeConstantData::WellKnown(d) => d,
1558             VCodeConstantData::U64(value) => &value[..],
1559         }
1560     }
1561 
1562     /// Calculate the alignment of the constant data.
1563     pub fn alignment(&self) -> u32 {
1564         if self.as_slice().len() <= 8 {
1565             8
1566         } else {
1567             16
1568         }
1569     }
1570 }
1571 
1572 #[cfg(test)]
1573 mod test {
1574     use super::*;
1575     use std::mem::size_of;
1576 
1577     #[test]
1578     fn size_of_constant_structs() {
1579         assert_eq!(size_of::<Constant>(), 4);
1580         assert_eq!(size_of::<VCodeConstant>(), 4);
1581         assert_eq!(size_of::<ConstantData>(), 24);
1582         assert_eq!(size_of::<VCodeConstantData>(), 32);
1583         assert_eq!(
1584             size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(),
1585             24
1586         );
1587         // TODO The VCodeConstants structure's memory size could be further optimized.
1588         // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at
1589         // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes.
1590     }
1591 }
1592