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::ir::{self, types, Constant, ConstantData, SourceLoc};
22 use crate::machinst::*;
23 use crate::settings;
24 use crate::timing;
25 use regalloc::Function as RegallocFunction;
26 use regalloc::Set as RegallocSet;
27 use regalloc::{
28     BlockIx, InstIx, PrettyPrint, Range, RegAllocResult, RegClass, RegUsageCollector,
29     RegUsageMapper, SpillSlot, StackmapRequestInfo,
30 };
31 
32 use alloc::boxed::Box;
33 use alloc::{borrow::Cow, vec::Vec};
34 use cranelift_entity::{entity_impl, Keys, PrimaryMap};
35 use std::cell::RefCell;
36 use std::collections::HashMap;
37 use std::fmt;
38 use std::iter;
39 use std::string::String;
40 
41 /// Index referring to an instruction in VCode.
42 pub type InsnIndex = u32;
43 /// Index referring to a basic block in VCode.
44 pub type BlockIndex = u32;
45 
46 /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
47 /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
48 pub trait VCodeInst: MachInst + MachInstEmit {}
49 impl<I: MachInst + MachInstEmit> VCodeInst for I {}
50 
51 /// A function in "VCode" (virtualized-register code) form, after lowering.
52 /// This is essentially a standard CFG of basic blocks, where each basic block
53 /// consists of lowered instructions produced by the machine-specific backend.
54 pub struct VCode<I: VCodeInst> {
55     /// Function liveins.
56     liveins: RegallocSet<RealReg>,
57 
58     /// Function liveouts.
59     liveouts: RegallocSet<RealReg>,
60 
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     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
71     /// reasonable to keep one of these per instruction.)
72     srclocs: Vec<SourceLoc>,
73 
74     /// Entry block.
75     entry: BlockIndex,
76 
77     /// Block instruction indices.
78     block_ranges: Vec<(InsnIndex, InsnIndex)>,
79 
80     /// Block successors: index range in the successor-list below.
81     block_succ_range: Vec<(usize, usize)>,
82 
83     /// Block successor lists, concatenated into one Vec. The `block_succ_range`
84     /// list of tuples above gives (start, end) ranges within this list that
85     /// correspond to each basic block's successors.
86     block_succs: Vec<BlockIx>,
87 
88     /// Block-order information.
89     block_order: BlockLoweringOrder,
90 
91     /// ABI object.
92     abi: Box<dyn ABICallee<I = I>>,
93 
94     /// Constant information used during code emission. This should be
95     /// immutable across function compilations within the same module.
96     emit_info: I::Info,
97 
98     /// Safepoint instruction indices. Filled in post-regalloc. (Prior to
99     /// regalloc, the safepoint instructions are listed in the separate
100     /// `StackmapRequestInfo` held separate from the `VCode`.)
101     safepoint_insns: Vec<InsnIndex>,
102 
103     /// For each safepoint entry in `safepoint_insns`, a list of `SpillSlot`s.
104     /// These are used to generate actual stack maps at emission. Filled in
105     /// post-regalloc.
106     safepoint_slots: Vec<Vec<SpillSlot>>,
107 
108     /// Do we generate debug info?
109     generate_debug_info: bool,
110 
111     /// Instruction end offsets, instruction indices at each label,
112     /// total buffer size, and start of cold code.  Only present if
113     /// `generate_debug_info` is set.
114     insts_layout: RefCell<InstsLayoutInfo>,
115 
116     /// Constants.
117     constants: VCodeConstants,
118 
119     /// Are any debug value-labels present? If not, we can skip the
120     /// post-emission analysis.
121     has_value_labels: bool,
122 }
123 
124 #[derive(Debug, Default)]
125 pub(crate) struct InstsLayoutInfo {
126     pub(crate) inst_end_offsets: Vec<CodeOffset>,
127     pub(crate) label_inst_indices: Vec<CodeOffset>,
128     pub(crate) start_of_cold_code: Option<CodeOffset>,
129 }
130 
131 /// A builder for a VCode function body. This builder is designed for the
132 /// lowering approach that we take: we traverse basic blocks in forward
133 /// (original IR) order, but within each basic block, we generate code from
134 /// bottom to top; and within each IR instruction that we visit in this reverse
135 /// order, we emit machine instructions in *forward* order again.
136 ///
137 /// Hence, to produce the final instructions in proper order, we perform two
138 /// swaps.  First, the machine instructions (`I` instances) are produced in
139 /// forward order for an individual IR instruction. Then these are *reversed*
140 /// and concatenated to `bb_insns` at the end of the IR instruction lowering.
141 /// The `bb_insns` vec will thus contain all machine instructions for a basic
142 /// block, in reverse order. Finally, when we're done with a basic block, we
143 /// reverse the whole block's vec of instructions again, and concatenate onto
144 /// the VCode's insts.
145 pub struct VCodeBuilder<I: VCodeInst> {
146     /// In-progress VCode.
147     vcode: VCode<I>,
148 
149     /// In-progress stack map-request info.
150     stack_map_info: StackmapRequestInfo,
151 
152     /// Index of the last block-start in the vcode.
153     block_start: InsnIndex,
154 
155     /// Start of succs for the current block in the concatenated succs list.
156     succ_start: usize,
157 
158     /// Current source location.
159     cur_srcloc: SourceLoc,
160 }
161 
162 impl<I: VCodeInst> VCodeBuilder<I> {
163     /// Create a new VCodeBuilder.
164     pub fn new(
165         abi: Box<dyn ABICallee<I = I>>,
166         emit_info: I::Info,
167         block_order: BlockLoweringOrder,
168         constants: VCodeConstants,
169     ) -> VCodeBuilder<I> {
170         let reftype_class = I::ref_type_regclass(abi.flags());
171         let vcode = VCode::new(
172             abi,
173             emit_info,
174             block_order,
175             constants,
176             /* generate_debug_info = */ true,
177         );
178         let stack_map_info = StackmapRequestInfo {
179             reftype_class,
180             reftyped_vregs: vec![],
181             safepoint_insns: vec![],
182         };
183 
184         VCodeBuilder {
185             vcode,
186             stack_map_info,
187             block_start: 0,
188             succ_start: 0,
189             cur_srcloc: SourceLoc::default(),
190         }
191     }
192 
193     /// Access the ABI object.
194     pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> {
195         &mut *self.vcode.abi
196     }
197 
198     /// Access to the BlockLoweringOrder object.
199     pub fn block_order(&self) -> &BlockLoweringOrder {
200         &self.vcode.block_order
201     }
202 
203     /// Set the type of a VReg.
204     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
205         if self.vcode.vreg_types.len() <= vreg.get_index() {
206             self.vcode
207                 .vreg_types
208                 .resize(vreg.get_index() + 1, ir::types::I8);
209         }
210         self.vcode.vreg_types[vreg.get_index()] = ty;
211         if is_reftype(ty) {
212             self.stack_map_info.reftyped_vregs.push(vreg);
213             self.vcode.have_ref_values = true;
214         }
215     }
216 
217     /// Set the current block as the entry block.
218     pub fn set_entry(&mut self, block: BlockIndex) {
219         self.vcode.entry = block;
220     }
221 
222     /// End the current basic block. Must be called after emitting vcode insts
223     /// for IR insts and prior to ending the function (building the VCode).
224     pub fn end_bb(&mut self) {
225         let start_idx = self.block_start;
226         let end_idx = self.vcode.insts.len() as InsnIndex;
227         self.block_start = end_idx;
228         // Add the instruction index range to the list of blocks.
229         self.vcode.block_ranges.push((start_idx, end_idx));
230         // End the successors list.
231         let succ_end = self.vcode.block_succs.len();
232         self.vcode
233             .block_succ_range
234             .push((self.succ_start, succ_end));
235         self.succ_start = succ_end;
236     }
237 
238     /// Push an instruction for the current BB and current IR inst within the BB.
239     pub fn push(&mut self, insn: I, is_safepoint: bool) {
240         match insn.is_term() {
241             MachTerminator::None | MachTerminator::Ret => {}
242             MachTerminator::Uncond(target) => {
243                 self.vcode.block_succs.push(BlockIx::new(target.get()));
244             }
245             MachTerminator::Cond(true_branch, false_branch) => {
246                 self.vcode.block_succs.push(BlockIx::new(true_branch.get()));
247                 self.vcode
248                     .block_succs
249                     .push(BlockIx::new(false_branch.get()));
250             }
251             MachTerminator::Indirect(targets) => {
252                 for target in targets {
253                     self.vcode.block_succs.push(BlockIx::new(target.get()));
254                 }
255             }
256         }
257         if insn.defines_value_label().is_some() {
258             self.vcode.has_value_labels = true;
259         }
260         self.vcode.insts.push(insn);
261         self.vcode.srclocs.push(self.cur_srcloc);
262         if is_safepoint {
263             self.stack_map_info
264                 .safepoint_insns
265                 .push(InstIx::new((self.vcode.insts.len() - 1) as u32));
266         }
267     }
268 
269     /// Set the current source location.
270     pub fn set_srcloc(&mut self, srcloc: SourceLoc) {
271         self.cur_srcloc = srcloc;
272     }
273 
274     /// Access the constants.
275     pub fn constants(&mut self) -> &mut VCodeConstants {
276         &mut self.vcode.constants
277     }
278 
279     /// Build the final VCode, returning the vcode itself as well as auxiliary
280     /// information, such as the stack map request information.
281     pub fn build(self) -> (VCode<I>, StackmapRequestInfo) {
282         // TODO: come up with an abstraction for "vcode and auxiliary data". The
283         // auxiliary data needs to be separate from the vcode so that it can be
284         // referenced as the vcode is mutated (e.g. by the register allocator).
285         (self.vcode, self.stack_map_info)
286     }
287 }
288 
289 fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool {
290     if let Some((to, from)) = insn.is_move() {
291         to.to_reg() == from
292     } else {
293         false
294     }
295 }
296 
297 /// Is this type a reference type?
298 fn is_reftype(ty: Type) -> bool {
299     ty == types::R64 || ty == types::R32
300 }
301 
302 impl<I: VCodeInst> VCode<I> {
303     /// New empty VCode.
304     fn new(
305         abi: Box<dyn ABICallee<I = I>>,
306         emit_info: I::Info,
307         block_order: BlockLoweringOrder,
308         constants: VCodeConstants,
309         generate_debug_info: bool,
310     ) -> VCode<I> {
311         VCode {
312             liveins: abi.liveins(),
313             liveouts: abi.liveouts(),
314             vreg_types: vec![],
315             have_ref_values: false,
316             insts: vec![],
317             srclocs: vec![],
318             entry: 0,
319             block_ranges: vec![],
320             block_succ_range: vec![],
321             block_succs: vec![],
322             block_order,
323             abi,
324             emit_info,
325             safepoint_insns: vec![],
326             safepoint_slots: vec![],
327             generate_debug_info,
328             insts_layout: RefCell::new(Default::default()),
329             constants,
330             has_value_labels: false,
331         }
332     }
333 
334     /// Returns the flags controlling this function's compilation.
335     pub fn flags(&self) -> &settings::Flags {
336         self.abi.flags()
337     }
338 
339     /// Get the IR-level type of a VReg.
340     pub fn vreg_type(&self, vreg: VirtualReg) -> Type {
341         self.vreg_types[vreg.get_index()]
342     }
343 
344     /// Get the number of blocks. Block indices will be in the range `0 ..
345     /// (self.num_blocks() - 1)`.
346     pub fn num_blocks(&self) -> usize {
347         self.block_ranges.len()
348     }
349 
350     /// Stack frame size for the full function's body.
351     pub fn frame_size(&self) -> u32 {
352         self.abi.frame_size()
353     }
354 
355     /// Get the successors for a block.
356     pub fn succs(&self, block: BlockIndex) -> &[BlockIx] {
357         let (start, end) = self.block_succ_range[block as usize];
358         &self.block_succs[start..end]
359     }
360 
361     /// Take the results of register allocation, with a sequence of
362     /// instructions including spliced fill/reload/move instructions, and replace
363     /// the VCode with them.
364     pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) {
365         // Record the spillslot count and clobbered registers for the ABI/stack
366         // setup code.
367         self.abi.set_num_spillslots(result.num_spill_slots as usize);
368         self.abi
369             .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r)));
370 
371         let mut final_insns = vec![];
372         let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
373         let mut final_srclocs = vec![];
374         let mut final_safepoint_insns = vec![];
375         let mut safept_idx = 0;
376 
377         assert!(result.target_map.elems().len() == self.num_blocks());
378         for block in 0..self.num_blocks() {
379             let start = result.target_map.elems()[block].get() as usize;
380             let end = if block == self.num_blocks() - 1 {
381                 result.insns.len()
382             } else {
383                 result.target_map.elems()[block + 1].get() as usize
384             };
385             let block = block as BlockIndex;
386             let final_start = final_insns.len() as InsnIndex;
387 
388             if block == self.entry {
389                 // Start with the prologue.
390                 let prologue = self.abi.gen_prologue();
391                 let len = prologue.len();
392                 final_insns.extend(prologue.into_iter());
393                 final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len));
394             }
395 
396             for i in start..end {
397                 let insn = &result.insns[i];
398 
399                 // Elide redundant moves at this point (we only know what is
400                 // redundant once registers are allocated).
401                 if is_redundant_move(insn) {
402                     continue;
403                 }
404 
405                 // Is there a srcloc associated with this insn? Look it up based on original
406                 // instruction index (if new insn corresponds to some original insn, i.e., is not
407                 // an inserted load/spill/move).
408                 let orig_iix = result.orig_insn_map[InstIx::new(i as u32)];
409                 let srcloc = if orig_iix.is_invalid() {
410                     SourceLoc::default()
411                 } else {
412                     self.srclocs[orig_iix.get() as usize]
413                 };
414 
415                 // Whenever encountering a return instruction, replace it
416                 // with the epilogue.
417                 let is_ret = insn.is_term() == MachTerminator::Ret;
418                 if is_ret {
419                     let epilogue = self.abi.gen_epilogue();
420                     let len = epilogue.len();
421                     final_insns.extend(epilogue.into_iter());
422                     final_srclocs.extend(iter::repeat(srcloc).take(len));
423                 } else {
424                     final_insns.push(insn.clone());
425                     final_srclocs.push(srcloc);
426                 }
427 
428                 // Was this instruction a safepoint instruction? Add its final
429                 // index to the safepoint insn-index list if so.
430                 if safept_idx < result.new_safepoint_insns.len()
431                     && (result.new_safepoint_insns[safept_idx].get() as usize) == i
432                 {
433                     let idx = final_insns.len() - 1;
434                     final_safepoint_insns.push(idx as InsnIndex);
435                     safept_idx += 1;
436                 }
437             }
438 
439             let final_end = final_insns.len() as InsnIndex;
440             final_block_ranges[block as usize] = (final_start, final_end);
441         }
442 
443         debug_assert!(final_insns.len() == final_srclocs.len());
444 
445         self.insts = final_insns;
446         self.srclocs = final_srclocs;
447         self.block_ranges = final_block_ranges;
448         self.safepoint_insns = final_safepoint_insns;
449 
450         // Save safepoint slot-lists. These will be passed to the `EmitState`
451         // for the machine backend during emission so that it can do
452         // target-specific translations of slot numbers to stack offsets.
453         self.safepoint_slots = result.stackmaps;
454     }
455 
456     /// Emit the instructions to a `MachBuffer`, containing fixed-up code and external
457     /// reloc/trap/etc. records ready for use.
458     pub fn emit(
459         &self,
460     ) -> (
461         MachBuffer<I>,
462         Vec<CodeOffset>,
463         Vec<(CodeOffset, CodeOffset)>,
464     )
465     where
466         I: MachInstEmit,
467     {
468         let _tt = timing::vcode_emit();
469         let mut buffer = MachBuffer::new();
470         let mut state = I::State::new(&*self.abi);
471         let cfg_metadata = self.flags().machine_code_cfg_info();
472         let mut bb_starts: Vec<Option<CodeOffset>> = vec![];
473 
474         // The first M MachLabels are reserved for block indices, the next N MachLabels for
475         // constants.
476         buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex);
477         buffer.reserve_labels_for_constants(&self.constants);
478 
479         let mut inst_end_offsets = vec![0; self.insts.len()];
480         let mut label_inst_indices = vec![0; self.num_blocks()];
481 
482         // Map from instruction index to index in
483         // `safepoint_slots`. We need this because we emit
484         // instructions out-of-order, while the safepoint_insns /
485         // safepoint_slots data structures are sorted in instruction
486         // order.
487         let mut safepoint_indices: FxHashMap<u32, usize> = FxHashMap::default();
488         for (safepoint_idx, iix) in self.safepoint_insns.iter().enumerate() {
489             // Disregard safepoints that ended up having no live refs.
490             if self.safepoint_slots[safepoint_idx].len() > 0 {
491                 safepoint_indices.insert(*iix, safepoint_idx);
492             }
493         }
494 
495         // Construct the final order we emit code in: cold blocks at the end.
496         let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![];
497         let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![];
498         for block in 0..self.num_blocks() {
499             let block = block as BlockIndex;
500             if self.block_order.is_cold(block) {
501                 cold_blocks.push(block);
502             } else {
503                 final_order.push(block);
504             }
505         }
506         let first_cold_block = cold_blocks.first().cloned();
507         final_order.extend(cold_blocks.clone());
508 
509         // Emit blocks.
510         let mut cur_srcloc = None;
511         let mut last_offset = None;
512         let mut start_of_cold_code = None;
513         for block in final_order {
514             let new_offset = I::align_basic_block(buffer.cur_offset());
515             while new_offset > buffer.cur_offset() {
516                 // Pad with NOPs up to the aligned block offset.
517                 let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
518                 nop.emit(&mut buffer, &self.emit_info, &mut Default::default());
519             }
520             assert_eq!(buffer.cur_offset(), new_offset);
521 
522             if Some(block) == first_cold_block {
523                 start_of_cold_code = Some(buffer.cur_offset());
524             }
525 
526             let (start, end) = self.block_ranges[block as usize];
527             buffer.bind_label(MachLabel::from_block(block));
528             label_inst_indices[block as usize] = start;
529 
530             if cfg_metadata {
531                 // Track BB starts. If we have backed up due to MachBuffer
532                 // branch opts, note that the removed blocks were removed.
533                 let cur_offset = buffer.cur_offset();
534                 if last_offset.is_some() && cur_offset <= last_offset.unwrap() {
535                     for i in (0..bb_starts.len()).rev() {
536                         if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() {
537                             break;
538                         }
539                         bb_starts[i] = None;
540                     }
541                 }
542                 bb_starts.push(Some(cur_offset));
543                 last_offset = Some(cur_offset);
544             }
545 
546             for iix in start..end {
547                 let srcloc = self.srclocs[iix as usize];
548                 if cur_srcloc != Some(srcloc) {
549                     if cur_srcloc.is_some() {
550                         buffer.end_srcloc();
551                     }
552                     buffer.start_srcloc(srcloc);
553                     cur_srcloc = Some(srcloc);
554                 }
555                 state.pre_sourceloc(cur_srcloc.unwrap_or(SourceLoc::default()));
556 
557                 if let Some(safepoint_idx) = safepoint_indices.get(&iix) {
558                     let stack_map = self
559                         .abi
560                         .spillslots_to_stack_map(&self.safepoint_slots[*safepoint_idx][..], &state);
561                     state.pre_safepoint(stack_map);
562                 }
563 
564                 self.insts[iix as usize].emit(&mut buffer, &self.emit_info, &mut state);
565 
566                 if self.generate_debug_info {
567                     // Buffer truncation may have happened since last inst append; trim inst-end
568                     // layout info as appropriate.
569                     let l = &mut inst_end_offsets[0..iix as usize];
570                     for end in l.iter_mut().rev() {
571                         if *end > buffer.cur_offset() {
572                             *end = buffer.cur_offset();
573                         } else {
574                             break;
575                         }
576                     }
577                     inst_end_offsets[iix as usize] = buffer.cur_offset();
578                 }
579             }
580 
581             if cur_srcloc.is_some() {
582                 buffer.end_srcloc();
583                 cur_srcloc = None;
584             }
585 
586             // Do we need an island? Get the worst-case size of the next BB and see if, having
587             // emitted that many bytes, we will be beyond the deadline.
588             if block < (self.num_blocks() - 1) as BlockIndex {
589                 let next_block = block + 1;
590                 let next_block_range = self.block_ranges[next_block as usize];
591                 let next_block_size = next_block_range.1 - next_block_range.0;
592                 let worst_case_next_bb = I::worst_case_size() * next_block_size;
593                 if buffer.island_needed(worst_case_next_bb) {
594                     buffer.emit_island(worst_case_next_bb);
595                 }
596             }
597         }
598 
599         // Emit the constants used by the function.
600         for (constant, data) in self.constants.iter() {
601             let label = buffer.get_label_for_constant(constant);
602             buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value());
603         }
604 
605         if self.generate_debug_info {
606             for end in inst_end_offsets.iter_mut().rev() {
607                 if *end > buffer.cur_offset() {
608                     *end = buffer.cur_offset();
609                 } else {
610                     break;
611                 }
612             }
613             *self.insts_layout.borrow_mut() = InstsLayoutInfo {
614                 inst_end_offsets,
615                 label_inst_indices,
616                 start_of_cold_code,
617             };
618         }
619 
620         // Create `bb_edges` and final (filtered) `bb_starts`.
621         let mut final_bb_starts = vec![];
622         let mut bb_edges = vec![];
623         if cfg_metadata {
624             for block in 0..self.num_blocks() {
625                 if bb_starts[block].is_none() {
626                     // Block was deleted by MachBuffer; skip.
627                     continue;
628                 }
629                 let from = bb_starts[block].unwrap();
630 
631                 final_bb_starts.push(from);
632                 // Resolve each `succ` label and add edges.
633                 let succs = self.block_succs(BlockIx::new(block as u32));
634                 for succ in succs.iter() {
635                     let to = buffer.resolve_label_offset(MachLabel::from_block(succ.get()));
636                     bb_edges.push((from, to));
637                 }
638             }
639         }
640 
641         (buffer, final_bb_starts, bb_edges)
642     }
643 
644     /// Generates value-label ranges.
645     pub fn value_labels_ranges(&self) -> ValueLabelsRanges {
646         if !self.has_value_labels {
647             return ValueLabelsRanges::default();
648         }
649 
650         let layout_info = &self.insts_layout.borrow();
651         debug::compute(&self.insts, &*layout_info)
652     }
653 
654     /// Get the offsets of stackslots.
655     pub fn stackslot_offsets(&self) -> &PrimaryMap<StackSlot, u32> {
656         self.abi.stackslot_offsets()
657     }
658 
659     /// Get the IR block for a BlockIndex, if one exists.
660     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
661         self.block_order.lowered_order()[block as usize].orig_block()
662     }
663 }
664 
665 impl<I: VCodeInst> RegallocFunction for VCode<I> {
666     type Inst = I;
667 
668     fn insns(&self) -> &[I] {
669         &self.insts[..]
670     }
671 
672     fn insns_mut(&mut self) -> &mut [I] {
673         &mut self.insts[..]
674     }
675 
676     fn get_insn(&self, insn: InstIx) -> &I {
677         &self.insts[insn.get() as usize]
678     }
679 
680     fn get_insn_mut(&mut self, insn: InstIx) -> &mut I {
681         &mut self.insts[insn.get() as usize]
682     }
683 
684     fn blocks(&self) -> Range<BlockIx> {
685         Range::new(BlockIx::new(0), self.block_ranges.len())
686     }
687 
688     fn entry_block(&self) -> BlockIx {
689         BlockIx::new(self.entry)
690     }
691 
692     fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
693         let (start, end) = self.block_ranges[block.get() as usize];
694         Range::new(InstIx::new(start), (end - start) as usize)
695     }
696 
697     fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> {
698         let (start, end) = self.block_succ_range[block.get() as usize];
699         Cow::Borrowed(&self.block_succs[start..end])
700     }
701 
702     fn is_ret(&self, insn: InstIx) -> bool {
703         match self.insts[insn.get() as usize].is_term() {
704             MachTerminator::Ret => true,
705             _ => false,
706         }
707     }
708 
709     fn is_included_in_clobbers(&self, insn: &I) -> bool {
710         insn.is_included_in_clobbers()
711     }
712 
713     fn get_regs(insn: &I, collector: &mut RegUsageCollector) {
714         insn.get_regs(collector)
715     }
716 
717     fn map_regs<RUM: RegUsageMapper>(insn: &mut I, mapper: &RUM) {
718         insn.map_regs(mapper);
719     }
720 
721     fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> {
722         insn.is_move()
723     }
724 
725     fn get_num_vregs(&self) -> usize {
726         self.vreg_types.len()
727     }
728 
729     fn get_spillslot_size(&self, regclass: RegClass, _: VirtualReg) -> u32 {
730         self.abi.get_spillslot_size(regclass)
731     }
732 
733     fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, _: Option<VirtualReg>) -> I {
734         self.abi.gen_spill(to_slot, from_reg)
735     }
736 
737     fn gen_reload(
738         &self,
739         to_reg: Writable<RealReg>,
740         from_slot: SpillSlot,
741         _: Option<VirtualReg>,
742     ) -> I {
743         self.abi.gen_reload(to_reg, from_slot)
744     }
745 
746     fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I {
747         let ty = self.vreg_type(vreg);
748         I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty)
749     }
750 
751     fn gen_zero_len_nop(&self) -> I {
752         I::gen_nop(0)
753     }
754 
755     fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> {
756         insn.maybe_direct_reload(reg, slot)
757     }
758 
759     fn func_liveins(&self) -> RegallocSet<RealReg> {
760         self.liveins.clone()
761     }
762 
763     fn func_liveouts(&self) -> RegallocSet<RealReg> {
764         self.liveouts.clone()
765     }
766 }
767 
768 impl<I: VCodeInst> fmt::Debug for VCode<I> {
769     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
770         writeln!(f, "VCode_Debug {{")?;
771         writeln!(f, "  Entry block: {}", self.entry)?;
772 
773         for block in 0..self.num_blocks() {
774             writeln!(f, "Block {}:", block,)?;
775             for succ in self.succs(block as BlockIndex) {
776                 writeln!(f, "  (successor: Block {})", succ.get())?;
777             }
778             let (start, end) = self.block_ranges[block];
779             writeln!(f, "  (instruction range: {} .. {})", start, end)?;
780             for inst in start..end {
781                 writeln!(f, "  Inst {}: {:?}", inst, self.insts[inst as usize])?;
782             }
783         }
784 
785         writeln!(f, "}}")?;
786         Ok(())
787     }
788 }
789 
790 /// Pretty-printing with `RealRegUniverse` context.
791 impl<I: VCodeInst> PrettyPrint for VCode<I> {
792     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
793         use std::fmt::Write;
794 
795         let mut s = String::new();
796         write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap();
797         write!(&mut s, "  Entry block: {}\n", self.entry).unwrap();
798 
799         let mut state = Default::default();
800         let mut safepoint_idx = 0;
801         for i in 0..self.num_blocks() {
802             let block = i as BlockIndex;
803 
804             write!(&mut s, "Block {}:\n", block).unwrap();
805             if let Some(bb) = self.bindex_to_bb(block) {
806                 write!(&mut s, "  (original IR block: {})\n", bb).unwrap();
807             }
808             for succ in self.succs(block) {
809                 write!(&mut s, "  (successor: Block {})\n", succ.get()).unwrap();
810             }
811             let (start, end) = self.block_ranges[block as usize];
812             write!(&mut s, "  (instruction range: {} .. {})\n", start, end).unwrap();
813             for inst in start..end {
814                 if safepoint_idx < self.safepoint_insns.len()
815                     && self.safepoint_insns[safepoint_idx] == inst
816                 {
817                     write!(
818                         &mut s,
819                         "      (safepoint: slots {:?} with EmitState {:?})\n",
820                         self.safepoint_slots[safepoint_idx], state,
821                     )
822                     .unwrap();
823                     safepoint_idx += 1;
824                 }
825                 write!(
826                     &mut s,
827                     "  Inst {}:   {}\n",
828                     inst,
829                     self.insts[inst as usize].pretty_print(mb_rru, &mut state)
830                 )
831                 .unwrap();
832             }
833         }
834 
835         write!(&mut s, "}}}}\n").unwrap();
836 
837         s
838     }
839 }
840 
841 /// This structure tracks the large constants used in VCode that will be emitted separately by the
842 /// [MachBuffer].
843 ///
844 /// First, during the lowering phase, constants are inserted using
845 /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are
846 /// used in this phase. Some deduplication is performed, when possible, as constant
847 /// values are inserted.
848 ///
849 /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the
850 /// constants so that instructions can refer to the value's memory location. The [MachBuffer]
851 /// then writes the constant values to the buffer.
852 #[derive(Default)]
853 pub struct VCodeConstants {
854     constants: PrimaryMap<VCodeConstant, VCodeConstantData>,
855     pool_uses: HashMap<Constant, VCodeConstant>,
856     well_known_uses: HashMap<*const [u8], VCodeConstant>,
857 }
858 impl VCodeConstants {
859     /// Initialize the structure with the expected number of constants.
860     pub fn with_capacity(expected_num_constants: usize) -> Self {
861         Self {
862             constants: PrimaryMap::with_capacity(expected_num_constants),
863             pool_uses: HashMap::with_capacity(expected_num_constants),
864             well_known_uses: HashMap::new(),
865         }
866     }
867 
868     /// Insert a constant; using this method indicates that a constant value will be used and thus
869     /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants
870     /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not
871     /// [VCodeConstantData::Generated].
872     pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant {
873         match data {
874             VCodeConstantData::Generated(_) => self.constants.push(data),
875             VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) {
876                 None => {
877                     let vcode_constant = self.constants.push(data);
878                     self.pool_uses.insert(constant, vcode_constant);
879                     vcode_constant
880                 }
881                 Some(&vcode_constant) => vcode_constant,
882             },
883             VCodeConstantData::WellKnown(data_ref) => {
884                 match self.well_known_uses.get(&(data_ref as *const [u8])) {
885                     None => {
886                         let vcode_constant = self.constants.push(data);
887                         self.well_known_uses
888                             .insert(data_ref as *const [u8], vcode_constant);
889                         vcode_constant
890                     }
891                     Some(&vcode_constant) => vcode_constant,
892                 }
893             }
894         }
895     }
896 
897     /// Return the number of constants inserted.
898     pub fn len(&self) -> usize {
899         self.constants.len()
900     }
901 
902     /// Iterate over the [VCodeConstant] keys inserted in this structure.
903     pub fn keys(&self) -> Keys<VCodeConstant> {
904         self.constants.keys()
905     }
906 
907     /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this
908     /// structure.
909     pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> {
910         self.constants.iter()
911     }
912 }
913 
914 /// A use of a constant by one or more VCode instructions; see [VCodeConstants].
915 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
916 pub struct VCodeConstant(u32);
917 entity_impl!(VCodeConstant);
918 
919 /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking
920 /// these separately instead of as raw byte buffers allows us to avoid some duplication.
921 pub enum VCodeConstantData {
922     /// A constant already present in the Cranelift IR
923     /// [ConstantPool](crate::ir::constant::ConstantPool).
924     Pool(Constant, ConstantData),
925     /// A reference to a well-known constant value that is statically encoded within the compiler.
926     WellKnown(&'static [u8]),
927     /// A constant value generated during lowering; the value may depend on the instruction context
928     /// which makes it difficult to de-duplicate--if possible, use other variants.
929     Generated(ConstantData),
930 }
931 impl VCodeConstantData {
932     /// Retrieve the constant data as a byte slice.
933     pub fn as_slice(&self) -> &[u8] {
934         match self {
935             VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(),
936             VCodeConstantData::WellKnown(d) => d,
937         }
938     }
939 
940     /// Calculate the alignment of the constant data.
941     pub fn alignment(&self) -> u32 {
942         if self.as_slice().len() <= 8 {
943             8
944         } else {
945             16
946         }
947     }
948 }
949 
950 #[cfg(test)]
951 mod test {
952     use super::*;
953     use std::mem::size_of;
954 
955     #[test]
956     fn size_of_constant_structs() {
957         assert_eq!(size_of::<Constant>(), 4);
958         assert_eq!(size_of::<VCodeConstant>(), 4);
959         assert_eq!(size_of::<ConstantData>(), 24);
960         assert_eq!(size_of::<VCodeConstantData>(), 32);
961         assert_eq!(
962             size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(),
963             24
964         );
965         // TODO The VCodeConstants structure's memory size could be further optimized.
966         // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at
967         // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes.
968     }
969 }
970