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 2083f182b3SAndrew Brown use crate::ir::{self, types, Constant, ConstantData, 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::{ 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; 45de4af90aSYury Delendik /// Range of an instructions in VCode. 46de4af90aSYury Delendik pub type InsnRange = core::ops::Range<InsnIndex>; 47d8357426SChris Fallin 48d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be 49d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. 5072e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 5172e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {} 52d8357426SChris Fallin 53d8357426SChris Fallin /// A function in "VCode" (virtualized-register code) form, after lowering. 54d8357426SChris Fallin /// This is essentially a standard CFG of basic blocks, where each basic block 55d8357426SChris Fallin /// consists of lowered instructions produced by the machine-specific backend. 56d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 57d8357426SChris Fallin /// Function liveins. 58d8357426SChris Fallin liveins: RegallocSet<RealReg>, 59d8357426SChris Fallin 60d8357426SChris Fallin /// Function liveouts. 61d8357426SChris Fallin liveouts: RegallocSet<RealReg>, 62d8357426SChris Fallin 63d8357426SChris Fallin /// VReg IR-level types. 64d8357426SChris Fallin vreg_types: Vec<Type>, 65d8357426SChris Fallin 6608353fccSChris Fallin /// Do we have any ref values among our vregs? 6708353fccSChris Fallin have_ref_values: bool, 6808353fccSChris Fallin 69d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 7048cf2c2fSChris Fallin insts: Vec<I>, 71d8357426SChris Fallin 72b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 73b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 74b691770fSChris Fallin srclocs: Vec<SourceLoc>, 75b691770fSChris Fallin 76d8357426SChris Fallin /// Entry block. 77d8357426SChris Fallin entry: BlockIndex, 78d8357426SChris Fallin 79d8357426SChris Fallin /// Block instruction indices. 8048cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 81d8357426SChris Fallin 82d8357426SChris Fallin /// Block successors: index range in the successor-list below. 83d8357426SChris Fallin block_succ_range: Vec<(usize, usize)>, 84d8357426SChris Fallin 85d8357426SChris Fallin /// Block successor lists, concatenated into one Vec. The `block_succ_range` 86d8357426SChris Fallin /// list of tuples above gives (start, end) ranges within this list that 87d8357426SChris Fallin /// correspond to each basic block's successors. 884f919c64SBenjamin Bouvier block_succs: Vec<BlockIx>, 89d8357426SChris Fallin 9072e6be93SChris Fallin /// Block-order information. 9172e6be93SChris Fallin block_order: BlockLoweringOrder, 92d8357426SChris Fallin 93d8357426SChris Fallin /// ABI object. 94e8f772c1SChris Fallin abi: Box<dyn ABICallee<I = I>>, 9508353fccSChris Fallin 96c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 97c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 98c5bbc874SBenjamin Bouvier emit_info: I::Info, 99c5bbc874SBenjamin Bouvier 10008353fccSChris Fallin /// Safepoint instruction indices. Filled in post-regalloc. (Prior to 10108353fccSChris Fallin /// regalloc, the safepoint instructions are listed in the separate 10208353fccSChris Fallin /// `StackmapRequestInfo` held separate from the `VCode`.) 10308353fccSChris Fallin safepoint_insns: Vec<InsnIndex>, 10408353fccSChris Fallin 10508353fccSChris Fallin /// For each safepoint entry in `safepoint_insns`, a list of `SpillSlot`s. 10608353fccSChris Fallin /// These are used to generate actual stack maps at emission. Filled in 10708353fccSChris Fallin /// post-regalloc. 10808353fccSChris Fallin safepoint_slots: Vec<Vec<SpillSlot>>, 109de4af90aSYury Delendik 110de4af90aSYury Delendik /// Ranges for prologue and epilogue instructions. 111de4af90aSYury Delendik prologue_epilogue_ranges: Option<(InsnRange, Box<[InsnRange]>)>, 112de4af90aSYury Delendik 113de4af90aSYury Delendik /// Instruction end offsets 114de4af90aSYury Delendik insts_layout: RefCell<(Vec<u32>, u32)>, 11583f182b3SAndrew Brown 11683f182b3SAndrew Brown /// Constants. 11783f182b3SAndrew Brown constants: VCodeConstants, 118d8357426SChris Fallin } 119d8357426SChris Fallin 120d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the 121d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward 122d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from 123d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse 124d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again. 125d8357426SChris Fallin /// 126d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two 127d8357426SChris Fallin /// swaps. First, the machine instructions (`I` instances) are produced in 128d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed* 129d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering. 130d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic 131d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we 132d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto 133d8357426SChris Fallin /// the VCode's insts. 134d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 135d8357426SChris Fallin /// In-progress VCode. 136d8357426SChris Fallin vcode: VCode<I>, 137d8357426SChris Fallin 13808353fccSChris Fallin /// In-progress stack map-request info. 13905bf9ea3SNick Fitzgerald stack_map_info: StackmapRequestInfo, 14008353fccSChris Fallin 14172e6be93SChris Fallin /// Index of the last block-start in the vcode. 14272e6be93SChris Fallin block_start: InsnIndex, 143d8357426SChris Fallin 144d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 145d8357426SChris Fallin succ_start: usize, 146b691770fSChris Fallin 147b691770fSChris Fallin /// Current source location. 148b691770fSChris Fallin cur_srcloc: SourceLoc, 149d8357426SChris Fallin } 150d8357426SChris Fallin 151d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 152d8357426SChris Fallin /// Create a new VCodeBuilder. 153c5bbc874SBenjamin Bouvier pub fn new( 154c5bbc874SBenjamin Bouvier abi: Box<dyn ABICallee<I = I>>, 155c5bbc874SBenjamin Bouvier emit_info: I::Info, 156c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 15783f182b3SAndrew Brown constants: VCodeConstants, 158c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 15926529006SChris Fallin let reftype_class = I::ref_type_regclass(abi.flags()); 16083f182b3SAndrew Brown let vcode = VCode::new(abi, emit_info, block_order, constants); 16105bf9ea3SNick Fitzgerald let stack_map_info = StackmapRequestInfo { 16208353fccSChris Fallin reftype_class, 16308353fccSChris Fallin reftyped_vregs: vec![], 16408353fccSChris Fallin safepoint_insns: vec![], 16508353fccSChris Fallin }; 16608353fccSChris Fallin 167d8357426SChris Fallin VCodeBuilder { 168d8357426SChris Fallin vcode, 16905bf9ea3SNick Fitzgerald stack_map_info, 17072e6be93SChris Fallin block_start: 0, 171d8357426SChris Fallin succ_start: 0, 172b691770fSChris Fallin cur_srcloc: SourceLoc::default(), 173d8357426SChris Fallin } 174d8357426SChris Fallin } 175d8357426SChris Fallin 176d8357426SChris Fallin /// Access the ABI object. 177e8f772c1SChris Fallin pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> { 178d8357426SChris Fallin &mut *self.vcode.abi 179d8357426SChris Fallin } 180d8357426SChris Fallin 18172e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 18272e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 18372e6be93SChris Fallin &self.vcode.block_order 1841d90751bSBenjamin Bouvier } 1851d90751bSBenjamin Bouvier 186d8357426SChris Fallin /// Set the type of a VReg. 187d8357426SChris Fallin pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 18848f0b10cSJohnnie Birch if self.vcode.vreg_types.len() <= vreg.get_index() { 189ef5de04dSBenjamin Bouvier self.vcode 190ef5de04dSBenjamin Bouvier .vreg_types 191ef5de04dSBenjamin Bouvier .resize(vreg.get_index() + 1, ir::types::I8); 192d8357426SChris Fallin } 193d8357426SChris Fallin self.vcode.vreg_types[vreg.get_index()] = ty; 19408353fccSChris Fallin if is_reftype(ty) { 19505bf9ea3SNick Fitzgerald self.stack_map_info.reftyped_vregs.push(vreg); 19608353fccSChris Fallin self.vcode.have_ref_values = true; 19708353fccSChris Fallin } 19808353fccSChris Fallin } 19908353fccSChris Fallin 20008353fccSChris Fallin /// Are there any reference-typed values at all among the vregs? 20108353fccSChris Fallin pub fn have_ref_values(&self) -> bool { 20208353fccSChris Fallin self.vcode.have_ref_values() 203d8357426SChris Fallin } 204d8357426SChris Fallin 205d8357426SChris Fallin /// Set the current block as the entry block. 206d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 207d8357426SChris Fallin self.vcode.entry = block; 208d8357426SChris Fallin } 209d8357426SChris Fallin 210d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 211d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 21272e6be93SChris Fallin pub fn end_bb(&mut self) { 21372e6be93SChris Fallin let start_idx = self.block_start; 214d8357426SChris Fallin let end_idx = self.vcode.insts.len() as InsnIndex; 21572e6be93SChris Fallin self.block_start = end_idx; 216d8357426SChris Fallin // Add the instruction index range to the list of blocks. 217d8357426SChris Fallin self.vcode.block_ranges.push((start_idx, end_idx)); 218d8357426SChris Fallin // End the successors list. 219d8357426SChris Fallin let succ_end = self.vcode.block_succs.len(); 220d8357426SChris Fallin self.vcode 221d8357426SChris Fallin .block_succ_range 222d8357426SChris Fallin .push((self.succ_start, succ_end)); 223d8357426SChris Fallin self.succ_start = succ_end; 224d8357426SChris Fallin } 225d8357426SChris Fallin 226d8357426SChris Fallin /// Push an instruction for the current BB and current IR inst within the BB. 22708353fccSChris Fallin pub fn push(&mut self, insn: I, is_safepoint: bool) { 228d8357426SChris Fallin match insn.is_term() { 229d8357426SChris Fallin MachTerminator::None | MachTerminator::Ret => {} 230d8357426SChris Fallin MachTerminator::Uncond(target) => { 23172e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(target.get())); 232d8357426SChris Fallin } 233d8357426SChris Fallin MachTerminator::Cond(true_branch, false_branch) => { 23472e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(true_branch.get())); 23572e6be93SChris Fallin self.vcode 23672e6be93SChris Fallin .block_succs 23772e6be93SChris Fallin .push(BlockIx::new(false_branch.get())); 238d8357426SChris Fallin } 239d8357426SChris Fallin MachTerminator::Indirect(targets) => { 240d8357426SChris Fallin for target in targets { 24172e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(target.get())); 242d8357426SChris Fallin } 243d8357426SChris Fallin } 244d8357426SChris Fallin } 24572e6be93SChris Fallin self.vcode.insts.push(insn); 24672e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 24708353fccSChris Fallin if is_safepoint { 24805bf9ea3SNick Fitzgerald self.stack_map_info 24908353fccSChris Fallin .safepoint_insns 25008353fccSChris Fallin .push(InstIx::new((self.vcode.insts.len() - 1) as u32)); 25108353fccSChris Fallin } 25272e6be93SChris Fallin } 25372e6be93SChris Fallin 25472e6be93SChris Fallin /// Get the current source location. 25572e6be93SChris Fallin pub fn get_srcloc(&self) -> SourceLoc { 25672e6be93SChris Fallin self.cur_srcloc 257b691770fSChris Fallin } 258b691770fSChris Fallin 259b691770fSChris Fallin /// Set the current source location. 260b691770fSChris Fallin pub fn set_srcloc(&mut self, srcloc: SourceLoc) { 261b691770fSChris Fallin self.cur_srcloc = srcloc; 262d8357426SChris Fallin } 263d8357426SChris Fallin 26483f182b3SAndrew Brown /// Access the constants. 26583f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 26683f182b3SAndrew Brown &mut self.vcode.constants 26783f182b3SAndrew Brown } 26883f182b3SAndrew Brown 26908353fccSChris Fallin /// Build the final VCode, returning the vcode itself as well as auxiliary 27008353fccSChris Fallin /// information, such as the stack map request information. 27108353fccSChris Fallin pub fn build(self) -> (VCode<I>, StackmapRequestInfo) { 27208353fccSChris Fallin // TODO: come up with an abstraction for "vcode and auxiliary data". The 27308353fccSChris Fallin // auxiliary data needs to be separate from the vcode so that it can be 27408353fccSChris Fallin // referenced as the vcode is mutated (e.g. by the register allocator). 27505bf9ea3SNick Fitzgerald (self.vcode, self.stack_map_info) 276d8357426SChris Fallin } 277d8357426SChris Fallin } 278d8357426SChris Fallin 279d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool { 280d8357426SChris Fallin if let Some((to, from)) = insn.is_move() { 281d8357426SChris Fallin to.to_reg() == from 282d8357426SChris Fallin } else { 283d8357426SChris Fallin false 284d8357426SChris Fallin } 285d8357426SChris Fallin } 286d8357426SChris Fallin 28708353fccSChris Fallin /// Is this type a reference type? 28808353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 28926529006SChris Fallin ty == types::R64 || ty == types::R32 29008353fccSChris Fallin } 29108353fccSChris Fallin 292d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 293d8357426SChris Fallin /// New empty VCode. 294c5bbc874SBenjamin Bouvier fn new( 295c5bbc874SBenjamin Bouvier abi: Box<dyn ABICallee<I = I>>, 296c5bbc874SBenjamin Bouvier emit_info: I::Info, 297c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 29883f182b3SAndrew Brown constants: VCodeConstants, 299c5bbc874SBenjamin Bouvier ) -> VCode<I> { 300d8357426SChris Fallin VCode { 301d8357426SChris Fallin liveins: abi.liveins(), 302d8357426SChris Fallin liveouts: abi.liveouts(), 303d8357426SChris Fallin vreg_types: vec![], 30408353fccSChris Fallin have_ref_values: false, 305d8357426SChris Fallin insts: vec![], 306b691770fSChris Fallin srclocs: vec![], 307d8357426SChris Fallin entry: 0, 308d8357426SChris Fallin block_ranges: vec![], 309d8357426SChris Fallin block_succ_range: vec![], 310d8357426SChris Fallin block_succs: vec![], 31172e6be93SChris Fallin block_order, 312d8357426SChris Fallin abi, 313c5bbc874SBenjamin Bouvier emit_info, 31408353fccSChris Fallin safepoint_insns: vec![], 31508353fccSChris Fallin safepoint_slots: vec![], 316de4af90aSYury Delendik prologue_epilogue_ranges: None, 317de4af90aSYury Delendik insts_layout: RefCell::new((vec![], 0)), 31883f182b3SAndrew Brown constants, 319d8357426SChris Fallin } 320d8357426SChris Fallin } 321d8357426SChris Fallin 322d1b5df31SBenjamin Bouvier /// Returns the flags controlling this function's compilation. 323d1b5df31SBenjamin Bouvier pub fn flags(&self) -> &settings::Flags { 324d1b5df31SBenjamin Bouvier self.abi.flags() 325d1b5df31SBenjamin Bouvier } 326d1b5df31SBenjamin Bouvier 327d8357426SChris Fallin /// Get the IR-level type of a VReg. 328d8357426SChris Fallin pub fn vreg_type(&self, vreg: VirtualReg) -> Type { 329d8357426SChris Fallin self.vreg_types[vreg.get_index()] 330d8357426SChris Fallin } 331d8357426SChris Fallin 33208353fccSChris Fallin /// Are there any reference-typed values at all among the vregs? 33308353fccSChris Fallin pub fn have_ref_values(&self) -> bool { 33408353fccSChris Fallin self.have_ref_values 33508353fccSChris Fallin } 33608353fccSChris Fallin 337d8357426SChris Fallin /// Get the entry block. 338d8357426SChris Fallin pub fn entry(&self) -> BlockIndex { 339d8357426SChris Fallin self.entry 340d8357426SChris Fallin } 341d8357426SChris Fallin 342d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 343d8357426SChris Fallin /// (self.num_blocks() - 1)`. 344d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 345d8357426SChris Fallin self.block_ranges.len() 346d8357426SChris Fallin } 347d8357426SChris Fallin 348d8357426SChris Fallin /// Stack frame size for the full function's body. 349d8357426SChris Fallin pub fn frame_size(&self) -> u32 { 350d8357426SChris Fallin self.abi.frame_size() 351d8357426SChris Fallin } 352d8357426SChris Fallin 35308353fccSChris Fallin /// Inbound stack-args size. 35408353fccSChris Fallin pub fn stack_args_size(&self) -> u32 { 35508353fccSChris Fallin self.abi.stack_args_size() 35608353fccSChris Fallin } 35708353fccSChris Fallin 358d8357426SChris Fallin /// Get the successors for a block. 3594f919c64SBenjamin Bouvier pub fn succs(&self, block: BlockIndex) -> &[BlockIx] { 360d8357426SChris Fallin let (start, end) = self.block_succ_range[block as usize]; 361d8357426SChris Fallin &self.block_succs[start..end] 362d8357426SChris Fallin } 363d8357426SChris Fallin 364d8357426SChris Fallin /// Take the results of register allocation, with a sequence of 365d8357426SChris Fallin /// instructions including spliced fill/reload/move instructions, and replace 366d8357426SChris Fallin /// the VCode with them. 367d1b5df31SBenjamin Bouvier pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) { 368d8357426SChris Fallin // Record the spillslot count and clobbered registers for the ABI/stack 369d8357426SChris Fallin // setup code. 370d8357426SChris Fallin self.abi.set_num_spillslots(result.num_spill_slots as usize); 371d8357426SChris Fallin self.abi 372d8357426SChris Fallin .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r))); 373d8357426SChris Fallin 374d8357426SChris Fallin let mut final_insns = vec![]; 375d8357426SChris Fallin let mut final_block_ranges = vec![(0, 0); self.num_blocks()]; 376b691770fSChris Fallin let mut final_srclocs = vec![]; 37708353fccSChris Fallin let mut final_safepoint_insns = vec![]; 37808353fccSChris Fallin let mut safept_idx = 0; 379d8357426SChris Fallin 380de4af90aSYury Delendik let mut prologue_start = None; 381de4af90aSYury Delendik let mut prologue_end = None; 382de4af90aSYury Delendik let mut epilogue_islands = vec![]; 383de4af90aSYury Delendik 38408353fccSChris Fallin assert!(result.target_map.elems().len() == self.num_blocks()); 38572e6be93SChris Fallin for block in 0..self.num_blocks() { 38608353fccSChris Fallin let start = result.target_map.elems()[block].get() as usize; 38708353fccSChris Fallin let end = if block == self.num_blocks() - 1 { 38808353fccSChris Fallin result.insns.len() 38908353fccSChris Fallin } else { 39008353fccSChris Fallin result.target_map.elems()[block + 1].get() as usize 39108353fccSChris Fallin }; 39272e6be93SChris Fallin let block = block as BlockIndex; 393d8357426SChris Fallin let final_start = final_insns.len() as InsnIndex; 394d8357426SChris Fallin 39572e6be93SChris Fallin if block == self.entry { 396de4af90aSYury Delendik prologue_start = Some(final_insns.len() as InsnIndex); 397d8357426SChris Fallin // Start with the prologue. 398b691770fSChris Fallin let prologue = self.abi.gen_prologue(); 399b691770fSChris Fallin let len = prologue.len(); 400b691770fSChris Fallin final_insns.extend(prologue.into_iter()); 401b691770fSChris Fallin final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len)); 402de4af90aSYury Delendik prologue_end = Some(final_insns.len() as InsnIndex); 403d8357426SChris Fallin } 404d8357426SChris Fallin 405d8357426SChris Fallin for i in start..end { 406d8357426SChris Fallin let insn = &result.insns[i]; 407d8357426SChris Fallin 408d8357426SChris Fallin // Elide redundant moves at this point (we only know what is 409d8357426SChris Fallin // redundant once registers are allocated). 410d8357426SChris Fallin if is_redundant_move(insn) { 411d8357426SChris Fallin continue; 412d8357426SChris Fallin } 413d8357426SChris Fallin 414b691770fSChris Fallin // Is there a srcloc associated with this insn? Look it up based on original 415b691770fSChris Fallin // instruction index (if new insn corresponds to some original insn, i.e., is not 416b691770fSChris Fallin // an inserted load/spill/move). 417b691770fSChris Fallin let orig_iix = result.orig_insn_map[InstIx::new(i as u32)]; 418b691770fSChris Fallin let srcloc = if orig_iix.is_invalid() { 419b691770fSChris Fallin SourceLoc::default() 420b691770fSChris Fallin } else { 421b691770fSChris Fallin self.srclocs[orig_iix.get() as usize] 422b691770fSChris Fallin }; 423b691770fSChris Fallin 424d8357426SChris Fallin // Whenever encountering a return instruction, replace it 425d8357426SChris Fallin // with the epilogue. 426d8357426SChris Fallin let is_ret = insn.is_term() == MachTerminator::Ret; 427d8357426SChris Fallin if is_ret { 428de4af90aSYury Delendik let epilogue_start = final_insns.len() as InsnIndex; 429b691770fSChris Fallin let epilogue = self.abi.gen_epilogue(); 430b691770fSChris Fallin let len = epilogue.len(); 431b691770fSChris Fallin final_insns.extend(epilogue.into_iter()); 432b691770fSChris Fallin final_srclocs.extend(iter::repeat(srcloc).take(len)); 433de4af90aSYury Delendik epilogue_islands.push(epilogue_start..final_insns.len() as InsnIndex); 434d8357426SChris Fallin } else { 435d8357426SChris Fallin final_insns.push(insn.clone()); 436b691770fSChris Fallin final_srclocs.push(srcloc); 437d8357426SChris Fallin } 43808353fccSChris Fallin 43908353fccSChris Fallin // Was this instruction a safepoint instruction? Add its final 44008353fccSChris Fallin // index to the safepoint insn-index list if so. 44108353fccSChris Fallin if safept_idx < result.new_safepoint_insns.len() 44208353fccSChris Fallin && (result.new_safepoint_insns[safept_idx].get() as usize) == i 44308353fccSChris Fallin { 44408353fccSChris Fallin let idx = final_insns.len() - 1; 44508353fccSChris Fallin final_safepoint_insns.push(idx as InsnIndex); 44608353fccSChris Fallin safept_idx += 1; 44708353fccSChris Fallin } 448d8357426SChris Fallin } 449d8357426SChris Fallin 450d8357426SChris Fallin let final_end = final_insns.len() as InsnIndex; 45172e6be93SChris Fallin final_block_ranges[block as usize] = (final_start, final_end); 452d8357426SChris Fallin } 453d8357426SChris Fallin 454b691770fSChris Fallin debug_assert!(final_insns.len() == final_srclocs.len()); 455b691770fSChris Fallin 456d8357426SChris Fallin self.insts = final_insns; 457b691770fSChris Fallin self.srclocs = final_srclocs; 458d8357426SChris Fallin self.block_ranges = final_block_ranges; 45908353fccSChris Fallin self.safepoint_insns = final_safepoint_insns; 46008353fccSChris Fallin 46108353fccSChris Fallin // Save safepoint slot-lists. These will be passed to the `EmitState` 46208353fccSChris Fallin // for the machine backend during emission so that it can do 46308353fccSChris Fallin // target-specific translations of slot numbers to stack offsets. 46408353fccSChris Fallin self.safepoint_slots = result.stackmaps; 465de4af90aSYury Delendik 466de4af90aSYury Delendik self.prologue_epilogue_ranges = Some(( 467de4af90aSYury Delendik prologue_start.unwrap()..prologue_end.unwrap(), 468de4af90aSYury Delendik epilogue_islands.into_boxed_slice(), 469de4af90aSYury Delendik )); 470d8357426SChris Fallin } 471d8357426SChris Fallin 47272e6be93SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up code and external 47372e6be93SChris Fallin /// reloc/trap/etc. records ready for use. 47472e6be93SChris Fallin pub fn emit(&self) -> MachBuffer<I> 475d8357426SChris Fallin where 47672e6be93SChris Fallin I: MachInstEmit, 477d8357426SChris Fallin { 4782b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 47972e6be93SChris Fallin let mut buffer = MachBuffer::new(); 48008353fccSChris Fallin let mut state = I::State::new(&*self.abi); 481d8357426SChris Fallin 48283f182b3SAndrew Brown // The first M MachLabels are reserved for block indices, the next N MachLabels for 48383f182b3SAndrew Brown // constants. 48483f182b3SAndrew Brown buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex); 48583f182b3SAndrew Brown buffer.reserve_labels_for_constants(&self.constants); 486d8357426SChris Fallin 487de4af90aSYury Delendik let mut insts_layout = vec![0; self.insts.len()]; 488de4af90aSYury Delendik 48908353fccSChris Fallin let mut safepoint_idx = 0; 490964c6087SChris Fallin let mut cur_srcloc = None; 49172e6be93SChris Fallin for block in 0..self.num_blocks() { 49272e6be93SChris Fallin let block = block as BlockIndex; 49372e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 49472e6be93SChris Fallin while new_offset > buffer.cur_offset() { 495d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 49672e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 497c5bbc874SBenjamin Bouvier nop.emit(&mut buffer, &self.emit_info, &mut Default::default()); 498d8357426SChris Fallin } 49972e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 500d8357426SChris Fallin 50148cf2c2fSChris Fallin let (start, end) = self.block_ranges[block as usize]; 50272e6be93SChris Fallin buffer.bind_label(MachLabel::from_block(block)); 503d8357426SChris Fallin for iix in start..end { 504b691770fSChris Fallin let srcloc = self.srclocs[iix as usize]; 505964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 506964c6087SChris Fallin if cur_srcloc.is_some() { 50772e6be93SChris Fallin buffer.end_srcloc(); 508b691770fSChris Fallin } 50972e6be93SChris Fallin buffer.start_srcloc(srcloc); 510964c6087SChris Fallin cur_srcloc = Some(srcloc); 511b691770fSChris Fallin } 512*4dce5109SChris Fallin state.pre_sourceloc(cur_srcloc.unwrap_or(SourceLoc::default())); 513b691770fSChris Fallin 51408353fccSChris Fallin if safepoint_idx < self.safepoint_insns.len() 51508353fccSChris Fallin && self.safepoint_insns[safepoint_idx] == iix 51608353fccSChris Fallin { 51708353fccSChris Fallin if self.safepoint_slots[safepoint_idx].len() > 0 { 51805bf9ea3SNick Fitzgerald let stack_map = self.abi.spillslots_to_stack_map( 51908353fccSChris Fallin &self.safepoint_slots[safepoint_idx][..], 52008353fccSChris Fallin &state, 52108353fccSChris Fallin ); 52205bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 52308353fccSChris Fallin } 52408353fccSChris Fallin safepoint_idx += 1; 52508353fccSChris Fallin } 52608353fccSChris Fallin 527c5bbc874SBenjamin Bouvier self.insts[iix as usize].emit(&mut buffer, &self.emit_info, &mut state); 528de4af90aSYury Delendik 529de4af90aSYury Delendik insts_layout[iix as usize] = buffer.cur_offset(); 530d8357426SChris Fallin } 531b691770fSChris Fallin 532964c6087SChris Fallin if cur_srcloc.is_some() { 53372e6be93SChris Fallin buffer.end_srcloc(); 534964c6087SChris Fallin cur_srcloc = None; 535b691770fSChris Fallin } 53672e6be93SChris Fallin 53772e6be93SChris Fallin // Do we need an island? Get the worst-case size of the next BB and see if, having 53872e6be93SChris Fallin // emitted that many bytes, we will be beyond the deadline. 53972e6be93SChris Fallin if block < (self.num_blocks() - 1) as BlockIndex { 54072e6be93SChris Fallin let next_block = block + 1; 54172e6be93SChris Fallin let next_block_range = self.block_ranges[next_block as usize]; 54272e6be93SChris Fallin let next_block_size = next_block_range.1 - next_block_range.0; 54372e6be93SChris Fallin let worst_case_next_bb = I::worst_case_size() * next_block_size; 54472e6be93SChris Fallin if buffer.island_needed(worst_case_next_bb) { 54572e6be93SChris Fallin buffer.emit_island(); 54672e6be93SChris Fallin } 54772e6be93SChris Fallin } 548d8357426SChris Fallin } 549d8357426SChris Fallin 55083f182b3SAndrew Brown // Emit the constants used by the function. 55183f182b3SAndrew Brown for (constant, data) in self.constants.iter() { 55283f182b3SAndrew Brown let label = buffer.get_label_for_constant(constant); 55383f182b3SAndrew Brown buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value()); 55483f182b3SAndrew Brown } 55583f182b3SAndrew Brown 556de4af90aSYury Delendik *self.insts_layout.borrow_mut() = (insts_layout, buffer.cur_offset()); 557de4af90aSYury Delendik 55872e6be93SChris Fallin buffer 559d8357426SChris Fallin } 560d8357426SChris Fallin 561de4af90aSYury Delendik /// Generates unwind info. 562de4af90aSYury Delendik pub fn unwind_info( 563de4af90aSYury Delendik &self, 564f60c0f3eSYury Delendik ) -> crate::result::CodegenResult<Option<crate::isa::unwind::input::UnwindInfo<Reg>>> { 565de4af90aSYury Delendik let layout = &self.insts_layout.borrow(); 566de4af90aSYury Delendik let (prologue, epilogues) = self.prologue_epilogue_ranges.as_ref().unwrap(); 567de4af90aSYury Delendik let context = UnwindInfoContext { 568de4af90aSYury Delendik insts: &self.insts, 569de4af90aSYury Delendik insts_layout: &layout.0, 570de4af90aSYury Delendik len: layout.1, 571de4af90aSYury Delendik prologue: prologue.clone(), 572de4af90aSYury Delendik epilogues, 573de4af90aSYury Delendik }; 574f60c0f3eSYury Delendik I::UnwindInfo::create_unwind_info(context) 575de4af90aSYury Delendik } 576de4af90aSYury Delendik 577d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 578d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 57972e6be93SChris Fallin self.block_order.lowered_order()[block as usize].orig_block() 580d8357426SChris Fallin } 581d8357426SChris Fallin } 582d8357426SChris Fallin 583d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 584d8357426SChris Fallin type Inst = I; 585d8357426SChris Fallin 586d8357426SChris Fallin fn insns(&self) -> &[I] { 587d8357426SChris Fallin &self.insts[..] 588d8357426SChris Fallin } 589d8357426SChris Fallin 590d8357426SChris Fallin fn insns_mut(&mut self) -> &mut [I] { 591d8357426SChris Fallin &mut self.insts[..] 592d8357426SChris Fallin } 593d8357426SChris Fallin 594d8357426SChris Fallin fn get_insn(&self, insn: InstIx) -> &I { 595d8357426SChris Fallin &self.insts[insn.get() as usize] 596d8357426SChris Fallin } 597d8357426SChris Fallin 598d8357426SChris Fallin fn get_insn_mut(&mut self, insn: InstIx) -> &mut I { 599d8357426SChris Fallin &mut self.insts[insn.get() as usize] 600d8357426SChris Fallin } 601d8357426SChris Fallin 602d8357426SChris Fallin fn blocks(&self) -> Range<BlockIx> { 603d8357426SChris Fallin Range::new(BlockIx::new(0), self.block_ranges.len()) 604d8357426SChris Fallin } 605d8357426SChris Fallin 606d8357426SChris Fallin fn entry_block(&self) -> BlockIx { 607d8357426SChris Fallin BlockIx::new(self.entry) 608d8357426SChris Fallin } 609d8357426SChris Fallin 610d8357426SChris Fallin fn block_insns(&self, block: BlockIx) -> Range<InstIx> { 611d8357426SChris Fallin let (start, end) = self.block_ranges[block.get() as usize]; 612d8357426SChris Fallin Range::new(InstIx::new(start), (end - start) as usize) 613d8357426SChris Fallin } 614d8357426SChris Fallin 6154f919c64SBenjamin Bouvier fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> { 616d8357426SChris Fallin let (start, end) = self.block_succ_range[block.get() as usize]; 6174f919c64SBenjamin Bouvier Cow::Borrowed(&self.block_succs[start..end]) 618d8357426SChris Fallin } 619d8357426SChris Fallin 620d8357426SChris Fallin fn is_ret(&self, insn: InstIx) -> bool { 621d8357426SChris Fallin match self.insts[insn.get() as usize].is_term() { 622d8357426SChris Fallin MachTerminator::Ret => true, 623d8357426SChris Fallin _ => false, 624d8357426SChris Fallin } 625d8357426SChris Fallin } 626d8357426SChris Fallin 62771768bb6SChris Fallin fn is_included_in_clobbers(&self, insn: &I) -> bool { 62871768bb6SChris Fallin insn.is_included_in_clobbers() 62971768bb6SChris Fallin } 63071768bb6SChris Fallin 631d8357426SChris Fallin fn get_regs(insn: &I, collector: &mut RegUsageCollector) { 632d8357426SChris Fallin insn.get_regs(collector) 633d8357426SChris Fallin } 634d8357426SChris Fallin 6351f620e1bSBenjamin Bouvier fn map_regs<RUM: RegUsageMapper>(insn: &mut I, mapper: &RUM) { 636be6f060aSChris Fallin insn.map_regs(mapper); 637d8357426SChris Fallin } 638d8357426SChris Fallin 639d8357426SChris Fallin fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> { 640d8357426SChris Fallin insn.is_move() 641d8357426SChris Fallin } 642d8357426SChris Fallin 64346093f61SBenjamin Bouvier fn get_num_vregs(&self) -> usize { 64446093f61SBenjamin Bouvier self.vreg_types.len() 645be6f060aSChris Fallin } 646be6f060aSChris Fallin 647d8357426SChris Fallin fn get_spillslot_size(&self, regclass: RegClass, vreg: VirtualReg) -> u32 { 648d8357426SChris Fallin let ty = self.vreg_type(vreg); 649d8357426SChris Fallin self.abi.get_spillslot_size(regclass, ty) 650d8357426SChris Fallin } 651d8357426SChris Fallin 65208353fccSChris Fallin fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, vreg: Option<VirtualReg>) -> I { 65308353fccSChris Fallin let ty = vreg.map(|v| self.vreg_type(v)); 654d8357426SChris Fallin self.abi.gen_spill(to_slot, from_reg, ty) 655d8357426SChris Fallin } 656d8357426SChris Fallin 65708353fccSChris Fallin fn gen_reload( 65808353fccSChris Fallin &self, 65908353fccSChris Fallin to_reg: Writable<RealReg>, 66008353fccSChris Fallin from_slot: SpillSlot, 66108353fccSChris Fallin vreg: Option<VirtualReg>, 66208353fccSChris Fallin ) -> I { 66308353fccSChris Fallin let ty = vreg.map(|v| self.vreg_type(v)); 664d8357426SChris Fallin self.abi.gen_reload(to_reg, from_slot, ty) 665d8357426SChris Fallin } 666d8357426SChris Fallin 667d8357426SChris Fallin fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I { 668d8357426SChris Fallin let ty = self.vreg_type(vreg); 669d8357426SChris Fallin I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty) 670d8357426SChris Fallin } 671d8357426SChris Fallin 672d8357426SChris Fallin fn gen_zero_len_nop(&self) -> I { 673d8357426SChris Fallin I::gen_zero_len_nop() 674d8357426SChris Fallin } 675d8357426SChris Fallin 676d8357426SChris Fallin fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> { 677d8357426SChris Fallin insn.maybe_direct_reload(reg, slot) 678d8357426SChris Fallin } 679d8357426SChris Fallin 680d8357426SChris Fallin fn func_liveins(&self) -> RegallocSet<RealReg> { 681d8357426SChris Fallin self.liveins.clone() 682d8357426SChris Fallin } 683d8357426SChris Fallin 684d8357426SChris Fallin fn func_liveouts(&self) -> RegallocSet<RealReg> { 685d8357426SChris Fallin self.liveouts.clone() 686d8357426SChris Fallin } 687d8357426SChris Fallin } 688d8357426SChris Fallin 689d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 690d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 691d8357426SChris Fallin writeln!(f, "VCode_Debug {{")?; 692d8357426SChris Fallin writeln!(f, " Entry block: {}", self.entry)?; 693d8357426SChris Fallin 694d8357426SChris Fallin for block in 0..self.num_blocks() { 695d8357426SChris Fallin writeln!(f, "Block {}:", block,)?; 696d8357426SChris Fallin for succ in self.succs(block as BlockIndex) { 6974f919c64SBenjamin Bouvier writeln!(f, " (successor: Block {})", succ.get())?; 698d8357426SChris Fallin } 699d8357426SChris Fallin let (start, end) = self.block_ranges[block]; 700d8357426SChris Fallin writeln!(f, " (instruction range: {} .. {})", start, end)?; 701d8357426SChris Fallin for inst in start..end { 702d8357426SChris Fallin writeln!(f, " Inst {}: {:?}", inst, self.insts[inst as usize])?; 703d8357426SChris Fallin } 704d8357426SChris Fallin } 705d8357426SChris Fallin 706d8357426SChris Fallin writeln!(f, "}}")?; 707d8357426SChris Fallin Ok(()) 708d8357426SChris Fallin } 709d8357426SChris Fallin } 710d8357426SChris Fallin 71148cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context. 71271768bb6SChris Fallin impl<I: VCodeInst> PrettyPrint for VCode<I> { 713d8357426SChris Fallin fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String { 714d8357426SChris Fallin use std::fmt::Write; 715d8357426SChris Fallin 716d8357426SChris Fallin let mut s = String::new(); 71748cf2c2fSChris Fallin write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap(); 71848cf2c2fSChris Fallin write!(&mut s, " Entry block: {}\n", self.entry).unwrap(); 719d8357426SChris Fallin 72008353fccSChris Fallin let mut state = Default::default(); 72108353fccSChris Fallin let mut safepoint_idx = 0; 722d8357426SChris Fallin for i in 0..self.num_blocks() { 72372e6be93SChris Fallin let block = i as BlockIndex; 724d8357426SChris Fallin 72572e6be93SChris Fallin write!(&mut s, "Block {}:\n", block).unwrap(); 72672e6be93SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 72748cf2c2fSChris Fallin write!(&mut s, " (original IR block: {})\n", bb).unwrap(); 728d8357426SChris Fallin } 72972e6be93SChris Fallin for succ in self.succs(block) { 7304f919c64SBenjamin Bouvier write!(&mut s, " (successor: Block {})\n", succ.get()).unwrap(); 731d8357426SChris Fallin } 73272e6be93SChris Fallin let (start, end) = self.block_ranges[block as usize]; 73348cf2c2fSChris Fallin write!(&mut s, " (instruction range: {} .. {})\n", start, end).unwrap(); 734d8357426SChris Fallin for inst in start..end { 73508353fccSChris Fallin if safepoint_idx < self.safepoint_insns.len() 73608353fccSChris Fallin && self.safepoint_insns[safepoint_idx] == inst 73708353fccSChris Fallin { 73808353fccSChris Fallin write!( 73908353fccSChris Fallin &mut s, 74008353fccSChris Fallin " (safepoint: slots {:?} with EmitState {:?})\n", 74108353fccSChris Fallin self.safepoint_slots[safepoint_idx], state, 74208353fccSChris Fallin ) 74308353fccSChris Fallin .unwrap(); 74408353fccSChris Fallin safepoint_idx += 1; 74508353fccSChris Fallin } 74648cf2c2fSChris Fallin write!( 74748cf2c2fSChris Fallin &mut s, 74848cf2c2fSChris Fallin " Inst {}: {}\n", 749d8357426SChris Fallin inst, 75008353fccSChris Fallin self.insts[inst as usize].pretty_print(mb_rru, &mut state) 75148cf2c2fSChris Fallin ) 75248cf2c2fSChris Fallin .unwrap(); 753d8357426SChris Fallin } 754d8357426SChris Fallin } 755d8357426SChris Fallin 75648cf2c2fSChris Fallin write!(&mut s, "}}}}\n").unwrap(); 757d8357426SChris Fallin 758d8357426SChris Fallin s 759d8357426SChris Fallin } 760d8357426SChris Fallin } 76183f182b3SAndrew Brown 76283f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 76383f182b3SAndrew Brown /// [MachBuffer]. 76483f182b3SAndrew Brown /// 76583f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 76683f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are 76783f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 76883f182b3SAndrew Brown /// values are inserted. 76983f182b3SAndrew Brown /// 77083f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 77183f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 77283f182b3SAndrew Brown /// then writes the constant values to the buffer. 77383f182b3SAndrew Brown #[derive(Default)] 77483f182b3SAndrew Brown pub struct VCodeConstants { 77583f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 77683f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 77783f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 77883f182b3SAndrew Brown } 77983f182b3SAndrew Brown impl VCodeConstants { 78083f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 78183f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 78283f182b3SAndrew Brown Self { 78383f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 78483f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 78583f182b3SAndrew Brown well_known_uses: HashMap::new(), 78683f182b3SAndrew Brown } 78783f182b3SAndrew Brown } 78883f182b3SAndrew Brown 78983f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 79083f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 79183f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 79283f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 79383f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 79483f182b3SAndrew Brown match data { 79583f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 79683f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 79783f182b3SAndrew Brown None => { 79883f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 79983f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 80083f182b3SAndrew Brown vcode_constant 80183f182b3SAndrew Brown } 80283f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 80383f182b3SAndrew Brown }, 80483f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 80583f182b3SAndrew Brown match self.well_known_uses.get(&(data_ref as *const [u8])) { 80683f182b3SAndrew Brown None => { 80783f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 80883f182b3SAndrew Brown self.well_known_uses 80983f182b3SAndrew Brown .insert(data_ref as *const [u8], vcode_constant); 81083f182b3SAndrew Brown vcode_constant 81183f182b3SAndrew Brown } 81283f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 81383f182b3SAndrew Brown } 81483f182b3SAndrew Brown } 81583f182b3SAndrew Brown } 81683f182b3SAndrew Brown } 81783f182b3SAndrew Brown 81883f182b3SAndrew Brown /// Retrieve a byte slice for the given [VCodeConstant], if available. 81983f182b3SAndrew Brown pub fn get(&self, constant: VCodeConstant) -> Option<&[u8]> { 82083f182b3SAndrew Brown self.constants.get(constant).map(|d| d.as_slice()) 82183f182b3SAndrew Brown } 82283f182b3SAndrew Brown 82383f182b3SAndrew Brown /// Return the number of constants inserted. 82483f182b3SAndrew Brown pub fn len(&self) -> usize { 82583f182b3SAndrew Brown self.constants.len() 82683f182b3SAndrew Brown } 82783f182b3SAndrew Brown 82883f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys inserted in this structure. 82983f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 83083f182b3SAndrew Brown self.constants.keys() 83183f182b3SAndrew Brown } 83283f182b3SAndrew Brown 83383f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this 83483f182b3SAndrew Brown /// structure. 83583f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 83683f182b3SAndrew Brown self.constants.iter() 83783f182b3SAndrew Brown } 83883f182b3SAndrew Brown } 83983f182b3SAndrew Brown 84083f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 84183f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 84283f182b3SAndrew Brown pub struct VCodeConstant(u32); 84383f182b3SAndrew Brown entity_impl!(VCodeConstant); 84483f182b3SAndrew Brown 84583f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 84683f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 84783f182b3SAndrew Brown pub enum VCodeConstantData { 84883f182b3SAndrew Brown /// A constant already present in the Cranelift IR 84983f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 85083f182b3SAndrew Brown Pool(Constant, ConstantData), 85183f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 85283f182b3SAndrew Brown WellKnown(&'static [u8]), 85383f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 85483f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 85583f182b3SAndrew Brown Generated(ConstantData), 85683f182b3SAndrew Brown } 85783f182b3SAndrew Brown impl VCodeConstantData { 85883f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 85983f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 86083f182b3SAndrew Brown match self { 86183f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 86283f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 86383f182b3SAndrew Brown } 86483f182b3SAndrew Brown } 86583f182b3SAndrew Brown 86683f182b3SAndrew Brown /// Calculate the alignment of the constant data. 86783f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 86883f182b3SAndrew Brown if self.as_slice().len() <= 8 { 86983f182b3SAndrew Brown 8 87083f182b3SAndrew Brown } else { 87183f182b3SAndrew Brown 16 87283f182b3SAndrew Brown } 87383f182b3SAndrew Brown } 87483f182b3SAndrew Brown } 87583f182b3SAndrew Brown 87683f182b3SAndrew Brown #[cfg(test)] 87783f182b3SAndrew Brown mod test { 87883f182b3SAndrew Brown use super::*; 87983f182b3SAndrew Brown use std::mem::{size_of, size_of_val}; 88083f182b3SAndrew Brown 88183f182b3SAndrew Brown #[test] 88283f182b3SAndrew Brown fn size_of_constant_structs() { 88383f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 88483f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 88583f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 88683f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 88783f182b3SAndrew Brown assert_eq!( 88883f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 88983f182b3SAndrew Brown 24 89083f182b3SAndrew Brown ); 89183f182b3SAndrew Brown assert_eq!(size_of::<HashMap<Constant, VCodeConstant>>(), 48); 89283f182b3SAndrew Brown assert_eq!(size_of::<HashMap<*const [u8], VCodeConstant>>(), 48); 89383f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstants>(), 120); 89483f182b3SAndrew Brown assert_eq!(size_of_val(&VCodeConstants::with_capacity(0)), 120); 89583f182b3SAndrew Brown // TODO This structure could use some significant memory-size optimization. The use of 89683f182b3SAndrew Brown // HashMap to deduplicate both pool and well-known constants is clearly an issue. 89783f182b3SAndrew Brown } 89883f182b3SAndrew Brown } 899