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