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