1d8357426SChris Fallin //! This implements the VCode container: a CFG of Insts that have been lowered.
2d8357426SChris Fallin //!
3d8357426SChris Fallin //! VCode is virtual-register code. An instruction in VCode is almost a machine
4d8357426SChris Fallin //! instruction; however, its register slots can refer to virtual registers in
5d8357426SChris Fallin //! addition to real machine registers.
6d8357426SChris Fallin //!
7d8357426SChris Fallin //! VCode is structured with traditional basic blocks, and
8d8357426SChris Fallin //! each block must be terminated by an unconditional branch (one target), a
9d8357426SChris Fallin //! conditional branch (two targets), or a return (no targets). Note that this
10d8357426SChris Fallin //! slightly differs from the machine code of most ISAs: in most ISAs, a
11d8357426SChris Fallin //! conditional branch has one target (and the not-taken case falls through).
12d8357426SChris Fallin //! However, we expect that machine backends will elide branches to the following
13d8357426SChris Fallin //! block (i.e., zero-offset jumps), and will be able to codegen a branch-cond /
14d8357426SChris Fallin //! branch-uncond pair if *both* targets are not fallthrough. This allows us to
15d8357426SChris Fallin //! play with layout prior to final binary emission, as well, if we want.
16d8357426SChris Fallin //!
17d8357426SChris Fallin //! See the main module comment in `mod.rs` for more details on the VCode-based
18d8357426SChris Fallin //! backend pipeline.
19d8357426SChris Fallin 
20*666c2554SChris Fallin use crate::fx::FxHashMap;
2183f182b3SAndrew Brown use crate::ir::{self, types, Constant, ConstantData, SourceLoc};
22d8357426SChris Fallin use crate::machinst::*;
23d8357426SChris Fallin use crate::settings;
242b9fefe8SChris Fallin use crate::timing;
25d8357426SChris Fallin use regalloc::Function as RegallocFunction;
26d8357426SChris Fallin use regalloc::Set as RegallocSet;
27be6f060aSChris Fallin use regalloc::{
2871768bb6SChris Fallin     BlockIx, InstIx, PrettyPrint, Range, RegAllocResult, RegClass, RegUsageCollector,
2971768bb6SChris Fallin     RegUsageMapper, SpillSlot, StackmapRequestInfo,
30be6f060aSChris Fallin };
31d8357426SChris Fallin 
32d8357426SChris Fallin use alloc::boxed::Box;
334f919c64SBenjamin Bouvier use alloc::{borrow::Cow, vec::Vec};
3483f182b3SAndrew Brown use cranelift_entity::{entity_impl, Keys, PrimaryMap};
35de4af90aSYury Delendik use std::cell::RefCell;
3683f182b3SAndrew Brown use std::collections::HashMap;
37d8357426SChris Fallin use std::fmt;
38d8357426SChris Fallin use std::iter;
39d8357426SChris Fallin use std::string::String;
40d8357426SChris Fallin 
41d8357426SChris Fallin /// Index referring to an instruction in VCode.
42d8357426SChris Fallin pub type InsnIndex = u32;
43d8357426SChris Fallin /// Index referring to a basic block in VCode.
44d8357426SChris Fallin pub type BlockIndex = u32;
45d8357426SChris Fallin 
46d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
47d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
4872e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {}
4972e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {}
50d8357426SChris Fallin 
51d8357426SChris Fallin /// A function in "VCode" (virtualized-register code) form, after lowering.
52d8357426SChris Fallin /// This is essentially a standard CFG of basic blocks, where each basic block
53d8357426SChris Fallin /// consists of lowered instructions produced by the machine-specific backend.
54d8357426SChris Fallin pub struct VCode<I: VCodeInst> {
55d8357426SChris Fallin     /// Function liveins.
56d8357426SChris Fallin     liveins: RegallocSet<RealReg>,
57d8357426SChris Fallin 
58d8357426SChris Fallin     /// Function liveouts.
59d8357426SChris Fallin     liveouts: RegallocSet<RealReg>,
60d8357426SChris Fallin 
61d8357426SChris Fallin     /// VReg IR-level types.
62d8357426SChris Fallin     vreg_types: Vec<Type>,
63d8357426SChris Fallin 
6408353fccSChris Fallin     /// Do we have any ref values among our vregs?
6508353fccSChris Fallin     have_ref_values: bool,
6608353fccSChris Fallin 
67d8357426SChris Fallin     /// Lowered machine instructions in order corresponding to the original IR.
6848cf2c2fSChris Fallin     insts: Vec<I>,
69d8357426SChris Fallin 
70b691770fSChris Fallin     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
71b691770fSChris Fallin     /// reasonable to keep one of these per instruction.)
72b691770fSChris Fallin     srclocs: Vec<SourceLoc>,
73b691770fSChris Fallin 
74d8357426SChris Fallin     /// Entry block.
75d8357426SChris Fallin     entry: BlockIndex,
76d8357426SChris Fallin 
77d8357426SChris Fallin     /// Block instruction indices.
7848cf2c2fSChris Fallin     block_ranges: Vec<(InsnIndex, InsnIndex)>,
79d8357426SChris Fallin 
80d8357426SChris Fallin     /// Block successors: index range in the successor-list below.
81d8357426SChris Fallin     block_succ_range: Vec<(usize, usize)>,
82d8357426SChris Fallin 
83d8357426SChris Fallin     /// Block successor lists, concatenated into one Vec. The `block_succ_range`
84d8357426SChris Fallin     /// list of tuples above gives (start, end) ranges within this list that
85d8357426SChris Fallin     /// correspond to each basic block's successors.
864f919c64SBenjamin Bouvier     block_succs: Vec<BlockIx>,
87d8357426SChris Fallin 
8872e6be93SChris Fallin     /// Block-order information.
8972e6be93SChris Fallin     block_order: BlockLoweringOrder,
90d8357426SChris Fallin 
91d8357426SChris Fallin     /// ABI object.
92e8f772c1SChris Fallin     abi: Box<dyn ABICallee<I = I>>,
9308353fccSChris Fallin 
94c5bbc874SBenjamin Bouvier     /// Constant information used during code emission. This should be
95c5bbc874SBenjamin Bouvier     /// immutable across function compilations within the same module.
96c5bbc874SBenjamin Bouvier     emit_info: I::Info,
97c5bbc874SBenjamin Bouvier 
9808353fccSChris Fallin     /// Safepoint instruction indices. Filled in post-regalloc. (Prior to
9908353fccSChris Fallin     /// regalloc, the safepoint instructions are listed in the separate
10008353fccSChris Fallin     /// `StackmapRequestInfo` held separate from the `VCode`.)
10108353fccSChris Fallin     safepoint_insns: Vec<InsnIndex>,
10208353fccSChris Fallin 
10308353fccSChris Fallin     /// For each safepoint entry in `safepoint_insns`, a list of `SpillSlot`s.
10408353fccSChris Fallin     /// These are used to generate actual stack maps at emission. Filled in
10508353fccSChris Fallin     /// post-regalloc.
10608353fccSChris Fallin     safepoint_slots: Vec<Vec<SpillSlot>>,
107de4af90aSYury Delendik 
108c84d6be6SChris Fallin     /// Do we generate debug info?
109c84d6be6SChris Fallin     generate_debug_info: bool,
110c84d6be6SChris Fallin 
111d9d64694SChris Fallin     /// Instruction end offsets, instruction indices at each label,
112d9d64694SChris Fallin     /// total buffer size, and start of cold code.  Only present if
113d9d64694SChris Fallin     /// `generate_debug_info` is set.
114d9d64694SChris Fallin     insts_layout: RefCell<InstsLayoutInfo>,
11583f182b3SAndrew Brown 
11683f182b3SAndrew Brown     /// Constants.
11783f182b3SAndrew Brown     constants: VCodeConstants,
118997fab55SChris Fallin 
119997fab55SChris Fallin     /// Are any debug value-labels present? If not, we can skip the
120997fab55SChris Fallin     /// post-emission analysis.
121997fab55SChris Fallin     has_value_labels: bool,
122d8357426SChris Fallin }
123d8357426SChris Fallin 
124d9d64694SChris Fallin #[derive(Debug, Default)]
125d9d64694SChris Fallin pub(crate) struct InstsLayoutInfo {
126d9d64694SChris Fallin     pub(crate) inst_end_offsets: Vec<CodeOffset>,
127d9d64694SChris Fallin     pub(crate) label_inst_indices: Vec<CodeOffset>,
128d9d64694SChris Fallin     pub(crate) start_of_cold_code: Option<CodeOffset>,
129d9d64694SChris Fallin }
130d9d64694SChris Fallin 
131d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the
132d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward
133d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from
134d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse
135d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again.
136d8357426SChris Fallin ///
137d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two
138d8357426SChris Fallin /// swaps.  First, the machine instructions (`I` instances) are produced in
139d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed*
140d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering.
141d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic
142d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we
143d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto
144d8357426SChris Fallin /// the VCode's insts.
145d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> {
146d8357426SChris Fallin     /// In-progress VCode.
147d8357426SChris Fallin     vcode: VCode<I>,
148d8357426SChris Fallin 
14908353fccSChris Fallin     /// In-progress stack map-request info.
15005bf9ea3SNick Fitzgerald     stack_map_info: StackmapRequestInfo,
15108353fccSChris Fallin 
15272e6be93SChris Fallin     /// Index of the last block-start in the vcode.
15372e6be93SChris Fallin     block_start: InsnIndex,
154d8357426SChris Fallin 
155d8357426SChris Fallin     /// Start of succs for the current block in the concatenated succs list.
156d8357426SChris Fallin     succ_start: usize,
157b691770fSChris Fallin 
158b691770fSChris Fallin     /// Current source location.
159b691770fSChris Fallin     cur_srcloc: SourceLoc,
160d8357426SChris Fallin }
161d8357426SChris Fallin 
162d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> {
163d8357426SChris Fallin     /// Create a new VCodeBuilder.
164c5bbc874SBenjamin Bouvier     pub fn new(
165c5bbc874SBenjamin Bouvier         abi: Box<dyn ABICallee<I = I>>,
166c5bbc874SBenjamin Bouvier         emit_info: I::Info,
167c5bbc874SBenjamin Bouvier         block_order: BlockLoweringOrder,
16883f182b3SAndrew Brown         constants: VCodeConstants,
169c5bbc874SBenjamin Bouvier     ) -> VCodeBuilder<I> {
17026529006SChris Fallin         let reftype_class = I::ref_type_regclass(abi.flags());
171c84d6be6SChris Fallin         let vcode = VCode::new(
172c84d6be6SChris Fallin             abi,
173c84d6be6SChris Fallin             emit_info,
174c84d6be6SChris Fallin             block_order,
175c84d6be6SChris Fallin             constants,
176c84d6be6SChris Fallin             /* generate_debug_info = */ true,
177c84d6be6SChris Fallin         );
17805bf9ea3SNick Fitzgerald         let stack_map_info = StackmapRequestInfo {
17908353fccSChris Fallin             reftype_class,
18008353fccSChris Fallin             reftyped_vregs: vec![],
18108353fccSChris Fallin             safepoint_insns: vec![],
18208353fccSChris Fallin         };
18308353fccSChris Fallin 
184d8357426SChris Fallin         VCodeBuilder {
185d8357426SChris Fallin             vcode,
18605bf9ea3SNick Fitzgerald             stack_map_info,
18772e6be93SChris Fallin             block_start: 0,
188d8357426SChris Fallin             succ_start: 0,
189b691770fSChris Fallin             cur_srcloc: SourceLoc::default(),
190d8357426SChris Fallin         }
191d8357426SChris Fallin     }
192d8357426SChris Fallin 
193d8357426SChris Fallin     /// Access the ABI object.
194e8f772c1SChris Fallin     pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> {
195d8357426SChris Fallin         &mut *self.vcode.abi
196d8357426SChris Fallin     }
197d8357426SChris Fallin 
19872e6be93SChris Fallin     /// Access to the BlockLoweringOrder object.
19972e6be93SChris Fallin     pub fn block_order(&self) -> &BlockLoweringOrder {
20072e6be93SChris Fallin         &self.vcode.block_order
2011d90751bSBenjamin Bouvier     }
2021d90751bSBenjamin Bouvier 
203d8357426SChris Fallin     /// Set the type of a VReg.
204d8357426SChris Fallin     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
20548f0b10cSJohnnie Birch         if self.vcode.vreg_types.len() <= vreg.get_index() {
206ef5de04dSBenjamin Bouvier             self.vcode
207ef5de04dSBenjamin Bouvier                 .vreg_types
208ef5de04dSBenjamin Bouvier                 .resize(vreg.get_index() + 1, ir::types::I8);
209d8357426SChris Fallin         }
210d8357426SChris Fallin         self.vcode.vreg_types[vreg.get_index()] = ty;
21108353fccSChris Fallin         if is_reftype(ty) {
21205bf9ea3SNick Fitzgerald             self.stack_map_info.reftyped_vregs.push(vreg);
21308353fccSChris Fallin             self.vcode.have_ref_values = true;
21408353fccSChris Fallin         }
21508353fccSChris Fallin     }
21608353fccSChris Fallin 
217d8357426SChris Fallin     /// Set the current block as the entry block.
218d8357426SChris Fallin     pub fn set_entry(&mut self, block: BlockIndex) {
219d8357426SChris Fallin         self.vcode.entry = block;
220d8357426SChris Fallin     }
221d8357426SChris Fallin 
222d8357426SChris Fallin     /// End the current basic block. Must be called after emitting vcode insts
223d8357426SChris Fallin     /// for IR insts and prior to ending the function (building the VCode).
22472e6be93SChris Fallin     pub fn end_bb(&mut self) {
22572e6be93SChris Fallin         let start_idx = self.block_start;
226d8357426SChris Fallin         let end_idx = self.vcode.insts.len() as InsnIndex;
22772e6be93SChris Fallin         self.block_start = end_idx;
228d8357426SChris Fallin         // Add the instruction index range to the list of blocks.
229d8357426SChris Fallin         self.vcode.block_ranges.push((start_idx, end_idx));
230d8357426SChris Fallin         // End the successors list.
231d8357426SChris Fallin         let succ_end = self.vcode.block_succs.len();
232d8357426SChris Fallin         self.vcode
233d8357426SChris Fallin             .block_succ_range
234d8357426SChris Fallin             .push((self.succ_start, succ_end));
235d8357426SChris Fallin         self.succ_start = succ_end;
236d8357426SChris Fallin     }
237d8357426SChris Fallin 
238d8357426SChris Fallin     /// Push an instruction for the current BB and current IR inst within the BB.
23908353fccSChris Fallin     pub fn push(&mut self, insn: I, is_safepoint: bool) {
240d8357426SChris Fallin         match insn.is_term() {
241d8357426SChris Fallin             MachTerminator::None | MachTerminator::Ret => {}
242d8357426SChris Fallin             MachTerminator::Uncond(target) => {
24372e6be93SChris Fallin                 self.vcode.block_succs.push(BlockIx::new(target.get()));
244d8357426SChris Fallin             }
245d8357426SChris Fallin             MachTerminator::Cond(true_branch, false_branch) => {
24672e6be93SChris Fallin                 self.vcode.block_succs.push(BlockIx::new(true_branch.get()));
24772e6be93SChris Fallin                 self.vcode
24872e6be93SChris Fallin                     .block_succs
24972e6be93SChris Fallin                     .push(BlockIx::new(false_branch.get()));
250d8357426SChris Fallin             }
251d8357426SChris Fallin             MachTerminator::Indirect(targets) => {
252d8357426SChris Fallin                 for target in targets {
25372e6be93SChris Fallin                     self.vcode.block_succs.push(BlockIx::new(target.get()));
254d8357426SChris Fallin                 }
255d8357426SChris Fallin             }
256d8357426SChris Fallin         }
257997fab55SChris Fallin         if insn.defines_value_label().is_some() {
258997fab55SChris Fallin             self.vcode.has_value_labels = true;
259997fab55SChris Fallin         }
26072e6be93SChris Fallin         self.vcode.insts.push(insn);
26172e6be93SChris Fallin         self.vcode.srclocs.push(self.cur_srcloc);
26208353fccSChris Fallin         if is_safepoint {
26305bf9ea3SNick Fitzgerald             self.stack_map_info
26408353fccSChris Fallin                 .safepoint_insns
26508353fccSChris Fallin                 .push(InstIx::new((self.vcode.insts.len() - 1) as u32));
26608353fccSChris Fallin         }
26772e6be93SChris Fallin     }
26872e6be93SChris Fallin 
269b691770fSChris Fallin     /// Set the current source location.
270b691770fSChris Fallin     pub fn set_srcloc(&mut self, srcloc: SourceLoc) {
271b691770fSChris Fallin         self.cur_srcloc = srcloc;
272d8357426SChris Fallin     }
273d8357426SChris Fallin 
27483f182b3SAndrew Brown     /// Access the constants.
27583f182b3SAndrew Brown     pub fn constants(&mut self) -> &mut VCodeConstants {
27683f182b3SAndrew Brown         &mut self.vcode.constants
27783f182b3SAndrew Brown     }
27883f182b3SAndrew Brown 
27908353fccSChris Fallin     /// Build the final VCode, returning the vcode itself as well as auxiliary
28008353fccSChris Fallin     /// information, such as the stack map request information.
28108353fccSChris Fallin     pub fn build(self) -> (VCode<I>, StackmapRequestInfo) {
28208353fccSChris Fallin         // TODO: come up with an abstraction for "vcode and auxiliary data". The
28308353fccSChris Fallin         // auxiliary data needs to be separate from the vcode so that it can be
28408353fccSChris Fallin         // referenced as the vcode is mutated (e.g. by the register allocator).
28505bf9ea3SNick Fitzgerald         (self.vcode, self.stack_map_info)
286d8357426SChris Fallin     }
287d8357426SChris Fallin }
288d8357426SChris Fallin 
289d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool {
290d8357426SChris Fallin     if let Some((to, from)) = insn.is_move() {
291d8357426SChris Fallin         to.to_reg() == from
292d8357426SChris Fallin     } else {
293d8357426SChris Fallin         false
294d8357426SChris Fallin     }
295d8357426SChris Fallin }
296d8357426SChris Fallin 
29708353fccSChris Fallin /// Is this type a reference type?
29808353fccSChris Fallin fn is_reftype(ty: Type) -> bool {
29926529006SChris Fallin     ty == types::R64 || ty == types::R32
30008353fccSChris Fallin }
30108353fccSChris Fallin 
302d8357426SChris Fallin impl<I: VCodeInst> VCode<I> {
303d8357426SChris Fallin     /// New empty VCode.
304c5bbc874SBenjamin Bouvier     fn new(
305c5bbc874SBenjamin Bouvier         abi: Box<dyn ABICallee<I = I>>,
306c5bbc874SBenjamin Bouvier         emit_info: I::Info,
307c5bbc874SBenjamin Bouvier         block_order: BlockLoweringOrder,
30883f182b3SAndrew Brown         constants: VCodeConstants,
309c84d6be6SChris Fallin         generate_debug_info: bool,
310c5bbc874SBenjamin Bouvier     ) -> VCode<I> {
311d8357426SChris Fallin         VCode {
312d8357426SChris Fallin             liveins: abi.liveins(),
313d8357426SChris Fallin             liveouts: abi.liveouts(),
314d8357426SChris Fallin             vreg_types: vec![],
31508353fccSChris Fallin             have_ref_values: false,
316d8357426SChris Fallin             insts: vec![],
317b691770fSChris Fallin             srclocs: vec![],
318d8357426SChris Fallin             entry: 0,
319d8357426SChris Fallin             block_ranges: vec![],
320d8357426SChris Fallin             block_succ_range: vec![],
321d8357426SChris Fallin             block_succs: vec![],
32272e6be93SChris Fallin             block_order,
323d8357426SChris Fallin             abi,
324c5bbc874SBenjamin Bouvier             emit_info,
32508353fccSChris Fallin             safepoint_insns: vec![],
32608353fccSChris Fallin             safepoint_slots: vec![],
327c84d6be6SChris Fallin             generate_debug_info,
328d9d64694SChris Fallin             insts_layout: RefCell::new(Default::default()),
32983f182b3SAndrew Brown             constants,
330997fab55SChris Fallin             has_value_labels: false,
331d8357426SChris Fallin         }
332d8357426SChris Fallin     }
333d8357426SChris Fallin 
334d1b5df31SBenjamin Bouvier     /// Returns the flags controlling this function's compilation.
335d1b5df31SBenjamin Bouvier     pub fn flags(&self) -> &settings::Flags {
336d1b5df31SBenjamin Bouvier         self.abi.flags()
337d1b5df31SBenjamin Bouvier     }
338d1b5df31SBenjamin Bouvier 
339d8357426SChris Fallin     /// Get the IR-level type of a VReg.
340d8357426SChris Fallin     pub fn vreg_type(&self, vreg: VirtualReg) -> Type {
341d8357426SChris Fallin         self.vreg_types[vreg.get_index()]
342d8357426SChris Fallin     }
343d8357426SChris Fallin 
344d8357426SChris Fallin     /// Get the number of blocks. Block indices will be in the range `0 ..
345d8357426SChris Fallin     /// (self.num_blocks() - 1)`.
346d8357426SChris Fallin     pub fn num_blocks(&self) -> usize {
347d8357426SChris Fallin         self.block_ranges.len()
348d8357426SChris Fallin     }
349d8357426SChris Fallin 
350d8357426SChris Fallin     /// Stack frame size for the full function's body.
351d8357426SChris Fallin     pub fn frame_size(&self) -> u32 {
352d8357426SChris Fallin         self.abi.frame_size()
353d8357426SChris Fallin     }
354d8357426SChris Fallin 
355d8357426SChris Fallin     /// Get the successors for a block.
3564f919c64SBenjamin Bouvier     pub fn succs(&self, block: BlockIndex) -> &[BlockIx] {
357d8357426SChris Fallin         let (start, end) = self.block_succ_range[block as usize];
358d8357426SChris Fallin         &self.block_succs[start..end]
359d8357426SChris Fallin     }
360d8357426SChris Fallin 
361d8357426SChris Fallin     /// Take the results of register allocation, with a sequence of
362d8357426SChris Fallin     /// instructions including spliced fill/reload/move instructions, and replace
363d8357426SChris Fallin     /// the VCode with them.
364d1b5df31SBenjamin Bouvier     pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) {
365d8357426SChris Fallin         // Record the spillslot count and clobbered registers for the ABI/stack
366d8357426SChris Fallin         // setup code.
367d8357426SChris Fallin         self.abi.set_num_spillslots(result.num_spill_slots as usize);
368d8357426SChris Fallin         self.abi
369d8357426SChris Fallin             .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r)));
370d8357426SChris Fallin 
371d8357426SChris Fallin         let mut final_insns = vec![];
372d8357426SChris Fallin         let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
373b691770fSChris Fallin         let mut final_srclocs = vec![];
37408353fccSChris Fallin         let mut final_safepoint_insns = vec![];
37508353fccSChris Fallin         let mut safept_idx = 0;
376d8357426SChris Fallin 
37708353fccSChris Fallin         assert!(result.target_map.elems().len() == self.num_blocks());
37872e6be93SChris Fallin         for block in 0..self.num_blocks() {
37908353fccSChris Fallin             let start = result.target_map.elems()[block].get() as usize;
38008353fccSChris Fallin             let end = if block == self.num_blocks() - 1 {
38108353fccSChris Fallin                 result.insns.len()
38208353fccSChris Fallin             } else {
38308353fccSChris Fallin                 result.target_map.elems()[block + 1].get() as usize
38408353fccSChris Fallin             };
38572e6be93SChris Fallin             let block = block as BlockIndex;
386d8357426SChris Fallin             let final_start = final_insns.len() as InsnIndex;
387d8357426SChris Fallin 
38872e6be93SChris Fallin             if block == self.entry {
389d8357426SChris Fallin                 // Start with the prologue.
390b691770fSChris Fallin                 let prologue = self.abi.gen_prologue();
391b691770fSChris Fallin                 let len = prologue.len();
392b691770fSChris Fallin                 final_insns.extend(prologue.into_iter());
393b691770fSChris Fallin                 final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len));
394d8357426SChris Fallin             }
395d8357426SChris Fallin 
396d8357426SChris Fallin             for i in start..end {
397d8357426SChris Fallin                 let insn = &result.insns[i];
398d8357426SChris Fallin 
399d8357426SChris Fallin                 // Elide redundant moves at this point (we only know what is
400d8357426SChris Fallin                 // redundant once registers are allocated).
401d8357426SChris Fallin                 if is_redundant_move(insn) {
402d8357426SChris Fallin                     continue;
403d8357426SChris Fallin                 }
404d8357426SChris Fallin 
405b691770fSChris Fallin                 // Is there a srcloc associated with this insn? Look it up based on original
406b691770fSChris Fallin                 // instruction index (if new insn corresponds to some original insn, i.e., is not
407b691770fSChris Fallin                 // an inserted load/spill/move).
408b691770fSChris Fallin                 let orig_iix = result.orig_insn_map[InstIx::new(i as u32)];
409b691770fSChris Fallin                 let srcloc = if orig_iix.is_invalid() {
410b691770fSChris Fallin                     SourceLoc::default()
411b691770fSChris Fallin                 } else {
412b691770fSChris Fallin                     self.srclocs[orig_iix.get() as usize]
413b691770fSChris Fallin                 };
414b691770fSChris Fallin 
415d8357426SChris Fallin                 // Whenever encountering a return instruction, replace it
416d8357426SChris Fallin                 // with the epilogue.
417d8357426SChris Fallin                 let is_ret = insn.is_term() == MachTerminator::Ret;
418d8357426SChris Fallin                 if is_ret {
419b691770fSChris Fallin                     let epilogue = self.abi.gen_epilogue();
420b691770fSChris Fallin                     let len = epilogue.len();
421b691770fSChris Fallin                     final_insns.extend(epilogue.into_iter());
422b691770fSChris Fallin                     final_srclocs.extend(iter::repeat(srcloc).take(len));
423d8357426SChris Fallin                 } else {
424d8357426SChris Fallin                     final_insns.push(insn.clone());
425b691770fSChris Fallin                     final_srclocs.push(srcloc);
426d8357426SChris Fallin                 }
42708353fccSChris Fallin 
42808353fccSChris Fallin                 // Was this instruction a safepoint instruction? Add its final
42908353fccSChris Fallin                 // index to the safepoint insn-index list if so.
43008353fccSChris Fallin                 if safept_idx < result.new_safepoint_insns.len()
43108353fccSChris Fallin                     && (result.new_safepoint_insns[safept_idx].get() as usize) == i
43208353fccSChris Fallin                 {
43308353fccSChris Fallin                     let idx = final_insns.len() - 1;
43408353fccSChris Fallin                     final_safepoint_insns.push(idx as InsnIndex);
43508353fccSChris Fallin                     safept_idx += 1;
43608353fccSChris Fallin                 }
437d8357426SChris Fallin             }
438d8357426SChris Fallin 
439d8357426SChris Fallin             let final_end = final_insns.len() as InsnIndex;
44072e6be93SChris Fallin             final_block_ranges[block as usize] = (final_start, final_end);
441d8357426SChris Fallin         }
442d8357426SChris Fallin 
443b691770fSChris Fallin         debug_assert!(final_insns.len() == final_srclocs.len());
444b691770fSChris Fallin 
445d8357426SChris Fallin         self.insts = final_insns;
446b691770fSChris Fallin         self.srclocs = final_srclocs;
447d8357426SChris Fallin         self.block_ranges = final_block_ranges;
44808353fccSChris Fallin         self.safepoint_insns = final_safepoint_insns;
44908353fccSChris Fallin 
45008353fccSChris Fallin         // Save safepoint slot-lists. These will be passed to the `EmitState`
45108353fccSChris Fallin         // for the machine backend during emission so that it can do
45208353fccSChris Fallin         // target-specific translations of slot numbers to stack offsets.
45308353fccSChris Fallin         self.safepoint_slots = result.stackmaps;
454d8357426SChris Fallin     }
455d8357426SChris Fallin 
45672e6be93SChris Fallin     /// Emit the instructions to a `MachBuffer`, containing fixed-up code and external
45772e6be93SChris Fallin     /// reloc/trap/etc. records ready for use.
45811a2ef01SChris Fallin     pub fn emit(
45911a2ef01SChris Fallin         &self,
46011a2ef01SChris Fallin     ) -> (
46111a2ef01SChris Fallin         MachBuffer<I>,
46211a2ef01SChris Fallin         Vec<CodeOffset>,
46311a2ef01SChris Fallin         Vec<(CodeOffset, CodeOffset)>,
46411a2ef01SChris Fallin     )
465d8357426SChris Fallin     where
46672e6be93SChris Fallin         I: MachInstEmit,
467d8357426SChris Fallin     {
4682b9fefe8SChris Fallin         let _tt = timing::vcode_emit();
46972e6be93SChris Fallin         let mut buffer = MachBuffer::new();
47008353fccSChris Fallin         let mut state = I::State::new(&*self.abi);
471800cf25bSChris Fallin         let cfg_metadata = self.flags().machine_code_cfg_info();
47211a2ef01SChris Fallin         let mut bb_starts: Vec<Option<CodeOffset>> = vec![];
473d8357426SChris Fallin 
47483f182b3SAndrew Brown         // The first M MachLabels are reserved for block indices, the next N MachLabels for
47583f182b3SAndrew Brown         // constants.
47683f182b3SAndrew Brown         buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex);
47783f182b3SAndrew Brown         buffer.reserve_labels_for_constants(&self.constants);
478d8357426SChris Fallin 
479d9d64694SChris Fallin         let mut inst_end_offsets = vec![0; self.insts.len()];
480d9d64694SChris Fallin         let mut label_inst_indices = vec![0; self.num_blocks()];
481de4af90aSYury Delendik 
482*666c2554SChris Fallin         // Map from instruction index to index in
483*666c2554SChris Fallin         // `safepoint_slots`. We need this because we emit
484*666c2554SChris Fallin         // instructions out-of-order, while the safepoint_insns /
485*666c2554SChris Fallin         // safepoint_slots data structures are sorted in instruction
486*666c2554SChris Fallin         // order.
487*666c2554SChris Fallin         let mut safepoint_indices: FxHashMap<u32, usize> = FxHashMap::default();
488*666c2554SChris Fallin         for (safepoint_idx, iix) in self.safepoint_insns.iter().enumerate() {
489*666c2554SChris Fallin             // Disregard safepoints that ended up having no live refs.
490*666c2554SChris Fallin             if self.safepoint_slots[safepoint_idx].len() > 0 {
491*666c2554SChris Fallin                 safepoint_indices.insert(*iix, safepoint_idx);
492*666c2554SChris Fallin             }
493*666c2554SChris Fallin         }
494*666c2554SChris Fallin 
495ef1b2d2fSChris Fallin         // Construct the final order we emit code in: cold blocks at the end.
496ef1b2d2fSChris Fallin         let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![];
497ef1b2d2fSChris Fallin         let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![];
498ef1b2d2fSChris Fallin         for block in 0..self.num_blocks() {
499ef1b2d2fSChris Fallin             let block = block as BlockIndex;
500ef1b2d2fSChris Fallin             if self.block_order.is_cold(block) {
501ef1b2d2fSChris Fallin                 cold_blocks.push(block);
502ef1b2d2fSChris Fallin             } else {
503ef1b2d2fSChris Fallin                 final_order.push(block);
504ef1b2d2fSChris Fallin             }
505ef1b2d2fSChris Fallin         }
506d9d64694SChris Fallin         let first_cold_block = cold_blocks.first().cloned();
507d9d64694SChris Fallin         final_order.extend(cold_blocks.clone());
508ef1b2d2fSChris Fallin 
509ef1b2d2fSChris Fallin         // Emit blocks.
510964c6087SChris Fallin         let mut cur_srcloc = None;
51111a2ef01SChris Fallin         let mut last_offset = None;
512d9d64694SChris Fallin         let mut start_of_cold_code = None;
513ef1b2d2fSChris Fallin         for block in final_order {
51472e6be93SChris Fallin             let new_offset = I::align_basic_block(buffer.cur_offset());
51572e6be93SChris Fallin             while new_offset > buffer.cur_offset() {
516d8357426SChris Fallin                 // Pad with NOPs up to the aligned block offset.
51772e6be93SChris Fallin                 let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
518c5bbc874SBenjamin Bouvier                 nop.emit(&mut buffer, &self.emit_info, &mut Default::default());
519d8357426SChris Fallin             }
52072e6be93SChris Fallin             assert_eq!(buffer.cur_offset(), new_offset);
521d8357426SChris Fallin 
522d9d64694SChris Fallin             if Some(block) == first_cold_block {
523d9d64694SChris Fallin                 start_of_cold_code = Some(buffer.cur_offset());
524d9d64694SChris Fallin             }
525d9d64694SChris Fallin 
52648cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
52772e6be93SChris Fallin             buffer.bind_label(MachLabel::from_block(block));
528d9d64694SChris Fallin             label_inst_indices[block as usize] = start;
52911a2ef01SChris Fallin 
530800cf25bSChris Fallin             if cfg_metadata {
53111a2ef01SChris Fallin                 // Track BB starts. If we have backed up due to MachBuffer
53211a2ef01SChris Fallin                 // branch opts, note that the removed blocks were removed.
53311a2ef01SChris Fallin                 let cur_offset = buffer.cur_offset();
53411a2ef01SChris Fallin                 if last_offset.is_some() && cur_offset <= last_offset.unwrap() {
53511a2ef01SChris Fallin                     for i in (0..bb_starts.len()).rev() {
53611a2ef01SChris Fallin                         if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() {
53711a2ef01SChris Fallin                             break;
53811a2ef01SChris Fallin                         }
53911a2ef01SChris Fallin                         bb_starts[i] = None;
54011a2ef01SChris Fallin                     }
54111a2ef01SChris Fallin                 }
54211a2ef01SChris Fallin                 bb_starts.push(Some(cur_offset));
54311a2ef01SChris Fallin                 last_offset = Some(cur_offset);
544800cf25bSChris Fallin             }
54511a2ef01SChris Fallin 
546d8357426SChris Fallin             for iix in start..end {
547b691770fSChris Fallin                 let srcloc = self.srclocs[iix as usize];
548964c6087SChris Fallin                 if cur_srcloc != Some(srcloc) {
549964c6087SChris Fallin                     if cur_srcloc.is_some() {
55072e6be93SChris Fallin                         buffer.end_srcloc();
551b691770fSChris Fallin                     }
55272e6be93SChris Fallin                     buffer.start_srcloc(srcloc);
553964c6087SChris Fallin                     cur_srcloc = Some(srcloc);
554b691770fSChris Fallin                 }
5554dce5109SChris Fallin                 state.pre_sourceloc(cur_srcloc.unwrap_or(SourceLoc::default()));
556b691770fSChris Fallin 
557*666c2554SChris Fallin                 if let Some(safepoint_idx) = safepoint_indices.get(&iix) {
558*666c2554SChris Fallin                     let stack_map = self
559*666c2554SChris Fallin                         .abi
560*666c2554SChris Fallin                         .spillslots_to_stack_map(&self.safepoint_slots[*safepoint_idx][..], &state);
56105bf9ea3SNick Fitzgerald                     state.pre_safepoint(stack_map);
56208353fccSChris Fallin                 }
56308353fccSChris Fallin 
564c5bbc874SBenjamin Bouvier                 self.insts[iix as usize].emit(&mut buffer, &self.emit_info, &mut state);
565de4af90aSYury Delendik 
566c84d6be6SChris Fallin                 if self.generate_debug_info {
567c84d6be6SChris Fallin                     // Buffer truncation may have happened since last inst append; trim inst-end
568c84d6be6SChris Fallin                     // layout info as appropriate.
569d9d64694SChris Fallin                     let l = &mut inst_end_offsets[0..iix as usize];
570c84d6be6SChris Fallin                     for end in l.iter_mut().rev() {
571c84d6be6SChris Fallin                         if *end > buffer.cur_offset() {
572c84d6be6SChris Fallin                             *end = buffer.cur_offset();
573c84d6be6SChris Fallin                         } else {
574c84d6be6SChris Fallin                             break;
575c84d6be6SChris Fallin                         }
576c84d6be6SChris Fallin                     }
577d9d64694SChris Fallin                     inst_end_offsets[iix as usize] = buffer.cur_offset();
578c84d6be6SChris Fallin                 }
579d8357426SChris Fallin             }
580b691770fSChris Fallin 
581964c6087SChris Fallin             if cur_srcloc.is_some() {
58272e6be93SChris Fallin                 buffer.end_srcloc();
583964c6087SChris Fallin                 cur_srcloc = None;
584b691770fSChris Fallin             }
58572e6be93SChris Fallin 
58672e6be93SChris Fallin             // Do we need an island? Get the worst-case size of the next BB and see if, having
58772e6be93SChris Fallin             // emitted that many bytes, we will be beyond the deadline.
58872e6be93SChris Fallin             if block < (self.num_blocks() - 1) as BlockIndex {
58972e6be93SChris Fallin                 let next_block = block + 1;
59072e6be93SChris Fallin                 let next_block_range = self.block_ranges[next_block as usize];
59172e6be93SChris Fallin                 let next_block_size = next_block_range.1 - next_block_range.0;
59272e6be93SChris Fallin                 let worst_case_next_bb = I::worst_case_size() * next_block_size;
59372e6be93SChris Fallin                 if buffer.island_needed(worst_case_next_bb) {
5941532516aSAlex Crichton                     buffer.emit_island(worst_case_next_bb);
59572e6be93SChris Fallin                 }
59672e6be93SChris Fallin             }
597d8357426SChris Fallin         }
598d8357426SChris Fallin 
59983f182b3SAndrew Brown         // Emit the constants used by the function.
60083f182b3SAndrew Brown         for (constant, data) in self.constants.iter() {
60183f182b3SAndrew Brown             let label = buffer.get_label_for_constant(constant);
60283f182b3SAndrew Brown             buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value());
60383f182b3SAndrew Brown         }
60483f182b3SAndrew Brown 
605c84d6be6SChris Fallin         if self.generate_debug_info {
606d9d64694SChris Fallin             for end in inst_end_offsets.iter_mut().rev() {
607c84d6be6SChris Fallin                 if *end > buffer.cur_offset() {
608c84d6be6SChris Fallin                     *end = buffer.cur_offset();
609c84d6be6SChris Fallin                 } else {
610c84d6be6SChris Fallin                     break;
611c84d6be6SChris Fallin                 }
612c84d6be6SChris Fallin             }
613d9d64694SChris Fallin             *self.insts_layout.borrow_mut() = InstsLayoutInfo {
614d9d64694SChris Fallin                 inst_end_offsets,
615d9d64694SChris Fallin                 label_inst_indices,
616d9d64694SChris Fallin                 start_of_cold_code,
617d9d64694SChris Fallin             };
618c84d6be6SChris Fallin         }
619de4af90aSYury Delendik 
62011a2ef01SChris Fallin         // Create `bb_edges` and final (filtered) `bb_starts`.
62111a2ef01SChris Fallin         let mut final_bb_starts = vec![];
62211a2ef01SChris Fallin         let mut bb_edges = vec![];
623800cf25bSChris Fallin         if cfg_metadata {
62411a2ef01SChris Fallin             for block in 0..self.num_blocks() {
62511a2ef01SChris Fallin                 if bb_starts[block].is_none() {
62611a2ef01SChris Fallin                     // Block was deleted by MachBuffer; skip.
62711a2ef01SChris Fallin                     continue;
62811a2ef01SChris Fallin                 }
62911a2ef01SChris Fallin                 let from = bb_starts[block].unwrap();
63011a2ef01SChris Fallin 
63111a2ef01SChris Fallin                 final_bb_starts.push(from);
63211a2ef01SChris Fallin                 // Resolve each `succ` label and add edges.
63311a2ef01SChris Fallin                 let succs = self.block_succs(BlockIx::new(block as u32));
63411a2ef01SChris Fallin                 for succ in succs.iter() {
63511a2ef01SChris Fallin                     let to = buffer.resolve_label_offset(MachLabel::from_block(succ.get()));
63611a2ef01SChris Fallin                     bb_edges.push((from, to));
63711a2ef01SChris Fallin                 }
63811a2ef01SChris Fallin             }
639800cf25bSChris Fallin         }
64011a2ef01SChris Fallin 
64111a2ef01SChris Fallin         (buffer, final_bb_starts, bb_edges)
642d8357426SChris Fallin     }
643d8357426SChris Fallin 
644c84d6be6SChris Fallin     /// Generates value-label ranges.
645602006ffSbjorn3     pub fn value_labels_ranges(&self) -> ValueLabelsRanges {
646997fab55SChris Fallin         if !self.has_value_labels {
647602006ffSbjorn3             return ValueLabelsRanges::default();
648997fab55SChris Fallin         }
649997fab55SChris Fallin 
650d9d64694SChris Fallin         let layout_info = &self.insts_layout.borrow();
651d9d64694SChris Fallin         debug::compute(&self.insts, &*layout_info)
65276d61504Sbjorn3     }
65376d61504Sbjorn3 
65476d61504Sbjorn3     /// Get the offsets of stackslots.
65576d61504Sbjorn3     pub fn stackslot_offsets(&self) -> &PrimaryMap<StackSlot, u32> {
65676d61504Sbjorn3         self.abi.stackslot_offsets()
657c84d6be6SChris Fallin     }
658c84d6be6SChris Fallin 
659d8357426SChris Fallin     /// Get the IR block for a BlockIndex, if one exists.
660d8357426SChris Fallin     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
66172e6be93SChris Fallin         self.block_order.lowered_order()[block as usize].orig_block()
662d8357426SChris Fallin     }
663d8357426SChris Fallin }
664d8357426SChris Fallin 
665d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> {
666d8357426SChris Fallin     type Inst = I;
667d8357426SChris Fallin 
668d8357426SChris Fallin     fn insns(&self) -> &[I] {
669d8357426SChris Fallin         &self.insts[..]
670d8357426SChris Fallin     }
671d8357426SChris Fallin 
672d8357426SChris Fallin     fn insns_mut(&mut self) -> &mut [I] {
673d8357426SChris Fallin         &mut self.insts[..]
674d8357426SChris Fallin     }
675d8357426SChris Fallin 
676d8357426SChris Fallin     fn get_insn(&self, insn: InstIx) -> &I {
677d8357426SChris Fallin         &self.insts[insn.get() as usize]
678d8357426SChris Fallin     }
679d8357426SChris Fallin 
680d8357426SChris Fallin     fn get_insn_mut(&mut self, insn: InstIx) -> &mut I {
681d8357426SChris Fallin         &mut self.insts[insn.get() as usize]
682d8357426SChris Fallin     }
683d8357426SChris Fallin 
684d8357426SChris Fallin     fn blocks(&self) -> Range<BlockIx> {
685d8357426SChris Fallin         Range::new(BlockIx::new(0), self.block_ranges.len())
686d8357426SChris Fallin     }
687d8357426SChris Fallin 
688d8357426SChris Fallin     fn entry_block(&self) -> BlockIx {
689d8357426SChris Fallin         BlockIx::new(self.entry)
690d8357426SChris Fallin     }
691d8357426SChris Fallin 
692d8357426SChris Fallin     fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
693d8357426SChris Fallin         let (start, end) = self.block_ranges[block.get() as usize];
694d8357426SChris Fallin         Range::new(InstIx::new(start), (end - start) as usize)
695d8357426SChris Fallin     }
696d8357426SChris Fallin 
6974f919c64SBenjamin Bouvier     fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> {
698d8357426SChris Fallin         let (start, end) = self.block_succ_range[block.get() as usize];
6994f919c64SBenjamin Bouvier         Cow::Borrowed(&self.block_succs[start..end])
700d8357426SChris Fallin     }
701d8357426SChris Fallin 
702d8357426SChris Fallin     fn is_ret(&self, insn: InstIx) -> bool {
703d8357426SChris Fallin         match self.insts[insn.get() as usize].is_term() {
704d8357426SChris Fallin             MachTerminator::Ret => true,
705d8357426SChris Fallin             _ => false,
706d8357426SChris Fallin         }
707d8357426SChris Fallin     }
708d8357426SChris Fallin 
70971768bb6SChris Fallin     fn is_included_in_clobbers(&self, insn: &I) -> bool {
71071768bb6SChris Fallin         insn.is_included_in_clobbers()
71171768bb6SChris Fallin     }
71271768bb6SChris Fallin 
713d8357426SChris Fallin     fn get_regs(insn: &I, collector: &mut RegUsageCollector) {
714d8357426SChris Fallin         insn.get_regs(collector)
715d8357426SChris Fallin     }
716d8357426SChris Fallin 
7171f620e1bSBenjamin Bouvier     fn map_regs<RUM: RegUsageMapper>(insn: &mut I, mapper: &RUM) {
718be6f060aSChris Fallin         insn.map_regs(mapper);
719d8357426SChris Fallin     }
720d8357426SChris Fallin 
721d8357426SChris Fallin     fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> {
722d8357426SChris Fallin         insn.is_move()
723d8357426SChris Fallin     }
724d8357426SChris Fallin 
72546093f61SBenjamin Bouvier     fn get_num_vregs(&self) -> usize {
72646093f61SBenjamin Bouvier         self.vreg_types.len()
727be6f060aSChris Fallin     }
728be6f060aSChris Fallin 
729833ebeedSChris Fallin     fn get_spillslot_size(&self, regclass: RegClass, _: VirtualReg) -> u32 {
730833ebeedSChris Fallin         self.abi.get_spillslot_size(regclass)
731d8357426SChris Fallin     }
732d8357426SChris Fallin 
733833ebeedSChris Fallin     fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, _: Option<VirtualReg>) -> I {
734833ebeedSChris Fallin         self.abi.gen_spill(to_slot, from_reg)
735d8357426SChris Fallin     }
736d8357426SChris Fallin 
73708353fccSChris Fallin     fn gen_reload(
73808353fccSChris Fallin         &self,
73908353fccSChris Fallin         to_reg: Writable<RealReg>,
74008353fccSChris Fallin         from_slot: SpillSlot,
741833ebeedSChris Fallin         _: Option<VirtualReg>,
74208353fccSChris Fallin     ) -> I {
743833ebeedSChris Fallin         self.abi.gen_reload(to_reg, from_slot)
744d8357426SChris Fallin     }
745d8357426SChris Fallin 
746d8357426SChris Fallin     fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I {
747d8357426SChris Fallin         let ty = self.vreg_type(vreg);
748d8357426SChris Fallin         I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty)
749d8357426SChris Fallin     }
750d8357426SChris Fallin 
751d8357426SChris Fallin     fn gen_zero_len_nop(&self) -> I {
75299be82c8SKasey Carrothers         I::gen_nop(0)
753d8357426SChris Fallin     }
754d8357426SChris Fallin 
755d8357426SChris Fallin     fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> {
756d8357426SChris Fallin         insn.maybe_direct_reload(reg, slot)
757d8357426SChris Fallin     }
758d8357426SChris Fallin 
759d8357426SChris Fallin     fn func_liveins(&self) -> RegallocSet<RealReg> {
760d8357426SChris Fallin         self.liveins.clone()
761d8357426SChris Fallin     }
762d8357426SChris Fallin 
763d8357426SChris Fallin     fn func_liveouts(&self) -> RegallocSet<RealReg> {
764d8357426SChris Fallin         self.liveouts.clone()
765d8357426SChris Fallin     }
766d8357426SChris Fallin }
767d8357426SChris Fallin 
768d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> {
769d8357426SChris Fallin     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
770d8357426SChris Fallin         writeln!(f, "VCode_Debug {{")?;
771d8357426SChris Fallin         writeln!(f, "  Entry block: {}", self.entry)?;
772d8357426SChris Fallin 
773d8357426SChris Fallin         for block in 0..self.num_blocks() {
774d8357426SChris Fallin             writeln!(f, "Block {}:", block,)?;
775d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
7764f919c64SBenjamin Bouvier                 writeln!(f, "  (successor: Block {})", succ.get())?;
777d8357426SChris Fallin             }
778d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
779d8357426SChris Fallin             writeln!(f, "  (instruction range: {} .. {})", start, end)?;
780d8357426SChris Fallin             for inst in start..end {
781d8357426SChris Fallin                 writeln!(f, "  Inst {}: {:?}", inst, self.insts[inst as usize])?;
782d8357426SChris Fallin             }
783d8357426SChris Fallin         }
784d8357426SChris Fallin 
785d8357426SChris Fallin         writeln!(f, "}}")?;
786d8357426SChris Fallin         Ok(())
787d8357426SChris Fallin     }
788d8357426SChris Fallin }
789d8357426SChris Fallin 
79048cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context.
79171768bb6SChris Fallin impl<I: VCodeInst> PrettyPrint for VCode<I> {
792d8357426SChris Fallin     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
793d8357426SChris Fallin         use std::fmt::Write;
794d8357426SChris Fallin 
795d8357426SChris Fallin         let mut s = String::new();
79648cf2c2fSChris Fallin         write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap();
79748cf2c2fSChris Fallin         write!(&mut s, "  Entry block: {}\n", self.entry).unwrap();
798d8357426SChris Fallin 
79908353fccSChris Fallin         let mut state = Default::default();
80008353fccSChris Fallin         let mut safepoint_idx = 0;
801d8357426SChris Fallin         for i in 0..self.num_blocks() {
80272e6be93SChris Fallin             let block = i as BlockIndex;
803d8357426SChris Fallin 
80472e6be93SChris Fallin             write!(&mut s, "Block {}:\n", block).unwrap();
80572e6be93SChris Fallin             if let Some(bb) = self.bindex_to_bb(block) {
80648cf2c2fSChris Fallin                 write!(&mut s, "  (original IR block: {})\n", bb).unwrap();
807d8357426SChris Fallin             }
80872e6be93SChris Fallin             for succ in self.succs(block) {
8094f919c64SBenjamin Bouvier                 write!(&mut s, "  (successor: Block {})\n", succ.get()).unwrap();
810d8357426SChris Fallin             }
81172e6be93SChris Fallin             let (start, end) = self.block_ranges[block as usize];
81248cf2c2fSChris Fallin             write!(&mut s, "  (instruction range: {} .. {})\n", start, end).unwrap();
813d8357426SChris Fallin             for inst in start..end {
81408353fccSChris Fallin                 if safepoint_idx < self.safepoint_insns.len()
81508353fccSChris Fallin                     && self.safepoint_insns[safepoint_idx] == inst
81608353fccSChris Fallin                 {
81708353fccSChris Fallin                     write!(
81808353fccSChris Fallin                         &mut s,
81908353fccSChris Fallin                         "      (safepoint: slots {:?} with EmitState {:?})\n",
82008353fccSChris Fallin                         self.safepoint_slots[safepoint_idx], state,
82108353fccSChris Fallin                     )
82208353fccSChris Fallin                     .unwrap();
82308353fccSChris Fallin                     safepoint_idx += 1;
82408353fccSChris Fallin                 }
82548cf2c2fSChris Fallin                 write!(
82648cf2c2fSChris Fallin                     &mut s,
82748cf2c2fSChris Fallin                     "  Inst {}:   {}\n",
828d8357426SChris Fallin                     inst,
82908353fccSChris Fallin                     self.insts[inst as usize].pretty_print(mb_rru, &mut state)
83048cf2c2fSChris Fallin                 )
83148cf2c2fSChris Fallin                 .unwrap();
832d8357426SChris Fallin             }
833d8357426SChris Fallin         }
834d8357426SChris Fallin 
83548cf2c2fSChris Fallin         write!(&mut s, "}}}}\n").unwrap();
836d8357426SChris Fallin 
837d8357426SChris Fallin         s
838d8357426SChris Fallin     }
839d8357426SChris Fallin }
84083f182b3SAndrew Brown 
84183f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the
84283f182b3SAndrew Brown /// [MachBuffer].
84383f182b3SAndrew Brown ///
84483f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using
84583f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are
84683f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant
84783f182b3SAndrew Brown /// values are inserted.
84883f182b3SAndrew Brown ///
84983f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the
85083f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer]
85183f182b3SAndrew Brown /// then writes the constant values to the buffer.
85283f182b3SAndrew Brown #[derive(Default)]
85383f182b3SAndrew Brown pub struct VCodeConstants {
85483f182b3SAndrew Brown     constants: PrimaryMap<VCodeConstant, VCodeConstantData>,
85583f182b3SAndrew Brown     pool_uses: HashMap<Constant, VCodeConstant>,
85683f182b3SAndrew Brown     well_known_uses: HashMap<*const [u8], VCodeConstant>,
85783f182b3SAndrew Brown }
85883f182b3SAndrew Brown impl VCodeConstants {
85983f182b3SAndrew Brown     /// Initialize the structure with the expected number of constants.
86083f182b3SAndrew Brown     pub fn with_capacity(expected_num_constants: usize) -> Self {
86183f182b3SAndrew Brown         Self {
86283f182b3SAndrew Brown             constants: PrimaryMap::with_capacity(expected_num_constants),
86383f182b3SAndrew Brown             pool_uses: HashMap::with_capacity(expected_num_constants),
86483f182b3SAndrew Brown             well_known_uses: HashMap::new(),
86583f182b3SAndrew Brown         }
86683f182b3SAndrew Brown     }
86783f182b3SAndrew Brown 
86883f182b3SAndrew Brown     /// Insert a constant; using this method indicates that a constant value will be used and thus
86983f182b3SAndrew Brown     /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants
87083f182b3SAndrew Brown     /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not
87183f182b3SAndrew Brown     /// [VCodeConstantData::Generated].
87283f182b3SAndrew Brown     pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant {
87383f182b3SAndrew Brown         match data {
87483f182b3SAndrew Brown             VCodeConstantData::Generated(_) => self.constants.push(data),
87583f182b3SAndrew Brown             VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) {
87683f182b3SAndrew Brown                 None => {
87783f182b3SAndrew Brown                     let vcode_constant = self.constants.push(data);
87883f182b3SAndrew Brown                     self.pool_uses.insert(constant, vcode_constant);
87983f182b3SAndrew Brown                     vcode_constant
88083f182b3SAndrew Brown                 }
88183f182b3SAndrew Brown                 Some(&vcode_constant) => vcode_constant,
88283f182b3SAndrew Brown             },
88383f182b3SAndrew Brown             VCodeConstantData::WellKnown(data_ref) => {
88483f182b3SAndrew Brown                 match self.well_known_uses.get(&(data_ref as *const [u8])) {
88583f182b3SAndrew Brown                     None => {
88683f182b3SAndrew Brown                         let vcode_constant = self.constants.push(data);
88783f182b3SAndrew Brown                         self.well_known_uses
88883f182b3SAndrew Brown                             .insert(data_ref as *const [u8], vcode_constant);
88983f182b3SAndrew Brown                         vcode_constant
89083f182b3SAndrew Brown                     }
89183f182b3SAndrew Brown                     Some(&vcode_constant) => vcode_constant,
89283f182b3SAndrew Brown                 }
89383f182b3SAndrew Brown             }
89483f182b3SAndrew Brown         }
89583f182b3SAndrew Brown     }
89683f182b3SAndrew Brown 
89783f182b3SAndrew Brown     /// Return the number of constants inserted.
89883f182b3SAndrew Brown     pub fn len(&self) -> usize {
89983f182b3SAndrew Brown         self.constants.len()
90083f182b3SAndrew Brown     }
90183f182b3SAndrew Brown 
90283f182b3SAndrew Brown     /// Iterate over the [VCodeConstant] keys inserted in this structure.
90383f182b3SAndrew Brown     pub fn keys(&self) -> Keys<VCodeConstant> {
90483f182b3SAndrew Brown         self.constants.keys()
90583f182b3SAndrew Brown     }
90683f182b3SAndrew Brown 
90783f182b3SAndrew Brown     /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this
90883f182b3SAndrew Brown     /// structure.
90983f182b3SAndrew Brown     pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> {
91083f182b3SAndrew Brown         self.constants.iter()
91183f182b3SAndrew Brown     }
91283f182b3SAndrew Brown }
91383f182b3SAndrew Brown 
91483f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants].
91583f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)]
91683f182b3SAndrew Brown pub struct VCodeConstant(u32);
91783f182b3SAndrew Brown entity_impl!(VCodeConstant);
91883f182b3SAndrew Brown 
91983f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking
92083f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication.
92183f182b3SAndrew Brown pub enum VCodeConstantData {
92283f182b3SAndrew Brown     /// A constant already present in the Cranelift IR
92383f182b3SAndrew Brown     /// [ConstantPool](crate::ir::constant::ConstantPool).
92483f182b3SAndrew Brown     Pool(Constant, ConstantData),
92583f182b3SAndrew Brown     /// A reference to a well-known constant value that is statically encoded within the compiler.
92683f182b3SAndrew Brown     WellKnown(&'static [u8]),
92783f182b3SAndrew Brown     /// A constant value generated during lowering; the value may depend on the instruction context
92883f182b3SAndrew Brown     /// which makes it difficult to de-duplicate--if possible, use other variants.
92983f182b3SAndrew Brown     Generated(ConstantData),
93083f182b3SAndrew Brown }
93183f182b3SAndrew Brown impl VCodeConstantData {
93283f182b3SAndrew Brown     /// Retrieve the constant data as a byte slice.
93383f182b3SAndrew Brown     pub fn as_slice(&self) -> &[u8] {
93483f182b3SAndrew Brown         match self {
93583f182b3SAndrew Brown             VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(),
93683f182b3SAndrew Brown             VCodeConstantData::WellKnown(d) => d,
93783f182b3SAndrew Brown         }
93883f182b3SAndrew Brown     }
93983f182b3SAndrew Brown 
94083f182b3SAndrew Brown     /// Calculate the alignment of the constant data.
94183f182b3SAndrew Brown     pub fn alignment(&self) -> u32 {
94283f182b3SAndrew Brown         if self.as_slice().len() <= 8 {
94383f182b3SAndrew Brown             8
94483f182b3SAndrew Brown         } else {
94583f182b3SAndrew Brown             16
94683f182b3SAndrew Brown         }
94783f182b3SAndrew Brown     }
94883f182b3SAndrew Brown }
94983f182b3SAndrew Brown 
95083f182b3SAndrew Brown #[cfg(test)]
95183f182b3SAndrew Brown mod test {
95283f182b3SAndrew Brown     use super::*;
9535e5e5206SChris Fallin     use std::mem::size_of;
95483f182b3SAndrew Brown 
95583f182b3SAndrew Brown     #[test]
95683f182b3SAndrew Brown     fn size_of_constant_structs() {
95783f182b3SAndrew Brown         assert_eq!(size_of::<Constant>(), 4);
95883f182b3SAndrew Brown         assert_eq!(size_of::<VCodeConstant>(), 4);
95983f182b3SAndrew Brown         assert_eq!(size_of::<ConstantData>(), 24);
96083f182b3SAndrew Brown         assert_eq!(size_of::<VCodeConstantData>(), 32);
96183f182b3SAndrew Brown         assert_eq!(
96283f182b3SAndrew Brown             size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(),
96383f182b3SAndrew Brown             24
96483f182b3SAndrew Brown         );
9655e5e5206SChris Fallin         // TODO The VCodeConstants structure's memory size could be further optimized.
9665e5e5206SChris Fallin         // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at
9675e5e5206SChris Fallin         // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes.
96883f182b3SAndrew Brown     }
96983f182b3SAndrew Brown }
970