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