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