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 
2008353fccSChris Fallin use crate::ir::{self, types, SourceLoc};
21d8357426SChris Fallin use crate::machinst::*;
22d8357426SChris Fallin use crate::settings;
232b9fefe8SChris Fallin use crate::timing;
24d8357426SChris Fallin 
25d8357426SChris Fallin use regalloc::Function as RegallocFunction;
26d8357426SChris Fallin use regalloc::Set as RegallocSet;
27be6f060aSChris Fallin use regalloc::{
2808353fccSChris Fallin     BlockIx, InstIx, Range, RegAllocResult, RegClass, RegUsageCollector, RegUsageMapper, SpillSlot,
2908353fccSChris Fallin     StackmapRequestInfo,
30be6f060aSChris Fallin };
31d8357426SChris Fallin 
32d8357426SChris Fallin use alloc::boxed::Box;
334f919c64SBenjamin Bouvier use alloc::{borrow::Cow, vec::Vec};
34d8357426SChris Fallin use std::fmt;
35d8357426SChris Fallin use std::iter;
36d8357426SChris Fallin use std::string::String;
37d8357426SChris Fallin 
38d8357426SChris Fallin /// Index referring to an instruction in VCode.
39d8357426SChris Fallin pub type InsnIndex = u32;
40d8357426SChris Fallin /// Index referring to a basic block in VCode.
41d8357426SChris Fallin pub type BlockIndex = u32;
42d8357426SChris Fallin 
43d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
44d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
4572e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {}
4672e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {}
47d8357426SChris Fallin 
48d8357426SChris Fallin /// A function in "VCode" (virtualized-register code) form, after lowering.
49d8357426SChris Fallin /// This is essentially a standard CFG of basic blocks, where each basic block
50d8357426SChris Fallin /// consists of lowered instructions produced by the machine-specific backend.
51d8357426SChris Fallin pub struct VCode<I: VCodeInst> {
52d8357426SChris Fallin     /// Function liveins.
53d8357426SChris Fallin     liveins: RegallocSet<RealReg>,
54d8357426SChris Fallin 
55d8357426SChris Fallin     /// Function liveouts.
56d8357426SChris Fallin     liveouts: RegallocSet<RealReg>,
57d8357426SChris Fallin 
58d8357426SChris Fallin     /// VReg IR-level types.
59d8357426SChris Fallin     vreg_types: Vec<Type>,
60d8357426SChris Fallin 
6108353fccSChris Fallin     /// Do we have any ref values among our vregs?
6208353fccSChris Fallin     have_ref_values: bool,
6308353fccSChris Fallin 
64d8357426SChris Fallin     /// Lowered machine instructions in order corresponding to the original IR.
6548cf2c2fSChris Fallin     insts: Vec<I>,
66d8357426SChris Fallin 
67b691770fSChris Fallin     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
68b691770fSChris Fallin     /// reasonable to keep one of these per instruction.)
69b691770fSChris Fallin     srclocs: Vec<SourceLoc>,
70b691770fSChris Fallin 
71d8357426SChris Fallin     /// Entry block.
72d8357426SChris Fallin     entry: BlockIndex,
73d8357426SChris Fallin 
74d8357426SChris Fallin     /// Block instruction indices.
7548cf2c2fSChris Fallin     block_ranges: Vec<(InsnIndex, InsnIndex)>,
76d8357426SChris Fallin 
77d8357426SChris Fallin     /// Block successors: index range in the successor-list below.
78d8357426SChris Fallin     block_succ_range: Vec<(usize, usize)>,
79d8357426SChris Fallin 
80d8357426SChris Fallin     /// Block successor lists, concatenated into one Vec. The `block_succ_range`
81d8357426SChris Fallin     /// list of tuples above gives (start, end) ranges within this list that
82d8357426SChris Fallin     /// correspond to each basic block's successors.
834f919c64SBenjamin Bouvier     block_succs: Vec<BlockIx>,
84d8357426SChris Fallin 
8572e6be93SChris Fallin     /// Block-order information.
8672e6be93SChris Fallin     block_order: BlockLoweringOrder,
87d8357426SChris Fallin 
88d8357426SChris Fallin     /// ABI object.
8948cf2c2fSChris Fallin     abi: Box<dyn ABIBody<I = I>>,
9008353fccSChris Fallin 
9108353fccSChris Fallin     /// Safepoint instruction indices. Filled in post-regalloc. (Prior to
9208353fccSChris Fallin     /// regalloc, the safepoint instructions are listed in the separate
9308353fccSChris Fallin     /// `StackmapRequestInfo` held separate from the `VCode`.)
9408353fccSChris Fallin     safepoint_insns: Vec<InsnIndex>,
9508353fccSChris Fallin 
9608353fccSChris Fallin     /// For each safepoint entry in `safepoint_insns`, a list of `SpillSlot`s.
9708353fccSChris Fallin     /// These are used to generate actual stack maps at emission. Filled in
9808353fccSChris Fallin     /// post-regalloc.
9908353fccSChris Fallin     safepoint_slots: Vec<Vec<SpillSlot>>,
100d8357426SChris Fallin }
101d8357426SChris Fallin 
102d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the
103d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward
104d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from
105d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse
106d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again.
107d8357426SChris Fallin ///
108d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two
109d8357426SChris Fallin /// swaps.  First, the machine instructions (`I` instances) are produced in
110d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed*
111d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering.
112d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic
113d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we
114d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto
115d8357426SChris Fallin /// the VCode's insts.
116d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> {
117d8357426SChris Fallin     /// In-progress VCode.
118d8357426SChris Fallin     vcode: VCode<I>,
119d8357426SChris Fallin 
12008353fccSChris Fallin     /// In-progress stack map-request info.
121*05bf9ea3SNick Fitzgerald     stack_map_info: StackmapRequestInfo,
12208353fccSChris Fallin 
12372e6be93SChris Fallin     /// Index of the last block-start in the vcode.
12472e6be93SChris Fallin     block_start: InsnIndex,
125d8357426SChris Fallin 
126d8357426SChris Fallin     /// Start of succs for the current block in the concatenated succs list.
127d8357426SChris Fallin     succ_start: usize,
128b691770fSChris Fallin 
129b691770fSChris Fallin     /// Current source location.
130b691770fSChris Fallin     cur_srcloc: SourceLoc,
131d8357426SChris Fallin }
132d8357426SChris Fallin 
133d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> {
134d8357426SChris Fallin     /// Create a new VCodeBuilder.
13572e6be93SChris Fallin     pub fn new(abi: Box<dyn ABIBody<I = I>>, block_order: BlockLoweringOrder) -> VCodeBuilder<I> {
13626529006SChris Fallin         let reftype_class = I::ref_type_regclass(abi.flags());
13772e6be93SChris Fallin         let vcode = VCode::new(abi, block_order);
138*05bf9ea3SNick Fitzgerald         let stack_map_info = StackmapRequestInfo {
13908353fccSChris Fallin             reftype_class,
14008353fccSChris Fallin             reftyped_vregs: vec![],
14108353fccSChris Fallin             safepoint_insns: vec![],
14208353fccSChris Fallin         };
14308353fccSChris Fallin 
144d8357426SChris Fallin         VCodeBuilder {
145d8357426SChris Fallin             vcode,
146*05bf9ea3SNick Fitzgerald             stack_map_info,
14772e6be93SChris Fallin             block_start: 0,
148d8357426SChris Fallin             succ_start: 0,
149b691770fSChris Fallin             cur_srcloc: SourceLoc::default(),
150d8357426SChris Fallin         }
151d8357426SChris Fallin     }
152d8357426SChris Fallin 
153d8357426SChris Fallin     /// Access the ABI object.
15448cf2c2fSChris Fallin     pub fn abi(&mut self) -> &mut dyn ABIBody<I = I> {
155d8357426SChris Fallin         &mut *self.vcode.abi
156d8357426SChris Fallin     }
157d8357426SChris Fallin 
15872e6be93SChris Fallin     /// Access to the BlockLoweringOrder object.
15972e6be93SChris Fallin     pub fn block_order(&self) -> &BlockLoweringOrder {
16072e6be93SChris Fallin         &self.vcode.block_order
1611d90751bSBenjamin Bouvier     }
1621d90751bSBenjamin Bouvier 
163d8357426SChris Fallin     /// Set the type of a VReg.
164d8357426SChris Fallin     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
16548f0b10cSJohnnie Birch         if self.vcode.vreg_types.len() <= vreg.get_index() {
166ef5de04dSBenjamin Bouvier             self.vcode
167ef5de04dSBenjamin Bouvier                 .vreg_types
168ef5de04dSBenjamin Bouvier                 .resize(vreg.get_index() + 1, ir::types::I8);
169d8357426SChris Fallin         }
170d8357426SChris Fallin         self.vcode.vreg_types[vreg.get_index()] = ty;
17108353fccSChris Fallin         if is_reftype(ty) {
172*05bf9ea3SNick Fitzgerald             self.stack_map_info.reftyped_vregs.push(vreg);
17308353fccSChris Fallin             self.vcode.have_ref_values = true;
17408353fccSChris Fallin         }
17508353fccSChris Fallin     }
17608353fccSChris Fallin 
17708353fccSChris Fallin     /// Are there any reference-typed values at all among the vregs?
17808353fccSChris Fallin     pub fn have_ref_values(&self) -> bool {
17908353fccSChris Fallin         self.vcode.have_ref_values()
180d8357426SChris Fallin     }
181d8357426SChris Fallin 
182d8357426SChris Fallin     /// Set the current block as the entry block.
183d8357426SChris Fallin     pub fn set_entry(&mut self, block: BlockIndex) {
184d8357426SChris Fallin         self.vcode.entry = block;
185d8357426SChris Fallin     }
186d8357426SChris Fallin 
187d8357426SChris Fallin     /// End the current basic block. Must be called after emitting vcode insts
188d8357426SChris Fallin     /// for IR insts and prior to ending the function (building the VCode).
18972e6be93SChris Fallin     pub fn end_bb(&mut self) {
19072e6be93SChris Fallin         let start_idx = self.block_start;
191d8357426SChris Fallin         let end_idx = self.vcode.insts.len() as InsnIndex;
19272e6be93SChris Fallin         self.block_start = end_idx;
193d8357426SChris Fallin         // Add the instruction index range to the list of blocks.
194d8357426SChris Fallin         self.vcode.block_ranges.push((start_idx, end_idx));
195d8357426SChris Fallin         // End the successors list.
196d8357426SChris Fallin         let succ_end = self.vcode.block_succs.len();
197d8357426SChris Fallin         self.vcode
198d8357426SChris Fallin             .block_succ_range
199d8357426SChris Fallin             .push((self.succ_start, succ_end));
200d8357426SChris Fallin         self.succ_start = succ_end;
201d8357426SChris Fallin     }
202d8357426SChris Fallin 
203d8357426SChris Fallin     /// Push an instruction for the current BB and current IR inst within the BB.
20408353fccSChris Fallin     pub fn push(&mut self, insn: I, is_safepoint: bool) {
205d8357426SChris Fallin         match insn.is_term() {
206d8357426SChris Fallin             MachTerminator::None | MachTerminator::Ret => {}
207d8357426SChris Fallin             MachTerminator::Uncond(target) => {
20872e6be93SChris Fallin                 self.vcode.block_succs.push(BlockIx::new(target.get()));
209d8357426SChris Fallin             }
210d8357426SChris Fallin             MachTerminator::Cond(true_branch, false_branch) => {
21172e6be93SChris Fallin                 self.vcode.block_succs.push(BlockIx::new(true_branch.get()));
21272e6be93SChris Fallin                 self.vcode
21372e6be93SChris Fallin                     .block_succs
21472e6be93SChris Fallin                     .push(BlockIx::new(false_branch.get()));
215d8357426SChris Fallin             }
216d8357426SChris Fallin             MachTerminator::Indirect(targets) => {
217d8357426SChris Fallin                 for target in targets {
21872e6be93SChris Fallin                     self.vcode.block_succs.push(BlockIx::new(target.get()));
219d8357426SChris Fallin                 }
220d8357426SChris Fallin             }
221d8357426SChris Fallin         }
22272e6be93SChris Fallin         self.vcode.insts.push(insn);
22372e6be93SChris Fallin         self.vcode.srclocs.push(self.cur_srcloc);
22408353fccSChris Fallin         if is_safepoint {
225*05bf9ea3SNick Fitzgerald             self.stack_map_info
22608353fccSChris Fallin                 .safepoint_insns
22708353fccSChris Fallin                 .push(InstIx::new((self.vcode.insts.len() - 1) as u32));
22808353fccSChris Fallin         }
22972e6be93SChris Fallin     }
23072e6be93SChris Fallin 
23172e6be93SChris Fallin     /// Get the current source location.
23272e6be93SChris Fallin     pub fn get_srcloc(&self) -> SourceLoc {
23372e6be93SChris Fallin         self.cur_srcloc
234b691770fSChris Fallin     }
235b691770fSChris Fallin 
236b691770fSChris Fallin     /// Set the current source location.
237b691770fSChris Fallin     pub fn set_srcloc(&mut self, srcloc: SourceLoc) {
238b691770fSChris Fallin         self.cur_srcloc = srcloc;
239d8357426SChris Fallin     }
240d8357426SChris Fallin 
24108353fccSChris Fallin     /// Build the final VCode, returning the vcode itself as well as auxiliary
24208353fccSChris Fallin     /// information, such as the stack map request information.
24308353fccSChris Fallin     pub fn build(self) -> (VCode<I>, StackmapRequestInfo) {
24408353fccSChris Fallin         // TODO: come up with an abstraction for "vcode and auxiliary data". The
24508353fccSChris Fallin         // auxiliary data needs to be separate from the vcode so that it can be
24608353fccSChris Fallin         // referenced as the vcode is mutated (e.g. by the register allocator).
247*05bf9ea3SNick Fitzgerald         (self.vcode, self.stack_map_info)
248d8357426SChris Fallin     }
249d8357426SChris Fallin }
250d8357426SChris Fallin 
251d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool {
252d8357426SChris Fallin     if let Some((to, from)) = insn.is_move() {
253d8357426SChris Fallin         to.to_reg() == from
254d8357426SChris Fallin     } else {
255d8357426SChris Fallin         false
256d8357426SChris Fallin     }
257d8357426SChris Fallin }
258d8357426SChris Fallin 
25908353fccSChris Fallin /// Is this type a reference type?
26008353fccSChris Fallin fn is_reftype(ty: Type) -> bool {
26126529006SChris Fallin     ty == types::R64 || ty == types::R32
26208353fccSChris Fallin }
26308353fccSChris Fallin 
264d8357426SChris Fallin impl<I: VCodeInst> VCode<I> {
265d8357426SChris Fallin     /// New empty VCode.
26672e6be93SChris Fallin     fn new(abi: Box<dyn ABIBody<I = I>>, block_order: BlockLoweringOrder) -> VCode<I> {
267d8357426SChris Fallin         VCode {
268d8357426SChris Fallin             liveins: abi.liveins(),
269d8357426SChris Fallin             liveouts: abi.liveouts(),
270d8357426SChris Fallin             vreg_types: vec![],
27108353fccSChris Fallin             have_ref_values: false,
272d8357426SChris Fallin             insts: vec![],
273b691770fSChris Fallin             srclocs: vec![],
274d8357426SChris Fallin             entry: 0,
275d8357426SChris Fallin             block_ranges: vec![],
276d8357426SChris Fallin             block_succ_range: vec![],
277d8357426SChris Fallin             block_succs: vec![],
27872e6be93SChris Fallin             block_order,
279d8357426SChris Fallin             abi,
28008353fccSChris Fallin             safepoint_insns: vec![],
28108353fccSChris Fallin             safepoint_slots: vec![],
282d8357426SChris Fallin         }
283d8357426SChris Fallin     }
284d8357426SChris Fallin 
285d1b5df31SBenjamin Bouvier     /// Returns the flags controlling this function's compilation.
286d1b5df31SBenjamin Bouvier     pub fn flags(&self) -> &settings::Flags {
287d1b5df31SBenjamin Bouvier         self.abi.flags()
288d1b5df31SBenjamin Bouvier     }
289d1b5df31SBenjamin Bouvier 
290d8357426SChris Fallin     /// Get the IR-level type of a VReg.
291d8357426SChris Fallin     pub fn vreg_type(&self, vreg: VirtualReg) -> Type {
292d8357426SChris Fallin         self.vreg_types[vreg.get_index()]
293d8357426SChris Fallin     }
294d8357426SChris Fallin 
29508353fccSChris Fallin     /// Are there any reference-typed values at all among the vregs?
29608353fccSChris Fallin     pub fn have_ref_values(&self) -> bool {
29708353fccSChris Fallin         self.have_ref_values
29808353fccSChris Fallin     }
29908353fccSChris Fallin 
300d8357426SChris Fallin     /// Get the entry block.
301d8357426SChris Fallin     pub fn entry(&self) -> BlockIndex {
302d8357426SChris Fallin         self.entry
303d8357426SChris Fallin     }
304d8357426SChris Fallin 
305d8357426SChris Fallin     /// Get the number of blocks. Block indices will be in the range `0 ..
306d8357426SChris Fallin     /// (self.num_blocks() - 1)`.
307d8357426SChris Fallin     pub fn num_blocks(&self) -> usize {
308d8357426SChris Fallin         self.block_ranges.len()
309d8357426SChris Fallin     }
310d8357426SChris Fallin 
311d8357426SChris Fallin     /// Stack frame size for the full function's body.
312d8357426SChris Fallin     pub fn frame_size(&self) -> u32 {
313d8357426SChris Fallin         self.abi.frame_size()
314d8357426SChris Fallin     }
315d8357426SChris Fallin 
31608353fccSChris Fallin     /// Inbound stack-args size.
31708353fccSChris Fallin     pub fn stack_args_size(&self) -> u32 {
31808353fccSChris Fallin         self.abi.stack_args_size()
31908353fccSChris Fallin     }
32008353fccSChris Fallin 
321d8357426SChris Fallin     /// Get the successors for a block.
3224f919c64SBenjamin Bouvier     pub fn succs(&self, block: BlockIndex) -> &[BlockIx] {
323d8357426SChris Fallin         let (start, end) = self.block_succ_range[block as usize];
324d8357426SChris Fallin         &self.block_succs[start..end]
325d8357426SChris Fallin     }
326d8357426SChris Fallin 
327d8357426SChris Fallin     /// Take the results of register allocation, with a sequence of
328d8357426SChris Fallin     /// instructions including spliced fill/reload/move instructions, and replace
329d8357426SChris Fallin     /// the VCode with them.
330d1b5df31SBenjamin Bouvier     pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) {
331d8357426SChris Fallin         // Record the spillslot count and clobbered registers for the ABI/stack
332d8357426SChris Fallin         // setup code.
333d8357426SChris Fallin         self.abi.set_num_spillslots(result.num_spill_slots as usize);
334d8357426SChris Fallin         self.abi
335d8357426SChris Fallin             .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r)));
336d8357426SChris Fallin 
337d8357426SChris Fallin         let mut final_insns = vec![];
338d8357426SChris Fallin         let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
339b691770fSChris Fallin         let mut final_srclocs = vec![];
34008353fccSChris Fallin         let mut final_safepoint_insns = vec![];
34108353fccSChris Fallin         let mut safept_idx = 0;
342d8357426SChris Fallin 
34308353fccSChris Fallin         assert!(result.target_map.elems().len() == self.num_blocks());
34472e6be93SChris Fallin         for block in 0..self.num_blocks() {
34508353fccSChris Fallin             let start = result.target_map.elems()[block].get() as usize;
34608353fccSChris Fallin             let end = if block == self.num_blocks() - 1 {
34708353fccSChris Fallin                 result.insns.len()
34808353fccSChris Fallin             } else {
34908353fccSChris Fallin                 result.target_map.elems()[block + 1].get() as usize
35008353fccSChris Fallin             };
35172e6be93SChris Fallin             let block = block as BlockIndex;
352d8357426SChris Fallin             let final_start = final_insns.len() as InsnIndex;
353d8357426SChris Fallin 
35472e6be93SChris Fallin             if block == self.entry {
355d8357426SChris Fallin                 // Start with the prologue.
356b691770fSChris Fallin                 let prologue = self.abi.gen_prologue();
357b691770fSChris Fallin                 let len = prologue.len();
358b691770fSChris Fallin                 final_insns.extend(prologue.into_iter());
359b691770fSChris Fallin                 final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len));
360d8357426SChris Fallin             }
361d8357426SChris Fallin 
362d8357426SChris Fallin             for i in start..end {
363d8357426SChris Fallin                 let insn = &result.insns[i];
364d8357426SChris Fallin 
365d8357426SChris Fallin                 // Elide redundant moves at this point (we only know what is
366d8357426SChris Fallin                 // redundant once registers are allocated).
367d8357426SChris Fallin                 if is_redundant_move(insn) {
368d8357426SChris Fallin                     continue;
369d8357426SChris Fallin                 }
370d8357426SChris Fallin 
371b691770fSChris Fallin                 // Is there a srcloc associated with this insn? Look it up based on original
372b691770fSChris Fallin                 // instruction index (if new insn corresponds to some original insn, i.e., is not
373b691770fSChris Fallin                 // an inserted load/spill/move).
374b691770fSChris Fallin                 let orig_iix = result.orig_insn_map[InstIx::new(i as u32)];
375b691770fSChris Fallin                 let srcloc = if orig_iix.is_invalid() {
376b691770fSChris Fallin                     SourceLoc::default()
377b691770fSChris Fallin                 } else {
378b691770fSChris Fallin                     self.srclocs[orig_iix.get() as usize]
379b691770fSChris Fallin                 };
380b691770fSChris Fallin 
381d8357426SChris Fallin                 // Whenever encountering a return instruction, replace it
382d8357426SChris Fallin                 // with the epilogue.
383d8357426SChris Fallin                 let is_ret = insn.is_term() == MachTerminator::Ret;
384d8357426SChris Fallin                 if is_ret {
385b691770fSChris Fallin                     let epilogue = self.abi.gen_epilogue();
386b691770fSChris Fallin                     let len = epilogue.len();
387b691770fSChris Fallin                     final_insns.extend(epilogue.into_iter());
388b691770fSChris Fallin                     final_srclocs.extend(iter::repeat(srcloc).take(len));
389d8357426SChris Fallin                 } else {
390d8357426SChris Fallin                     final_insns.push(insn.clone());
391b691770fSChris Fallin                     final_srclocs.push(srcloc);
392d8357426SChris Fallin                 }
39308353fccSChris Fallin 
39408353fccSChris Fallin                 // Was this instruction a safepoint instruction? Add its final
39508353fccSChris Fallin                 // index to the safepoint insn-index list if so.
39608353fccSChris Fallin                 if safept_idx < result.new_safepoint_insns.len()
39708353fccSChris Fallin                     && (result.new_safepoint_insns[safept_idx].get() as usize) == i
39808353fccSChris Fallin                 {
39908353fccSChris Fallin                     let idx = final_insns.len() - 1;
40008353fccSChris Fallin                     final_safepoint_insns.push(idx as InsnIndex);
40108353fccSChris Fallin                     safept_idx += 1;
40208353fccSChris Fallin                 }
403d8357426SChris Fallin             }
404d8357426SChris Fallin 
405d8357426SChris Fallin             let final_end = final_insns.len() as InsnIndex;
40672e6be93SChris Fallin             final_block_ranges[block as usize] = (final_start, final_end);
407d8357426SChris Fallin         }
408d8357426SChris Fallin 
409b691770fSChris Fallin         debug_assert!(final_insns.len() == final_srclocs.len());
410b691770fSChris Fallin 
411d8357426SChris Fallin         self.insts = final_insns;
412b691770fSChris Fallin         self.srclocs = final_srclocs;
413d8357426SChris Fallin         self.block_ranges = final_block_ranges;
41408353fccSChris Fallin         self.safepoint_insns = final_safepoint_insns;
41508353fccSChris Fallin 
41608353fccSChris Fallin         // Save safepoint slot-lists. These will be passed to the `EmitState`
41708353fccSChris Fallin         // for the machine backend during emission so that it can do
41808353fccSChris Fallin         // target-specific translations of slot numbers to stack offsets.
41908353fccSChris Fallin         self.safepoint_slots = result.stackmaps;
420d8357426SChris Fallin     }
421d8357426SChris Fallin 
42272e6be93SChris Fallin     /// Emit the instructions to a `MachBuffer`, containing fixed-up code and external
42372e6be93SChris Fallin     /// reloc/trap/etc. records ready for use.
42472e6be93SChris Fallin     pub fn emit(&self) -> MachBuffer<I>
425d8357426SChris Fallin     where
42672e6be93SChris Fallin         I: MachInstEmit,
427d8357426SChris Fallin     {
4282b9fefe8SChris Fallin         let _tt = timing::vcode_emit();
42972e6be93SChris Fallin         let mut buffer = MachBuffer::new();
43008353fccSChris Fallin         let mut state = I::State::new(&*self.abi);
431d8357426SChris Fallin 
43272e6be93SChris Fallin         buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex); // first N MachLabels are simply block indices.
433d8357426SChris Fallin 
434a7ca37e4SBenjamin Bouvier         let flags = self.abi.flags();
43508353fccSChris Fallin         let mut safepoint_idx = 0;
436964c6087SChris Fallin         let mut cur_srcloc = None;
43772e6be93SChris Fallin         for block in 0..self.num_blocks() {
43872e6be93SChris Fallin             let block = block as BlockIndex;
43972e6be93SChris Fallin             let new_offset = I::align_basic_block(buffer.cur_offset());
44072e6be93SChris Fallin             while new_offset > buffer.cur_offset() {
441d8357426SChris Fallin                 // Pad with NOPs up to the aligned block offset.
44272e6be93SChris Fallin                 let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
44372e6be93SChris Fallin                 nop.emit(&mut buffer, flags, &mut Default::default());
444d8357426SChris Fallin             }
44572e6be93SChris Fallin             assert_eq!(buffer.cur_offset(), new_offset);
446d8357426SChris Fallin 
44748cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
44872e6be93SChris Fallin             buffer.bind_label(MachLabel::from_block(block));
449d8357426SChris Fallin             for iix in start..end {
450b691770fSChris Fallin                 let srcloc = self.srclocs[iix as usize];
451964c6087SChris Fallin                 if cur_srcloc != Some(srcloc) {
452964c6087SChris Fallin                     if cur_srcloc.is_some() {
45372e6be93SChris Fallin                         buffer.end_srcloc();
454b691770fSChris Fallin                     }
45572e6be93SChris Fallin                     buffer.start_srcloc(srcloc);
456964c6087SChris Fallin                     cur_srcloc = Some(srcloc);
457b691770fSChris Fallin                 }
458b691770fSChris Fallin 
45908353fccSChris Fallin                 if safepoint_idx < self.safepoint_insns.len()
46008353fccSChris Fallin                     && self.safepoint_insns[safepoint_idx] == iix
46108353fccSChris Fallin                 {
46208353fccSChris Fallin                     if self.safepoint_slots[safepoint_idx].len() > 0 {
463*05bf9ea3SNick Fitzgerald                         let stack_map = self.abi.spillslots_to_stack_map(
46408353fccSChris Fallin                             &self.safepoint_slots[safepoint_idx][..],
46508353fccSChris Fallin                             &state,
46608353fccSChris Fallin                         );
467*05bf9ea3SNick Fitzgerald                         state.pre_safepoint(stack_map);
46808353fccSChris Fallin                     }
46908353fccSChris Fallin                     safepoint_idx += 1;
47008353fccSChris Fallin                 }
47108353fccSChris Fallin 
47272e6be93SChris Fallin                 self.insts[iix as usize].emit(&mut buffer, flags, &mut state);
473d8357426SChris Fallin             }
474b691770fSChris Fallin 
475964c6087SChris Fallin             if cur_srcloc.is_some() {
47672e6be93SChris Fallin                 buffer.end_srcloc();
477964c6087SChris Fallin                 cur_srcloc = None;
478b691770fSChris Fallin             }
47972e6be93SChris Fallin 
48072e6be93SChris Fallin             // Do we need an island? Get the worst-case size of the next BB and see if, having
48172e6be93SChris Fallin             // emitted that many bytes, we will be beyond the deadline.
48272e6be93SChris Fallin             if block < (self.num_blocks() - 1) as BlockIndex {
48372e6be93SChris Fallin                 let next_block = block + 1;
48472e6be93SChris Fallin                 let next_block_range = self.block_ranges[next_block as usize];
48572e6be93SChris Fallin                 let next_block_size = next_block_range.1 - next_block_range.0;
48672e6be93SChris Fallin                 let worst_case_next_bb = I::worst_case_size() * next_block_size;
48772e6be93SChris Fallin                 if buffer.island_needed(worst_case_next_bb) {
48872e6be93SChris Fallin                     buffer.emit_island();
48972e6be93SChris Fallin                 }
49072e6be93SChris Fallin             }
491d8357426SChris Fallin         }
492d8357426SChris Fallin 
49372e6be93SChris Fallin         buffer
494d8357426SChris Fallin     }
495d8357426SChris Fallin 
496d8357426SChris Fallin     /// Get the IR block for a BlockIndex, if one exists.
497d8357426SChris Fallin     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
49872e6be93SChris Fallin         self.block_order.lowered_order()[block as usize].orig_block()
499d8357426SChris Fallin     }
500d8357426SChris Fallin }
501d8357426SChris Fallin 
502d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> {
503d8357426SChris Fallin     type Inst = I;
504d8357426SChris Fallin 
505d8357426SChris Fallin     fn insns(&self) -> &[I] {
506d8357426SChris Fallin         &self.insts[..]
507d8357426SChris Fallin     }
508d8357426SChris Fallin 
509d8357426SChris Fallin     fn insns_mut(&mut self) -> &mut [I] {
510d8357426SChris Fallin         &mut self.insts[..]
511d8357426SChris Fallin     }
512d8357426SChris Fallin 
513d8357426SChris Fallin     fn get_insn(&self, insn: InstIx) -> &I {
514d8357426SChris Fallin         &self.insts[insn.get() as usize]
515d8357426SChris Fallin     }
516d8357426SChris Fallin 
517d8357426SChris Fallin     fn get_insn_mut(&mut self, insn: InstIx) -> &mut I {
518d8357426SChris Fallin         &mut self.insts[insn.get() as usize]
519d8357426SChris Fallin     }
520d8357426SChris Fallin 
521d8357426SChris Fallin     fn blocks(&self) -> Range<BlockIx> {
522d8357426SChris Fallin         Range::new(BlockIx::new(0), self.block_ranges.len())
523d8357426SChris Fallin     }
524d8357426SChris Fallin 
525d8357426SChris Fallin     fn entry_block(&self) -> BlockIx {
526d8357426SChris Fallin         BlockIx::new(self.entry)
527d8357426SChris Fallin     }
528d8357426SChris Fallin 
529d8357426SChris Fallin     fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
530d8357426SChris Fallin         let (start, end) = self.block_ranges[block.get() as usize];
531d8357426SChris Fallin         Range::new(InstIx::new(start), (end - start) as usize)
532d8357426SChris Fallin     }
533d8357426SChris Fallin 
5344f919c64SBenjamin Bouvier     fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> {
535d8357426SChris Fallin         let (start, end) = self.block_succ_range[block.get() as usize];
5364f919c64SBenjamin Bouvier         Cow::Borrowed(&self.block_succs[start..end])
537d8357426SChris Fallin     }
538d8357426SChris Fallin 
539d8357426SChris Fallin     fn is_ret(&self, insn: InstIx) -> bool {
540d8357426SChris Fallin         match self.insts[insn.get() as usize].is_term() {
541d8357426SChris Fallin             MachTerminator::Ret => true,
542d8357426SChris Fallin             _ => false,
543d8357426SChris Fallin         }
544d8357426SChris Fallin     }
545d8357426SChris Fallin 
546d8357426SChris Fallin     fn get_regs(insn: &I, collector: &mut RegUsageCollector) {
547d8357426SChris Fallin         insn.get_regs(collector)
548d8357426SChris Fallin     }
549d8357426SChris Fallin 
5501f620e1bSBenjamin Bouvier     fn map_regs<RUM: RegUsageMapper>(insn: &mut I, mapper: &RUM) {
551be6f060aSChris Fallin         insn.map_regs(mapper);
552d8357426SChris Fallin     }
553d8357426SChris Fallin 
554d8357426SChris Fallin     fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> {
555d8357426SChris Fallin         insn.is_move()
556d8357426SChris Fallin     }
557d8357426SChris Fallin 
55846093f61SBenjamin Bouvier     fn get_num_vregs(&self) -> usize {
55946093f61SBenjamin Bouvier         self.vreg_types.len()
560be6f060aSChris Fallin     }
561be6f060aSChris Fallin 
562d8357426SChris Fallin     fn get_spillslot_size(&self, regclass: RegClass, vreg: VirtualReg) -> u32 {
563d8357426SChris Fallin         let ty = self.vreg_type(vreg);
564d8357426SChris Fallin         self.abi.get_spillslot_size(regclass, ty)
565d8357426SChris Fallin     }
566d8357426SChris Fallin 
56708353fccSChris Fallin     fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, vreg: Option<VirtualReg>) -> I {
56808353fccSChris Fallin         let ty = vreg.map(|v| self.vreg_type(v));
569d8357426SChris Fallin         self.abi.gen_spill(to_slot, from_reg, ty)
570d8357426SChris Fallin     }
571d8357426SChris Fallin 
57208353fccSChris Fallin     fn gen_reload(
57308353fccSChris Fallin         &self,
57408353fccSChris Fallin         to_reg: Writable<RealReg>,
57508353fccSChris Fallin         from_slot: SpillSlot,
57608353fccSChris Fallin         vreg: Option<VirtualReg>,
57708353fccSChris Fallin     ) -> I {
57808353fccSChris Fallin         let ty = vreg.map(|v| self.vreg_type(v));
579d8357426SChris Fallin         self.abi.gen_reload(to_reg, from_slot, ty)
580d8357426SChris Fallin     }
581d8357426SChris Fallin 
582d8357426SChris Fallin     fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I {
583d8357426SChris Fallin         let ty = self.vreg_type(vreg);
584d8357426SChris Fallin         I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty)
585d8357426SChris Fallin     }
586d8357426SChris Fallin 
587d8357426SChris Fallin     fn gen_zero_len_nop(&self) -> I {
588d8357426SChris Fallin         I::gen_zero_len_nop()
589d8357426SChris Fallin     }
590d8357426SChris Fallin 
591d8357426SChris Fallin     fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> {
592d8357426SChris Fallin         insn.maybe_direct_reload(reg, slot)
593d8357426SChris Fallin     }
594d8357426SChris Fallin 
595d8357426SChris Fallin     fn func_liveins(&self) -> RegallocSet<RealReg> {
596d8357426SChris Fallin         self.liveins.clone()
597d8357426SChris Fallin     }
598d8357426SChris Fallin 
599d8357426SChris Fallin     fn func_liveouts(&self) -> RegallocSet<RealReg> {
600d8357426SChris Fallin         self.liveouts.clone()
601d8357426SChris Fallin     }
602d8357426SChris Fallin }
603d8357426SChris Fallin 
604d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> {
605d8357426SChris Fallin     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
606d8357426SChris Fallin         writeln!(f, "VCode_Debug {{")?;
607d8357426SChris Fallin         writeln!(f, "  Entry block: {}", self.entry)?;
608d8357426SChris Fallin 
609d8357426SChris Fallin         for block in 0..self.num_blocks() {
610d8357426SChris Fallin             writeln!(f, "Block {}:", block,)?;
611d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
6124f919c64SBenjamin Bouvier                 writeln!(f, "  (successor: Block {})", succ.get())?;
613d8357426SChris Fallin             }
614d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
615d8357426SChris Fallin             writeln!(f, "  (instruction range: {} .. {})", start, end)?;
616d8357426SChris Fallin             for inst in start..end {
617d8357426SChris Fallin                 writeln!(f, "  Inst {}: {:?}", inst, self.insts[inst as usize])?;
618d8357426SChris Fallin             }
619d8357426SChris Fallin         }
620d8357426SChris Fallin 
621d8357426SChris Fallin         writeln!(f, "}}")?;
622d8357426SChris Fallin         Ok(())
623d8357426SChris Fallin     }
624d8357426SChris Fallin }
625d8357426SChris Fallin 
62648cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context.
62708353fccSChris Fallin impl<I: VCodeInst> ShowWithRRU for VCode<I> {
628d8357426SChris Fallin     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
629d8357426SChris Fallin         use std::fmt::Write;
630d8357426SChris Fallin 
631d8357426SChris Fallin         let mut s = String::new();
63248cf2c2fSChris Fallin         write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap();
63348cf2c2fSChris Fallin         write!(&mut s, "  Entry block: {}\n", self.entry).unwrap();
634d8357426SChris Fallin 
63508353fccSChris Fallin         let mut state = Default::default();
63608353fccSChris Fallin         let mut safepoint_idx = 0;
637d8357426SChris Fallin         for i in 0..self.num_blocks() {
63872e6be93SChris Fallin             let block = i as BlockIndex;
639d8357426SChris Fallin 
64072e6be93SChris Fallin             write!(&mut s, "Block {}:\n", block).unwrap();
64172e6be93SChris Fallin             if let Some(bb) = self.bindex_to_bb(block) {
64248cf2c2fSChris Fallin                 write!(&mut s, "  (original IR block: {})\n", bb).unwrap();
643d8357426SChris Fallin             }
64472e6be93SChris Fallin             for succ in self.succs(block) {
6454f919c64SBenjamin Bouvier                 write!(&mut s, "  (successor: Block {})\n", succ.get()).unwrap();
646d8357426SChris Fallin             }
64772e6be93SChris Fallin             let (start, end) = self.block_ranges[block as usize];
64848cf2c2fSChris Fallin             write!(&mut s, "  (instruction range: {} .. {})\n", start, end).unwrap();
649d8357426SChris Fallin             for inst in start..end {
65008353fccSChris Fallin                 if safepoint_idx < self.safepoint_insns.len()
65108353fccSChris Fallin                     && self.safepoint_insns[safepoint_idx] == inst
65208353fccSChris Fallin                 {
65308353fccSChris Fallin                     write!(
65408353fccSChris Fallin                         &mut s,
65508353fccSChris Fallin                         "      (safepoint: slots {:?} with EmitState {:?})\n",
65608353fccSChris Fallin                         self.safepoint_slots[safepoint_idx], state,
65708353fccSChris Fallin                     )
65808353fccSChris Fallin                     .unwrap();
65908353fccSChris Fallin                     safepoint_idx += 1;
66008353fccSChris Fallin                 }
66148cf2c2fSChris Fallin                 write!(
66248cf2c2fSChris Fallin                     &mut s,
66348cf2c2fSChris Fallin                     "  Inst {}:   {}\n",
664d8357426SChris Fallin                     inst,
66508353fccSChris Fallin                     self.insts[inst as usize].pretty_print(mb_rru, &mut state)
66648cf2c2fSChris Fallin                 )
66748cf2c2fSChris Fallin                 .unwrap();
668d8357426SChris Fallin             }
669d8357426SChris Fallin         }
670d8357426SChris Fallin 
67148cf2c2fSChris Fallin         write!(&mut s, "}}}}\n").unwrap();
672d8357426SChris Fallin 
673d8357426SChris Fallin         s
674d8357426SChris Fallin     }
675d8357426SChris Fallin }
676