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 20666c2554SChris Fallin use crate::fx::FxHashMap; 21a0318f36SChris Fallin use crate::fx::FxHashSet; 229c43749dSSam Parker use crate::ir::{ 239c43749dSSam Parker self, types, Constant, ConstantData, DynamicStackSlot, LabelValueLoc, SourceLoc, ValueLabel, 249c43749dSSam Parker }; 25d8357426SChris Fallin use crate::machinst::*; 262b9fefe8SChris Fallin use crate::timing; 27a0318f36SChris Fallin use crate::ValueLocRange; 28a0318f36SChris Fallin use regalloc2::{ 29b2e28b91SChris Fallin Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PReg, PRegSet, 30a0318f36SChris Fallin RegClass, VReg, 31be6f060aSChris Fallin }; 32d8357426SChris Fallin 33d8357426SChris Fallin use alloc::boxed::Box; 34a0318f36SChris Fallin use alloc::vec::Vec; 3583f182b3SAndrew Brown use cranelift_entity::{entity_impl, Keys, PrimaryMap}; 36eb435f30SChris Fallin use std::collections::hash_map::Entry; 3783f182b3SAndrew Brown use std::collections::HashMap; 38d8357426SChris Fallin use std::fmt; 39d8357426SChris Fallin 40d8357426SChris Fallin /// Index referring to an instruction in VCode. 41a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst; 42a0318f36SChris Fallin 43d8357426SChris Fallin /// Index referring to a basic block in VCode. 44a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block; 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 51a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after 52a0318f36SChris Fallin /// lowering. This is essentially a standard CFG of basic blocks, 53a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced 54a0318f36SChris Fallin /// by the machine-specific backend. 55a0318f36SChris Fallin /// 56a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not 57a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register 58a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output` 59a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not 60a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the 61a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or 62a0318f36SChris Fallin /// metadata as requested. 63d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 64d8357426SChris Fallin /// VReg IR-level types. 65d8357426SChris Fallin vreg_types: Vec<Type>, 66d8357426SChris Fallin 6708353fccSChris Fallin /// Do we have any ref values among our vregs? 6808353fccSChris Fallin have_ref_values: bool, 6908353fccSChris Fallin 70d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 7148cf2c2fSChris Fallin insts: Vec<I>, 72d8357426SChris Fallin 73a0318f36SChris Fallin /// Operands: pre-regalloc references to virtual registers with 74a0318f36SChris Fallin /// constraints, in one flattened array. This allows the regalloc 75a0318f36SChris Fallin /// to efficiently access all operands without requiring expensive 76a0318f36SChris Fallin /// matches or method invocations on insts. 77a0318f36SChris Fallin operands: Vec<Operand>, 78a0318f36SChris Fallin 79a0318f36SChris Fallin /// Operand index ranges: for each instruction in `insts`, there 80a0318f36SChris Fallin /// is a tuple here providing the range in `operands` for that 81a0318f36SChris Fallin /// instruction's operands. 82a0318f36SChris Fallin operand_ranges: Vec<(u32, u32)>, 83a0318f36SChris Fallin 84b2e28b91SChris Fallin /// Clobbers: a sparse map from instruction indices to clobber masks. 85b2e28b91SChris Fallin clobbers: FxHashMap<InsnIndex, PRegSet>, 86a0318f36SChris Fallin 87a0318f36SChris Fallin /// Move information: for a given InsnIndex, (src, dst) operand pair. 88a0318f36SChris Fallin is_move: FxHashMap<InsnIndex, (Operand, Operand)>, 89a0318f36SChris Fallin 90b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 91b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 92b691770fSChris Fallin srclocs: Vec<SourceLoc>, 93b691770fSChris Fallin 94d8357426SChris Fallin /// Entry block. 95d8357426SChris Fallin entry: BlockIndex, 96d8357426SChris Fallin 97d8357426SChris Fallin /// Block instruction indices. 9848cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 99d8357426SChris Fallin 100a0318f36SChris Fallin /// Block successors: index range in the `block_succs_preds` list. 101a0318f36SChris Fallin block_succ_range: Vec<(u32, u32)>, 102d8357426SChris Fallin 103a0318f36SChris Fallin /// Block predecessors: index range in the `block_succs_preds` list. 104a0318f36SChris Fallin block_pred_range: Vec<(u32, u32)>, 105a0318f36SChris Fallin 106a0318f36SChris Fallin /// Block successor and predecessor lists, concatenated into one 107a0318f36SChris Fallin /// Vec. The `block_succ_range` and `block_pred_range` lists of 108a0318f36SChris Fallin /// tuples above give (start, end) ranges within this list that 109a0318f36SChris Fallin /// correspond to each basic block's successors or predecessors, 110a0318f36SChris Fallin /// respectively. 111a0318f36SChris Fallin block_succs_preds: Vec<regalloc2::Block>, 112a0318f36SChris Fallin 113a0318f36SChris Fallin /// Block parameters: index range in `block_params` below. 114a0318f36SChris Fallin block_params_range: Vec<(u32, u32)>, 115a0318f36SChris Fallin 116a0318f36SChris Fallin /// Block parameter lists, concatenated into one vec. The 117a0318f36SChris Fallin /// `block_params_range` list of tuples above gives (start, end) 118a0318f36SChris Fallin /// ranges within this list that correspond to each basic block's 119a0318f36SChris Fallin /// blockparam vregs. 120a0318f36SChris Fallin block_params: Vec<regalloc2::VReg>, 121a0318f36SChris Fallin 122a0318f36SChris Fallin /// Outgoing block arguments on branch instructions, concatenated 123a0318f36SChris Fallin /// into one list. 124a0318f36SChris Fallin /// 125a0318f36SChris Fallin /// Note that this is conceptually a 3D array: we have a VReg list 126a0318f36SChris Fallin /// per block, per successor. We flatten those three dimensions 127a0318f36SChris Fallin /// into this 1D vec, then store index ranges in two levels of 128a0318f36SChris Fallin /// indirection. 129a0318f36SChris Fallin /// 130a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 131a0318f36SChris Fallin branch_block_args: Vec<regalloc2::VReg>, 132a0318f36SChris Fallin 133a0318f36SChris Fallin /// Array of sequences of (start, end) tuples in 134a0318f36SChris Fallin /// `branch_block_args`, one for each successor; these sequences 135a0318f36SChris Fallin /// for each block are concatenated. 136a0318f36SChris Fallin /// 137a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 138a0318f36SChris Fallin branch_block_arg_range: Vec<(u32, u32)>, 139a0318f36SChris Fallin 140a0318f36SChris Fallin /// For a given block, indices in `branch_block_arg_range` 141a0318f36SChris Fallin /// corresponding to all of its successors. 142a0318f36SChris Fallin branch_block_arg_succ_range: Vec<(u32, u32)>, 143a0318f36SChris Fallin 144a0318f36SChris Fallin /// VReg aliases. Each key in this table is translated to its 145a0318f36SChris Fallin /// value when gathering Operands from instructions. Aliases are 146a0318f36SChris Fallin /// not chased transitively (we do not further look up the 147a0318f36SChris Fallin /// translated reg to see if it is another alias). 148a0318f36SChris Fallin /// 149a0318f36SChris Fallin /// We use these aliases to rename an instruction's expected 150a0318f36SChris Fallin /// result vregs to the returned vregs from lowering, which are 151a0318f36SChris Fallin /// usually freshly-allocated temps. 152a0318f36SChris Fallin /// 153a0318f36SChris Fallin /// Operands and branch arguments will already have been 154a0318f36SChris Fallin /// translated through this alias table; but it helps to make 155a0318f36SChris Fallin /// sense of instructions when pretty-printed, for example. 156a0318f36SChris Fallin vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>, 157d8357426SChris Fallin 15872e6be93SChris Fallin /// Block-order information. 15972e6be93SChris Fallin block_order: BlockLoweringOrder, 160d8357426SChris Fallin 161d8357426SChris Fallin /// ABI object. 162e8f772c1SChris Fallin abi: Box<dyn ABICallee<I = I>>, 16308353fccSChris Fallin 164c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 165c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 166c5bbc874SBenjamin Bouvier emit_info: I::Info, 167c5bbc874SBenjamin Bouvier 168a0318f36SChris Fallin /// Reference-typed `regalloc2::VReg`s. The regalloc requires 169a0318f36SChris Fallin /// these in a dense slice (as opposed to querying the 170a0318f36SChris Fallin /// reftype-status of each vreg) for efficient iteration. 171a0318f36SChris Fallin reftyped_vregs: Vec<VReg>, 17208353fccSChris Fallin 173a0318f36SChris Fallin /// A set with the same contents as `reftyped_vregs`, in order to 174a0318f36SChris Fallin /// avoid inserting more than once. 175a0318f36SChris Fallin reftyped_vregs_set: FxHashSet<VReg>, 17683f182b3SAndrew Brown 17783f182b3SAndrew Brown /// Constants. 17883f182b3SAndrew Brown constants: VCodeConstants, 179997fab55SChris Fallin 180a0318f36SChris Fallin /// Value labels for debuginfo attached to vregs. 181a0318f36SChris Fallin debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, 182d8357426SChris Fallin } 183d8357426SChris Fallin 184a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed 185a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly, 186a0318f36SChris Fallin /// and optionally metadata about the code layout. 187a0318f36SChris Fallin pub struct EmitResult<I: VCodeInst> { 188a0318f36SChris Fallin /// The MachBuffer containing the machine code. 189a0318f36SChris Fallin pub buffer: MachBuffer<I>, 190a0318f36SChris Fallin 191a0318f36SChris Fallin /// Offset of each basic block, recorded during emission. Computed 192a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 193a0318f36SChris Fallin pub bb_offsets: Vec<CodeOffset>, 194a0318f36SChris Fallin 195a0318f36SChris Fallin /// Final basic-block edges, in terms of code offsets of 196a0318f36SChris Fallin /// bb-starts. Computed only if `debug_value_labels` is non-empty. 197a0318f36SChris Fallin pub bb_edges: Vec<(CodeOffset, CodeOffset)>, 198a0318f36SChris Fallin 199a0318f36SChris Fallin /// Final instruction offsets, recorded during emission. Computed 200a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 201a0318f36SChris Fallin pub inst_offsets: Vec<CodeOffset>, 202a0318f36SChris Fallin 203a0318f36SChris Fallin /// Final length of function body. 204a0318f36SChris Fallin pub func_body_len: CodeOffset, 205a0318f36SChris Fallin 206a0318f36SChris Fallin /// The pretty-printed disassembly, if any. This uses the same 207a0318f36SChris Fallin /// pretty-printing for MachInsts as the pre-regalloc VCode Debug 208a0318f36SChris Fallin /// implementation, but additionally includes the prologue and 209a0318f36SChris Fallin /// epilogue(s), and makes use of the regalloc results. 210a0318f36SChris Fallin pub disasm: Option<String>, 211a0318f36SChris Fallin 2129c43749dSSam Parker /// Offsets of sized stackslots. 2139c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 2149c43749dSSam Parker 2159c43749dSSam Parker /// Offsets of dynamic stackslots. 2169c43749dSSam Parker pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>, 217a0318f36SChris Fallin 218a0318f36SChris Fallin /// Value-labels information (debug metadata). 219a0318f36SChris Fallin pub value_labels_ranges: ValueLabelsRanges, 220a0318f36SChris Fallin 221a0318f36SChris Fallin /// Stack frame size. 222a0318f36SChris Fallin pub frame_size: u32, 223d9d64694SChris Fallin } 224d9d64694SChris Fallin 225a0318f36SChris Fallin /// A builder for a VCode function body. 226d8357426SChris Fallin /// 227a0318f36SChris Fallin /// This builder has the ability to accept instructions in either 228a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that 229a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst> 230a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions 231a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will 232a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine 233a0318f36SChris Fallin /// order. 234a0318f36SChris Fallin /// 235a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the 236a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the 237a0318f36SChris Fallin /// order of construction. Note that this means we do not know the 238a0318f36SChris Fallin /// final block or instruction indices when building, so we do not 239a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending 240a0318f36SChris Fallin /// terminator instructions with successor blocks.) 241d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 242d8357426SChris Fallin /// In-progress VCode. 243d8357426SChris Fallin vcode: VCode<I>, 244d8357426SChris Fallin 245a0318f36SChris Fallin /// In what direction is the build occuring? 246a0318f36SChris Fallin direction: VCodeBuildDirection, 24708353fccSChris Fallin 24872e6be93SChris Fallin /// Index of the last block-start in the vcode. 249a0318f36SChris Fallin block_start: usize, 250d8357426SChris Fallin 251d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 252d8357426SChris Fallin succ_start: usize, 253b691770fSChris Fallin 254a0318f36SChris Fallin /// Start of blockparams for the current block in the concatenated 255a0318f36SChris Fallin /// blockparams list. 256a0318f36SChris Fallin block_params_start: usize, 257a0318f36SChris Fallin 258a0318f36SChris Fallin /// Start of successor blockparam arg list entries in 259a0318f36SChris Fallin /// the concatenated branch_block_arg_range list. 260a0318f36SChris Fallin branch_block_arg_succ_start: usize, 261a0318f36SChris Fallin 262b691770fSChris Fallin /// Current source location. 263b691770fSChris Fallin cur_srcloc: SourceLoc, 264a0318f36SChris Fallin 265a0318f36SChris Fallin /// Debug-value label in-progress map, keyed by label. For each 266a0318f36SChris Fallin /// label, we keep disjoint ranges mapping to vregs. We'll flatten 267a0318f36SChris Fallin /// this into (vreg, range, label) tuples when done. 268a0318f36SChris Fallin debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>, 269a0318f36SChris Fallin } 270a0318f36SChris Fallin 271a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode. 272a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)] 273a0318f36SChris Fallin pub enum VCodeBuildDirection { 274a0318f36SChris Fallin // TODO: add `Forward` once we need it and can test it adequately. 275a0318f36SChris Fallin /// Backward-build pass: we expect the producer to call `emit()` 276a0318f36SChris Fallin /// with instructions in reverse program order within each block. 277a0318f36SChris Fallin Backward, 278d8357426SChris Fallin } 279d8357426SChris Fallin 280d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 281d8357426SChris Fallin /// Create a new VCodeBuilder. 282c5bbc874SBenjamin Bouvier pub fn new( 283c5bbc874SBenjamin Bouvier abi: Box<dyn ABICallee<I = I>>, 284c5bbc874SBenjamin Bouvier emit_info: I::Info, 285c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 28683f182b3SAndrew Brown constants: VCodeConstants, 287a0318f36SChris Fallin direction: VCodeBuildDirection, 288c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 289a0318f36SChris Fallin let vcode = VCode::new(abi, emit_info, block_order, constants); 29008353fccSChris Fallin 291d8357426SChris Fallin VCodeBuilder { 292d8357426SChris Fallin vcode, 293a0318f36SChris Fallin direction, 29472e6be93SChris Fallin block_start: 0, 295d8357426SChris Fallin succ_start: 0, 296a0318f36SChris Fallin block_params_start: 0, 297a0318f36SChris Fallin branch_block_arg_succ_start: 0, 298b691770fSChris Fallin cur_srcloc: SourceLoc::default(), 299a0318f36SChris Fallin debug_info: FxHashMap::default(), 300d8357426SChris Fallin } 301d8357426SChris Fallin } 302d8357426SChris Fallin 303d8357426SChris Fallin /// Access the ABI object. 304e8f772c1SChris Fallin pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> { 305d8357426SChris Fallin &mut *self.vcode.abi 306d8357426SChris Fallin } 307d8357426SChris Fallin 30872e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 30972e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 31072e6be93SChris Fallin &self.vcode.block_order 3111d90751bSBenjamin Bouvier } 3121d90751bSBenjamin Bouvier 313d8357426SChris Fallin /// Set the type of a VReg. 314d8357426SChris Fallin pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 315a0318f36SChris Fallin if self.vcode.vreg_types.len() <= vreg.index() { 316ef5de04dSBenjamin Bouvier self.vcode 317ef5de04dSBenjamin Bouvier .vreg_types 318a0318f36SChris Fallin .resize(vreg.index() + 1, ir::types::I8); 319d8357426SChris Fallin } 320a0318f36SChris Fallin self.vcode.vreg_types[vreg.index()] = ty; 32108353fccSChris Fallin if is_reftype(ty) { 322a0318f36SChris Fallin let vreg: VReg = vreg.into(); 323a0318f36SChris Fallin if self.vcode.reftyped_vregs_set.insert(vreg) { 324a0318f36SChris Fallin self.vcode.reftyped_vregs.push(vreg); 325a0318f36SChris Fallin } 32608353fccSChris Fallin self.vcode.have_ref_values = true; 32708353fccSChris Fallin } 32808353fccSChris Fallin } 32908353fccSChris Fallin 330a0318f36SChris Fallin /// Get the type of a VReg. 331a0318f36SChris Fallin pub fn get_vreg_type(&self, vreg: VirtualReg) -> Type { 332a0318f36SChris Fallin self.vcode.vreg_types[vreg.index()] 333a0318f36SChris Fallin } 334a0318f36SChris Fallin 335d8357426SChris Fallin /// Set the current block as the entry block. 336d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 337d8357426SChris Fallin self.vcode.entry = block; 338d8357426SChris Fallin } 339d8357426SChris Fallin 340d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 341d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 34272e6be93SChris Fallin pub fn end_bb(&mut self) { 34372e6be93SChris Fallin let start_idx = self.block_start; 344a0318f36SChris Fallin let end_idx = self.vcode.insts.len(); 34572e6be93SChris Fallin self.block_start = end_idx; 346d8357426SChris Fallin // Add the instruction index range to the list of blocks. 347a0318f36SChris Fallin self.vcode 348a0318f36SChris Fallin .block_ranges 349a0318f36SChris Fallin .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx))); 350d8357426SChris Fallin // End the successors list. 351a0318f36SChris Fallin let succ_end = self.vcode.block_succs_preds.len(); 352d8357426SChris Fallin self.vcode 353d8357426SChris Fallin .block_succ_range 354a0318f36SChris Fallin .push((self.succ_start as u32, succ_end as u32)); 355d8357426SChris Fallin self.succ_start = succ_end; 356a0318f36SChris Fallin // End the blockparams list. 357a0318f36SChris Fallin let block_params_end = self.vcode.block_params.len(); 358a0318f36SChris Fallin self.vcode 359a0318f36SChris Fallin .block_params_range 360a0318f36SChris Fallin .push((self.block_params_start as u32, block_params_end as u32)); 361a0318f36SChris Fallin self.block_params_start = block_params_end; 362a0318f36SChris Fallin // End the branch blockparam args list. 363a0318f36SChris Fallin let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); 364a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.push(( 365a0318f36SChris Fallin self.branch_block_arg_succ_start as u32, 366a0318f36SChris Fallin branch_block_arg_succ_end as u32, 367a0318f36SChris Fallin )); 368a0318f36SChris Fallin self.branch_block_arg_succ_start = branch_block_arg_succ_end; 369d8357426SChris Fallin } 370d8357426SChris Fallin 371a0318f36SChris Fallin pub fn add_block_param(&mut self, param: VirtualReg, ty: Type) { 372a0318f36SChris Fallin self.set_vreg_type(param, ty); 373a0318f36SChris Fallin self.vcode.block_params.push(param.into()); 374a0318f36SChris Fallin } 375a0318f36SChris Fallin 3765774e068SChris Fallin fn add_branch_args_for_succ(&mut self, args: &[Reg]) { 377a0318f36SChris Fallin let start = self.vcode.branch_block_args.len(); 378a0318f36SChris Fallin self.vcode 379a0318f36SChris Fallin .branch_block_args 380a0318f36SChris Fallin .extend(args.iter().map(|&arg| VReg::from(arg))); 381a0318f36SChris Fallin let end = self.vcode.branch_block_args.len(); 382a0318f36SChris Fallin self.vcode 383a0318f36SChris Fallin .branch_block_arg_range 384a0318f36SChris Fallin .push((start as u32, end as u32)); 385a0318f36SChris Fallin } 386a0318f36SChris Fallin 387a0318f36SChris Fallin /// Push an instruction for the current BB and current IR inst 388a0318f36SChris Fallin /// within the BB. 389a0318f36SChris Fallin pub fn push(&mut self, insn: I) { 39072e6be93SChris Fallin self.vcode.insts.push(insn); 39172e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 39272e6be93SChris Fallin } 39372e6be93SChris Fallin 3945774e068SChris Fallin /// Add a successor block with branch args. 3955774e068SChris Fallin pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { 3965774e068SChris Fallin self.vcode.block_succs_preds.push(block); 3975774e068SChris Fallin self.add_branch_args_for_succ(args); 3985774e068SChris Fallin } 3995774e068SChris Fallin 400b691770fSChris Fallin /// Set the current source location. 401b691770fSChris Fallin pub fn set_srcloc(&mut self, srcloc: SourceLoc) { 402b691770fSChris Fallin self.cur_srcloc = srcloc; 403d8357426SChris Fallin } 404d8357426SChris Fallin 405a0318f36SChris Fallin /// Add a debug value label to a register. 406a0318f36SChris Fallin pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { 407a0318f36SChris Fallin // We'll fix up labels in reverse(). Because we're generating 408a0318f36SChris Fallin // code bottom-to-top, the liverange of the label goes *from* 409a0318f36SChris Fallin // the last index at which was defined (or 0, which is the end 410a0318f36SChris Fallin // of the eventual function) *to* just this instruction, and 411a0318f36SChris Fallin // no further. 412a0318f36SChris Fallin let inst = InsnIndex::new(self.vcode.insts.len()); 413a0318f36SChris Fallin let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); 414a0318f36SChris Fallin let last = labels 415a0318f36SChris Fallin .last() 416a0318f36SChris Fallin .map(|(_start, end, _vreg)| *end) 417a0318f36SChris Fallin .unwrap_or(InsnIndex::new(0)); 418a0318f36SChris Fallin labels.push((last, inst, reg.into())); 419a0318f36SChris Fallin } 420a0318f36SChris Fallin 421a0318f36SChris Fallin pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { 422a0318f36SChris Fallin let from = from.into(); 423a0318f36SChris Fallin let resolved_to = self.resolve_vreg_alias(to.into()); 424a0318f36SChris Fallin // Disallow cycles (see below). 425a0318f36SChris Fallin assert_ne!(resolved_to, from); 426a0318f36SChris Fallin self.vcode.vreg_aliases.insert(from, resolved_to); 427a0318f36SChris Fallin } 428a0318f36SChris Fallin 429a0318f36SChris Fallin pub fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 430a0318f36SChris Fallin Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, from) 431a0318f36SChris Fallin } 432a0318f36SChris Fallin 433a0318f36SChris Fallin fn resolve_vreg_alias_impl( 434a0318f36SChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 435a0318f36SChris Fallin from: regalloc2::VReg, 436a0318f36SChris Fallin ) -> regalloc2::VReg { 437a0318f36SChris Fallin // We prevent cycles from existing by resolving targets of 438a0318f36SChris Fallin // aliases eagerly before setting them. If the target resolves 439a0318f36SChris Fallin // to the origin of the alias, then a cycle would be created 440a0318f36SChris Fallin // and the alias is disallowed. Because of the structure of 441a0318f36SChris Fallin // SSA code (one instruction can refer to another's defs but 442a0318f36SChris Fallin // not vice-versa, except indirectly through 443a0318f36SChris Fallin // phis/blockparams), cycles should not occur as we use 444a0318f36SChris Fallin // aliases to redirect vregs to the temps that actually define 445a0318f36SChris Fallin // them. 446a0318f36SChris Fallin 447a0318f36SChris Fallin let mut vreg = from; 448a0318f36SChris Fallin while let Some(to) = aliases.get(&vreg) { 449a0318f36SChris Fallin vreg = *to; 450a0318f36SChris Fallin } 451a0318f36SChris Fallin vreg 452a0318f36SChris Fallin } 453a0318f36SChris Fallin 45483f182b3SAndrew Brown /// Access the constants. 45583f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 45683f182b3SAndrew Brown &mut self.vcode.constants 45783f182b3SAndrew Brown } 45883f182b3SAndrew Brown 459a0318f36SChris Fallin fn compute_preds_from_succs(&mut self) { 460a0318f36SChris Fallin // Compute predecessors from successors. In order to gather 461a0318f36SChris Fallin // all preds for a block into a contiguous sequence, we build 462a0318f36SChris Fallin // a list of (succ, pred) tuples and then sort. 463a0318f36SChris Fallin let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> = 464a0318f36SChris Fallin Vec::with_capacity(self.vcode.block_succs_preds.len()); 465a0318f36SChris Fallin for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() { 466a0318f36SChris Fallin let pred = BlockIndex::new(pred); 467a0318f36SChris Fallin for i in start..end { 468a0318f36SChris Fallin let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index()); 469a0318f36SChris Fallin succ_pred_edges.push((succ, pred)); 470a0318f36SChris Fallin } 471a0318f36SChris Fallin } 472a0318f36SChris Fallin succ_pred_edges.sort_unstable(); 473a0318f36SChris Fallin 474a0318f36SChris Fallin let mut i = 0; 475a0318f36SChris Fallin for succ in 0..self.vcode.num_blocks() { 476a0318f36SChris Fallin let succ = BlockIndex::new(succ); 477a0318f36SChris Fallin let start = self.vcode.block_succs_preds.len(); 478a0318f36SChris Fallin while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ { 479a0318f36SChris Fallin let pred = succ_pred_edges[i].1; 480a0318f36SChris Fallin self.vcode.block_succs_preds.push(pred); 481a0318f36SChris Fallin i += 1; 482a0318f36SChris Fallin } 483a0318f36SChris Fallin let end = self.vcode.block_succs_preds.len(); 484a0318f36SChris Fallin self.vcode.block_pred_range.push((start as u32, end as u32)); 485d8357426SChris Fallin } 486d8357426SChris Fallin } 487d8357426SChris Fallin 488a0318f36SChris Fallin /// Called once, when a build in Backward order is complete, to 489a0318f36SChris Fallin /// perform the overall reversal (into final forward order) and 490a0318f36SChris Fallin /// finalize metadata accordingly. 491a0318f36SChris Fallin fn reverse_and_finalize(&mut self) { 492a0318f36SChris Fallin let n_insts = self.vcode.insts.len(); 493a0318f36SChris Fallin if n_insts == 0 { 494a0318f36SChris Fallin return; 495a0318f36SChris Fallin } 496a0318f36SChris Fallin 497a0318f36SChris Fallin // Reverse the per-block and per-inst sequences. 498a0318f36SChris Fallin self.vcode.block_ranges.reverse(); 499a0318f36SChris Fallin // block_params_range is indexed by block (and blocks were 500a0318f36SChris Fallin // traversed in reverse) so we reverse it; but block-param 501a0318f36SChris Fallin // sequences in the concatenated vec can remain in reverse 502a0318f36SChris Fallin // order (it is effectively an arena of arbitrarily-placed 503a0318f36SChris Fallin // referenced sequences). 504a0318f36SChris Fallin self.vcode.block_params_range.reverse(); 505a0318f36SChris Fallin // Likewise, we reverse block_succ_range, but the block_succ 506a0318f36SChris Fallin // concatenated array can remain as-is. 507a0318f36SChris Fallin self.vcode.block_succ_range.reverse(); 508a0318f36SChris Fallin self.vcode.insts.reverse(); 509a0318f36SChris Fallin self.vcode.srclocs.reverse(); 510a0318f36SChris Fallin // Likewise, branch_block_arg_succ_range is indexed by block 511a0318f36SChris Fallin // so must be reversed. 512a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.reverse(); 513a0318f36SChris Fallin 514a0318f36SChris Fallin // To translate an instruction index *endpoint* in reversed 515a0318f36SChris Fallin // order to forward order, compute `n_insts - i`. 516a0318f36SChris Fallin // 517a0318f36SChris Fallin // Why not `n_insts - 1 - i`? That would be correct to 518a0318f36SChris Fallin // translate an individual instruction index (for ten insts 0 519a0318f36SChris Fallin // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes 520a0318f36SChris Fallin // 0). But for the usual inclusive-start, exclusive-end range 521a0318f36SChris Fallin // idiom, inclusive starts become exclusive ends and 522a0318f36SChris Fallin // vice-versa, so e.g. an (inclusive) start of 0 becomes an 523a0318f36SChris Fallin // (exclusive) end of 10. 524a0318f36SChris Fallin let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); 525a0318f36SChris Fallin 526a0318f36SChris Fallin // Edit the block-range instruction indices. 527a0318f36SChris Fallin for tuple in &mut self.vcode.block_ranges { 528a0318f36SChris Fallin let (start, end) = *tuple; 529a0318f36SChris Fallin *tuple = (translate(end), translate(start)); // Note reversed order. 530a0318f36SChris Fallin } 531a0318f36SChris Fallin 532a0318f36SChris Fallin // Generate debug-value labels based on per-label maps. 533a0318f36SChris Fallin for (label, tuples) in &self.debug_info { 534a0318f36SChris Fallin for &(start, end, vreg) in tuples { 535a0318f36SChris Fallin let vreg = self.resolve_vreg_alias(vreg); 536a0318f36SChris Fallin let fwd_start = translate(end); 537a0318f36SChris Fallin let fwd_end = translate(start); 538a0318f36SChris Fallin self.vcode 539a0318f36SChris Fallin .debug_value_labels 540a0318f36SChris Fallin .push((vreg, fwd_start, fwd_end, label.as_u32())); 541a0318f36SChris Fallin } 542a0318f36SChris Fallin } 543a0318f36SChris Fallin 544a0318f36SChris Fallin // Now sort debug value labels by VReg, as required 545a0318f36SChris Fallin // by regalloc2. 546a0318f36SChris Fallin self.vcode 547a0318f36SChris Fallin .debug_value_labels 548a0318f36SChris Fallin .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); 549a0318f36SChris Fallin } 550a0318f36SChris Fallin 551a0318f36SChris Fallin fn collect_operands(&mut self) { 552a0318f36SChris Fallin for (i, insn) in self.vcode.insts.iter().enumerate() { 553a0318f36SChris Fallin // Push operands from the instruction onto the operand list. 554a0318f36SChris Fallin // 555a0318f36SChris Fallin // We rename through the vreg alias table as we collect 556a0318f36SChris Fallin // the operands. This is better than a separate post-pass 557a0318f36SChris Fallin // over operands, because it has more cache locality: 558a0318f36SChris Fallin // operands only need to pass through L1 once. This is 559a0318f36SChris Fallin // also better than renaming instructions' 560a0318f36SChris Fallin // operands/registers while lowering, because here we only 561a0318f36SChris Fallin // need to do the `match` over the instruction to visit 562a0318f36SChris Fallin // its register fields (which is slow, branchy code) once. 563a0318f36SChris Fallin 564a0318f36SChris Fallin let vreg_aliases = &self.vcode.vreg_aliases; 565a0318f36SChris Fallin let mut op_collector = OperandCollector::new(&mut self.vcode.operands, |vreg| { 566a0318f36SChris Fallin Self::resolve_vreg_alias_impl(vreg_aliases, vreg) 567a0318f36SChris Fallin }); 568a0318f36SChris Fallin insn.get_operands(&mut op_collector); 569a0318f36SChris Fallin let (ops, clobbers) = op_collector.finish(); 570a0318f36SChris Fallin self.vcode.operand_ranges.push(ops); 571a0318f36SChris Fallin 572b2e28b91SChris Fallin if clobbers != PRegSet::default() { 573b2e28b91SChris Fallin self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); 574a0318f36SChris Fallin } 575a0318f36SChris Fallin 576a0318f36SChris Fallin if let Some((dst, src)) = insn.is_move() { 577a0318f36SChris Fallin let src = Operand::reg_use(Self::resolve_vreg_alias_impl(vreg_aliases, src.into())); 578a0318f36SChris Fallin let dst = Operand::reg_def(Self::resolve_vreg_alias_impl( 579a0318f36SChris Fallin vreg_aliases, 580a0318f36SChris Fallin dst.to_reg().into(), 581a0318f36SChris Fallin )); 582a0318f36SChris Fallin // Note that regalloc2 requires these in (src, dst) order. 583a0318f36SChris Fallin self.vcode.is_move.insert(InsnIndex::new(i), (src, dst)); 584a0318f36SChris Fallin } 585a0318f36SChris Fallin } 586a0318f36SChris Fallin 587a0318f36SChris Fallin // Translate blockparam args via the vreg aliases table as well. 588a0318f36SChris Fallin for arg in &mut self.vcode.branch_block_args { 589a0318f36SChris Fallin let new_arg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg); 590a0318f36SChris Fallin log::trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); 591a0318f36SChris Fallin *arg = new_arg; 592a0318f36SChris Fallin } 593a0318f36SChris Fallin } 594a0318f36SChris Fallin 595a0318f36SChris Fallin /// Build the final VCode. 596a0318f36SChris Fallin pub fn build(mut self) -> VCode<I> { 597a0318f36SChris Fallin if self.direction == VCodeBuildDirection::Backward { 598a0318f36SChris Fallin self.reverse_and_finalize(); 599a0318f36SChris Fallin } 600a0318f36SChris Fallin self.collect_operands(); 6012154c63dSAlex Crichton 6022154c63dSAlex Crichton // Apply register aliases to the `reftyped_vregs` list since this list 6032154c63dSAlex Crichton // will be returned directly to `regalloc2` eventually and all 6042154c63dSAlex Crichton // operands/results of instructions will use the alias-resolved vregs 6052154c63dSAlex Crichton // from `regalloc2`'s perspective. 606*2127c3a3SAlex Crichton // 607*2127c3a3SAlex Crichton // Also note that `reftyped_vregs` can't have duplicates, so after the 608*2127c3a3SAlex Crichton // aliases are applied duplicates are removed. 6092154c63dSAlex Crichton for reg in self.vcode.reftyped_vregs.iter_mut() { 6102154c63dSAlex Crichton *reg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg); 6112154c63dSAlex Crichton } 612*2127c3a3SAlex Crichton self.vcode.reftyped_vregs.sort(); 613*2127c3a3SAlex Crichton self.vcode.reftyped_vregs.dedup(); 6142154c63dSAlex Crichton 615a0318f36SChris Fallin self.compute_preds_from_succs(); 616a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 617a0318f36SChris Fallin self.vcode 618d8357426SChris Fallin } 619d8357426SChris Fallin } 620d8357426SChris Fallin 62108353fccSChris Fallin /// Is this type a reference type? 62208353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 62326529006SChris Fallin ty == types::R64 || ty == types::R32 62408353fccSChris Fallin } 62508353fccSChris Fallin 626d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 627d8357426SChris Fallin /// New empty VCode. 628c5bbc874SBenjamin Bouvier fn new( 629c5bbc874SBenjamin Bouvier abi: Box<dyn ABICallee<I = I>>, 630c5bbc874SBenjamin Bouvier emit_info: I::Info, 631c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 63283f182b3SAndrew Brown constants: VCodeConstants, 633c5bbc874SBenjamin Bouvier ) -> VCode<I> { 634a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 635d8357426SChris Fallin VCode { 636d8357426SChris Fallin vreg_types: vec![], 63708353fccSChris Fallin have_ref_values: false, 638a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 639a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 640a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 641b2e28b91SChris Fallin clobbers: FxHashMap::default(), 642a0318f36SChris Fallin is_move: FxHashMap::default(), 643a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 644a0318f36SChris Fallin entry: BlockIndex::new(0), 645a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 646a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 647a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 648a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 649a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 650a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 651a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 652a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 653a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 65472e6be93SChris Fallin block_order, 655d8357426SChris Fallin abi, 656c5bbc874SBenjamin Bouvier emit_info, 657a0318f36SChris Fallin reftyped_vregs: vec![], 658a0318f36SChris Fallin reftyped_vregs_set: FxHashSet::default(), 65983f182b3SAndrew Brown constants, 660a0318f36SChris Fallin debug_value_labels: vec![], 661a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 662d8357426SChris Fallin } 663d8357426SChris Fallin } 664d8357426SChris Fallin 665d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 666d8357426SChris Fallin /// (self.num_blocks() - 1)`. 667d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 668d8357426SChris Fallin self.block_ranges.len() 669d8357426SChris Fallin } 670d8357426SChris Fallin 671d8357426SChris Fallin /// Get the successors for a block. 672a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 673a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 674a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 675d8357426SChris Fallin } 676d8357426SChris Fallin 677a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 678a0318f36SChris Fallin // Compute clobbered registers. 679a0318f36SChris Fallin let mut clobbered = vec![]; 680a0318f36SChris Fallin let mut clobbered_set = FxHashSet::default(); 681d8357426SChris Fallin 682a0318f36SChris Fallin // All moves are included in clobbers. 683a0318f36SChris Fallin for edit in ®alloc.edits { 684a0318f36SChris Fallin let Edit::Move { to, .. } = edit.1; 685a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 686a0318f36SChris Fallin let reg = RealReg::from(preg); 687a0318f36SChris Fallin if clobbered_set.insert(reg) { 688a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 689a0318f36SChris Fallin } 690a0318f36SChris Fallin } 691d8357426SChris Fallin } 692d8357426SChris Fallin 693a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 694a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 695a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 696a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 697a0318f36SChris Fallin // the current function from clobbers, because by 698a0318f36SChris Fallin // definition everything clobbered by the call can be 699a0318f36SChris Fallin // clobbered by this function without saving as well.) 700a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 701d8357426SChris Fallin continue; 702d8357426SChris Fallin } 703d8357426SChris Fallin 704a0318f36SChris Fallin let start = *start as usize; 705a0318f36SChris Fallin let end = *end as usize; 706a0318f36SChris Fallin let operands = &self.operands[start..end]; 707a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 708a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 709a0318f36SChris Fallin // We're interested only in writes (Mods or Defs). 710a0318f36SChris Fallin if operand.kind() == OperandKind::Use { 711a0318f36SChris Fallin continue; 712d8357426SChris Fallin } 713a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 714a0318f36SChris Fallin let reg = RealReg::from(preg); 715a0318f36SChris Fallin if clobbered_set.insert(reg) { 716a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 717a0318f36SChris Fallin } 71808353fccSChris Fallin } 719d8357426SChris Fallin } 720d8357426SChris Fallin 721a0318f36SChris Fallin // Also add explicitly-clobbered registers. 722b2e28b91SChris Fallin for preg in self 723b2e28b91SChris Fallin .clobbers 724b2e28b91SChris Fallin .get(&InsnIndex::new(i)) 725b2e28b91SChris Fallin .cloned() 726b2e28b91SChris Fallin .unwrap_or_default() 727b2e28b91SChris Fallin { 728a0318f36SChris Fallin let reg = RealReg::from(preg); 729a0318f36SChris Fallin if clobbered_set.insert(reg) { 730a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 731a0318f36SChris Fallin } 732a0318f36SChris Fallin } 733a0318f36SChris Fallin } 734d8357426SChris Fallin 735a0318f36SChris Fallin clobbered 736d8357426SChris Fallin } 737d8357426SChris Fallin 738a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 739a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 740a0318f36SChris Fallin /// the regalloc results as well. 741a0318f36SChris Fallin /// 742a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 743a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 744a0318f36SChris Fallin /// is consumed by the emission process. 74511a2ef01SChris Fallin pub fn emit( 746a0318f36SChris Fallin mut self, 747a0318f36SChris Fallin regalloc: ®alloc2::Output, 748a0318f36SChris Fallin want_disasm: bool, 749a0318f36SChris Fallin want_metadata: bool, 750a0318f36SChris Fallin ) -> EmitResult<I> 751d8357426SChris Fallin where 75272e6be93SChris Fallin I: MachInstEmit, 753d8357426SChris Fallin { 754a0318f36SChris Fallin // To write into disasm string. 755a0318f36SChris Fallin use core::fmt::Write; 756a0318f36SChris Fallin 7572b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 75872e6be93SChris Fallin let mut buffer = MachBuffer::new(); 75911a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 760d8357426SChris Fallin 76183f182b3SAndrew Brown // The first M MachLabels are reserved for block indices, the next N MachLabels for 76283f182b3SAndrew Brown // constants. 763a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 76483f182b3SAndrew Brown buffer.reserve_labels_for_constants(&self.constants); 765d8357426SChris Fallin 766ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 767ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 768ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 769ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 770a0318f36SChris Fallin let block = BlockIndex::new(block); 771ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 772ef1b2d2fSChris Fallin cold_blocks.push(block); 773ef1b2d2fSChris Fallin } else { 774ef1b2d2fSChris Fallin final_order.push(block); 775ef1b2d2fSChris Fallin } 776ef1b2d2fSChris Fallin } 777d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 778ef1b2d2fSChris Fallin 779a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 780a0318f36SChris Fallin // number of spillslots. 781a0318f36SChris Fallin // 782a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 783a0318f36SChris Fallin // generate the prologue and set other info, but we can't 784a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 785a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 786a0318f36SChris Fallin // relatively cheap. 787a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 788a0318f36SChris Fallin self.abi.set_num_spillslots(regalloc.num_spillslots); 789a0318f36SChris Fallin self.abi.set_clobbered(clobbers); 790a0318f36SChris Fallin 791a0318f36SChris Fallin // We need to generate the prologue in order to get the ABI 792a0318f36SChris Fallin // object into the right state first. We'll emit it when we 793a0318f36SChris Fallin // hit the right block below. 794a0318f36SChris Fallin let prologue_insts = self.abi.gen_prologue(); 795a0318f36SChris Fallin 796ef1b2d2fSChris Fallin // Emit blocks. 797964c6087SChris Fallin let mut cur_srcloc = None; 79811a2ef01SChris Fallin let mut last_offset = None; 799a0318f36SChris Fallin let mut inst_offsets = vec![]; 800a0318f36SChris Fallin let mut state = I::State::new(&*self.abi); 801a0318f36SChris Fallin 802a0318f36SChris Fallin let mut disasm = String::new(); 803a0318f36SChris Fallin 804a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 805a0318f36SChris Fallin inst_offsets.resize(self.insts.len(), 0); 806a0318f36SChris Fallin } 807a0318f36SChris Fallin 808ef1b2d2fSChris Fallin for block in final_order { 809a0318f36SChris Fallin log::trace!("emitting block {:?}", block); 81072e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 81172e6be93SChris Fallin while new_offset > buffer.cur_offset() { 812d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 81372e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 814a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 815d8357426SChris Fallin } 81672e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 817d8357426SChris Fallin 818a0318f36SChris Fallin let do_emit = |inst: &I, 819a0318f36SChris Fallin allocs: &[Allocation], 820a0318f36SChris Fallin disasm: &mut String, 821a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 822a0318f36SChris Fallin state: &mut I::State| { 823a0318f36SChris Fallin if want_disasm { 824a0318f36SChris Fallin let mut s = state.clone(); 825a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 826a0318f36SChris Fallin } 827a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 828a0318f36SChris Fallin }; 829a0318f36SChris Fallin 830a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 831a0318f36SChris Fallin if block == self.entry { 832a0318f36SChris Fallin log::trace!(" -> entry block"); 833a0318f36SChris Fallin buffer.start_srcloc(SourceLoc::default()); 834a0318f36SChris Fallin state.pre_sourceloc(SourceLoc::default()); 835a0318f36SChris Fallin for inst in &prologue_insts { 836a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 837a0318f36SChris Fallin } 838a0318f36SChris Fallin buffer.end_srcloc(); 839d9d64694SChris Fallin } 840d9d64694SChris Fallin 841a0318f36SChris Fallin // Now emit the regular block body. 84211a2ef01SChris Fallin 843a0318f36SChris Fallin buffer.bind_label(MachLabel::from_block(block)); 844a0318f36SChris Fallin 845a0318f36SChris Fallin if want_disasm { 846a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 847a0318f36SChris Fallin } 848a0318f36SChris Fallin 849a0318f36SChris Fallin if want_metadata { 85011a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 85111a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 85211a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 85311a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 85411a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 85511a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 85611a2ef01SChris Fallin break; 85711a2ef01SChris Fallin } 85811a2ef01SChris Fallin bb_starts[i] = None; 85911a2ef01SChris Fallin } 86011a2ef01SChris Fallin } 86111a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 86211a2ef01SChris Fallin last_offset = Some(cur_offset); 863800cf25bSChris Fallin } 86411a2ef01SChris Fallin 865a0318f36SChris Fallin for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { 866a0318f36SChris Fallin match inst_or_edit { 867a0318f36SChris Fallin InstOrEdit::Inst(iix) => { 868a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 869a0318f36SChris Fallin // If we need to produce debug info, 870a0318f36SChris Fallin // record the offset of each instruction 871a0318f36SChris Fallin // so that we can translate value-label 872a0318f36SChris Fallin // ranges to machine-code offsets. 873a0318f36SChris Fallin 874a0318f36SChris Fallin // Cold blocks violate monotonicity 875a0318f36SChris Fallin // assumptions elsewhere (that 876a0318f36SChris Fallin // instructions in inst-index order are in 877a0318f36SChris Fallin // order in machine code), so we omit 878a0318f36SChris Fallin // their offsets here. Value-label range 879a0318f36SChris Fallin // generation below will skip empty ranges 880a0318f36SChris Fallin // and ranges with to-offsets of zero. 881a0318f36SChris Fallin if !self.block_order.is_cold(block) { 882a0318f36SChris Fallin inst_offsets[iix.index()] = buffer.cur_offset(); 883a0318f36SChris Fallin } 884a0318f36SChris Fallin } 885a0318f36SChris Fallin 886a0318f36SChris Fallin if self.insts[iix.index()].is_move().is_some() { 887a0318f36SChris Fallin // Skip moves in the pre-regalloc program; 888a0318f36SChris Fallin // all of these are incorporated by the 889a0318f36SChris Fallin // regalloc into its unified move handling 890a0318f36SChris Fallin // and they come out the other end, if 891a0318f36SChris Fallin // still needed (not elided), as 892a0318f36SChris Fallin // regalloc-inserted moves. 893a0318f36SChris Fallin continue; 894a0318f36SChris Fallin } 895a0318f36SChris Fallin 896a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 897a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 898964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 899964c6087SChris Fallin if cur_srcloc.is_some() { 90072e6be93SChris Fallin buffer.end_srcloc(); 901b691770fSChris Fallin } 90272e6be93SChris Fallin buffer.start_srcloc(srcloc); 903964c6087SChris Fallin cur_srcloc = Some(srcloc); 904b691770fSChris Fallin } 9054dce5109SChris Fallin state.pre_sourceloc(cur_srcloc.unwrap_or(SourceLoc::default())); 906b691770fSChris Fallin 907a0318f36SChris Fallin // If this is a safepoint, compute a stack map 908a0318f36SChris Fallin // and pass it to the emit state. 909a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 910a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 911a0318f36SChris Fallin // Find the contiguous range of 912a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 913a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 914a0318f36SChris Fallin // for this instruction index. 915a0318f36SChris Fallin let safepoint_slots_start = regalloc 916a0318f36SChris Fallin .safepoint_slots 917a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 918a0318f36SChris Fallin if progpoint.inst() >= iix { 919a0318f36SChris Fallin std::cmp::Ordering::Greater 920a0318f36SChris Fallin } else { 921a0318f36SChris Fallin std::cmp::Ordering::Less 922a0318f36SChris Fallin } 923a0318f36SChris Fallin }) 924a0318f36SChris Fallin .unwrap_err(); 925a0318f36SChris Fallin 926a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 927a0318f36SChris Fallin .iter() 928a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 929a0318f36SChris Fallin { 930a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 931a0318f36SChris Fallin safepoint_slots.push(slot); 932a0318f36SChris Fallin } 933a0318f36SChris Fallin if !safepoint_slots.is_empty() { 934666c2554SChris Fallin let stack_map = self 935666c2554SChris Fallin .abi 936a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 93705bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 93808353fccSChris Fallin } 939a0318f36SChris Fallin } 94008353fccSChris Fallin 941a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 942a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 943de4af90aSYury Delendik 944a0318f36SChris Fallin // If the instruction we are about to emit is 945a0318f36SChris Fallin // a return, place an epilogue at this point 946a0318f36SChris Fallin // (and don't emit the return; the actual 947a0318f36SChris Fallin // epilogue will contain it). 948a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 949a0318f36SChris Fallin for inst in self.abi.gen_epilogue() { 950a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 951a0318f36SChris Fallin } 952c84d6be6SChris Fallin } else { 953a0318f36SChris Fallin // Emit the instruction! 954a0318f36SChris Fallin do_emit( 955a0318f36SChris Fallin &self.insts[iix.index()], 956a0318f36SChris Fallin allocs, 957a0318f36SChris Fallin &mut disasm, 958a0318f36SChris Fallin &mut buffer, 959a0318f36SChris Fallin &mut state, 960a0318f36SChris Fallin ); 961c84d6be6SChris Fallin } 962c84d6be6SChris Fallin } 963a0318f36SChris Fallin 964a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 965a0318f36SChris Fallin // Create a move/spill/reload instruction and 966a0318f36SChris Fallin // immediately emit it. 967a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 968a0318f36SChris Fallin (Some(from), Some(to)) => { 969a0318f36SChris Fallin // Reg-to-reg move. 970a0318f36SChris Fallin let from_rreg = Reg::from(from); 971a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 972a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 973a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 974a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 975a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 976a0318f36SChris Fallin } 977a0318f36SChris Fallin (Some(from), None) => { 978a0318f36SChris Fallin // Spill from register to spillslot. 979a0318f36SChris Fallin let to = to.as_stack().unwrap(); 980a0318f36SChris Fallin let from_rreg = RealReg::from(from); 981a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 982a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 983a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 984a0318f36SChris Fallin } 985a0318f36SChris Fallin (None, Some(to)) => { 986a0318f36SChris Fallin // Load from spillslot to register. 987a0318f36SChris Fallin let from = from.as_stack().unwrap(); 988a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 989a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 990a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 991a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 992a0318f36SChris Fallin } 993a0318f36SChris Fallin (None, None) => { 994a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 995a0318f36SChris Fallin } 996a0318f36SChris Fallin } 997a0318f36SChris Fallin } 998c84d6be6SChris Fallin } 999d8357426SChris Fallin } 1000b691770fSChris Fallin 1001964c6087SChris Fallin if cur_srcloc.is_some() { 100272e6be93SChris Fallin buffer.end_srcloc(); 1003964c6087SChris Fallin cur_srcloc = None; 1004b691770fSChris Fallin } 100572e6be93SChris Fallin 1006a0318f36SChris Fallin // Do we need an island? Get the worst-case size of the 1007a0318f36SChris Fallin // next BB and see if, having emitted that many bytes, we 1008a0318f36SChris Fallin // will be beyond the deadline. 1009a0318f36SChris Fallin if block.index() < (self.num_blocks() - 1) { 1010a0318f36SChris Fallin let next_block = block.index() + 1; 1011a0318f36SChris Fallin let next_block_range = self.block_ranges[next_block]; 1012a0318f36SChris Fallin let next_block_size = next_block_range.1.index() - next_block_range.0.index(); 1013a0318f36SChris Fallin let worst_case_next_bb = I::worst_case_size() * next_block_size as u32; 101472e6be93SChris Fallin if buffer.island_needed(worst_case_next_bb) { 10151532516aSAlex Crichton buffer.emit_island(worst_case_next_bb); 101672e6be93SChris Fallin } 101772e6be93SChris Fallin } 1018d8357426SChris Fallin } 1019d8357426SChris Fallin 102083f182b3SAndrew Brown // Emit the constants used by the function. 102183f182b3SAndrew Brown for (constant, data) in self.constants.iter() { 102283f182b3SAndrew Brown let label = buffer.get_label_for_constant(constant); 102383f182b3SAndrew Brown buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value()); 102483f182b3SAndrew Brown } 102583f182b3SAndrew Brown 1026a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1027de4af90aSYury Delendik 102811a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 102911a2ef01SChris Fallin let mut bb_edges = vec![]; 1030a0318f36SChris Fallin let mut bb_offsets = vec![]; 1031a0318f36SChris Fallin if want_metadata { 103211a2ef01SChris Fallin for block in 0..self.num_blocks() { 103311a2ef01SChris Fallin if bb_starts[block].is_none() { 103411a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 103511a2ef01SChris Fallin continue; 103611a2ef01SChris Fallin } 103711a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 103811a2ef01SChris Fallin 1039a0318f36SChris Fallin bb_offsets.push(from); 104011a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1041a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1042a0318f36SChris Fallin for &succ in succs.iter() { 1043a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 104411a2ef01SChris Fallin bb_edges.push((from, to)); 104511a2ef01SChris Fallin } 104611a2ef01SChris Fallin } 1047800cf25bSChris Fallin } 104811a2ef01SChris Fallin 1049a0318f36SChris Fallin let value_labels_ranges = 1050a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1051a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1052a0318f36SChris Fallin 1053a0318f36SChris Fallin EmitResult { 1054a0318f36SChris Fallin buffer, 1055a0318f36SChris Fallin bb_offsets, 1056a0318f36SChris Fallin bb_edges, 1057a0318f36SChris Fallin inst_offsets, 1058a0318f36SChris Fallin func_body_len, 1059a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10609c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10619c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1062a0318f36SChris Fallin value_labels_ranges, 1063a0318f36SChris Fallin frame_size, 1064a0318f36SChris Fallin } 1065d8357426SChris Fallin } 1066d8357426SChris Fallin 1067a0318f36SChris Fallin fn compute_value_labels_ranges( 1068a0318f36SChris Fallin &self, 1069a0318f36SChris Fallin regalloc: ®alloc2::Output, 1070a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1071a0318f36SChris Fallin func_body_len: u32, 1072a0318f36SChris Fallin ) -> ValueLabelsRanges { 1073a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1074602006ffSbjorn3 return ValueLabelsRanges::default(); 1075997fab55SChris Fallin } 1076997fab55SChris Fallin 1077a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1078a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1079a0318f36SChris Fallin let ranges = value_labels_ranges 1080a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1081a0318f36SChris Fallin .or_insert_with(|| vec![]); 1082a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1083a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1084a0318f36SChris Fallin func_body_len 1085a0318f36SChris Fallin } else { 1086a0318f36SChris Fallin inst_offsets[to.inst().index()] 1087a0318f36SChris Fallin }; 1088a0318f36SChris Fallin 1089a0318f36SChris Fallin // Empty range or to-offset of zero can happen because of 1090a0318f36SChris Fallin // cold blocks (see above). 1091a0318f36SChris Fallin if to_offset == 0 || from_offset == to_offset { 1092a0318f36SChris Fallin continue; 109376d61504Sbjorn3 } 109476d61504Sbjorn3 1095a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1096a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1097a0318f36SChris Fallin } else { 1098a0318f36SChris Fallin // We can't translate spillslot locations at the 1099a0318f36SChris Fallin // moment because ValueLabelLoc requires an 1100a0318f36SChris Fallin // instantaneous SP offset, and this can *change* 1101a0318f36SChris Fallin // within the range we have here because of callsites 1102a0318f36SChris Fallin // adjusting SP temporarily. To avoid the complexity 1103a0318f36SChris Fallin // of accurately plumbing through nominal-SP 1104a0318f36SChris Fallin // adjustment sites, we just omit debug info for 1105a0318f36SChris Fallin // values that are spilled. Not ideal, but debug info 1106a0318f36SChris Fallin // is best-effort. 1107a0318f36SChris Fallin continue; 1108a0318f36SChris Fallin }; 1109a0318f36SChris Fallin 1110a0318f36SChris Fallin ranges.push(ValueLocRange { 1111a0318f36SChris Fallin loc, 1112a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1113a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1114a0318f36SChris Fallin // instruction; that is the same as the end of another 1115a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1116a0318f36SChris Fallin // we are past the previous instruction's end. 1117a0318f36SChris Fallin start: from_offset + 1, 1118a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1119a0318f36SChris Fallin // *include* the end of the last 1120a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1121a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1122a0318f36SChris Fallin // the first instruction not covered. That 1123a0318f36SChris Fallin // instruction's start is the same as the end of the 1124a0318f36SChris Fallin // last instruction that is included, so we go one 1125a0318f36SChris Fallin // byte further to be sure to include it. 1126a0318f36SChris Fallin end: to_offset + 1, 1127a0318f36SChris Fallin }); 1128a0318f36SChris Fallin } 1129a0318f36SChris Fallin 1130a0318f36SChris Fallin value_labels_ranges 1131c84d6be6SChris Fallin } 1132c84d6be6SChris Fallin 1133d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1134d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1135a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1136d8357426SChris Fallin } 11372154c63dSAlex Crichton 11382154c63dSAlex Crichton #[inline] 11392154c63dSAlex Crichton fn assert_no_vreg_aliases<'a>(&self, list: &'a [VReg]) -> &'a [VReg] { 11402154c63dSAlex Crichton for vreg in list { 11412154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 11422154c63dSAlex Crichton } 11432154c63dSAlex Crichton list 11442154c63dSAlex Crichton } 11452154c63dSAlex Crichton 11462154c63dSAlex Crichton #[inline] 11472154c63dSAlex Crichton fn assert_not_vreg_alias(&self, vreg: VReg) -> VReg { 11482154c63dSAlex Crichton debug_assert!(VCodeBuilder::<I>::resolve_vreg_alias_impl(&self.vreg_aliases, vreg) == vreg); 11492154c63dSAlex Crichton vreg 11502154c63dSAlex Crichton } 11512154c63dSAlex Crichton 11522154c63dSAlex Crichton #[inline] 11532154c63dSAlex Crichton fn assert_operand_not_vreg_alias(&self, op: Operand) -> Operand { 11542154c63dSAlex Crichton // It should be true by construction that `Operand`s do not contain any 11552154c63dSAlex Crichton // aliased vregs since they're all collected and mapped when the VCode 11562154c63dSAlex Crichton // is itself constructed. 11572154c63dSAlex Crichton self.assert_not_vreg_alias(op.vreg()); 11582154c63dSAlex Crichton op 11592154c63dSAlex Crichton } 1160d8357426SChris Fallin } 1161d8357426SChris Fallin 1162d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1163a0318f36SChris Fallin fn num_insts(&self) -> usize { 1164a0318f36SChris Fallin self.insts.len() 1165d8357426SChris Fallin } 1166d8357426SChris Fallin 1167a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1168a0318f36SChris Fallin self.block_ranges.len() 1169d8357426SChris Fallin } 1170d8357426SChris Fallin 1171a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1172a0318f36SChris Fallin self.entry 1173d8357426SChris Fallin } 1174d8357426SChris Fallin 1175a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1176a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1177a0318f36SChris Fallin InstRange::forward(start, end) 1178d8357426SChris Fallin } 1179d8357426SChris Fallin 1180a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1181a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1182a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1183d8357426SChris Fallin } 1184d8357426SChris Fallin 1185a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1186a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1187a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1188d8357426SChris Fallin } 1189d8357426SChris Fallin 1190a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1191a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 11922154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 11932154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 11942154c63dSAlex Crichton // double-check just to be sure. 11952154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1196d8357426SChris Fallin } 1197d8357426SChris Fallin 1198a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1199a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1200a0318f36SChris Fallin let succ_ranges = 1201a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1202a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 12032154c63dSAlex Crichton let ret = &self.branch_block_args 12042154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 12052154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1206d8357426SChris Fallin } 1207d8357426SChris Fallin 1208a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1209a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1210d8357426SChris Fallin MachTerminator::Ret => true, 1211d8357426SChris Fallin _ => false, 1212d8357426SChris Fallin } 1213d8357426SChris Fallin } 1214d8357426SChris Fallin 1215a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1216a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 12175774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1218a0318f36SChris Fallin _ => false, 1219a0318f36SChris Fallin } 122071768bb6SChris Fallin } 122171768bb6SChris Fallin 1222a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1223a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1224d8357426SChris Fallin } 1225d8357426SChris Fallin 1226a0318f36SChris Fallin fn is_move(&self, insn: InsnIndex) -> Option<(Operand, Operand)> { 12272154c63dSAlex Crichton let (a, b) = self.is_move.get(&insn)?; 12282154c63dSAlex Crichton Some(( 12292154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*a), 12302154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*b), 12312154c63dSAlex Crichton )) 1232d8357426SChris Fallin } 1233d8357426SChris Fallin 1234a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1235a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 12362154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 12372154c63dSAlex Crichton for op in ret { 12382154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*op); 12392154c63dSAlex Crichton } 12402154c63dSAlex Crichton ret 1241d8357426SChris Fallin } 1242d8357426SChris Fallin 1243b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1244b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1245be6f060aSChris Fallin } 1246be6f060aSChris Fallin 1247a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1248a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1249d8357426SChris Fallin } 1250d8357426SChris Fallin 1251a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 12522154c63dSAlex Crichton self.assert_no_vreg_aliases(&self.reftyped_vregs[..]) 1253d8357426SChris Fallin } 1254d8357426SChris Fallin 1255a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 12562154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 12572154c63dSAlex Crichton // generated and aliases are fully defined, so no double-check that 12582154c63dSAlex Crichton // aliases are not lingering. 12592154c63dSAlex Crichton for (vreg, ..) in self.debug_value_labels.iter() { 12602154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 12612154c63dSAlex Crichton } 1262a0318f36SChris Fallin &self.debug_value_labels[..] 1263d8357426SChris Fallin } 1264d8357426SChris Fallin 1265a0318f36SChris Fallin fn is_pinned_vreg(&self, vreg: VReg) -> Option<PReg> { 1266a0318f36SChris Fallin pinned_vreg_to_preg(vreg) 1267d8357426SChris Fallin } 1268d8357426SChris Fallin 1269a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1270a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1271d8357426SChris Fallin } 1272d8357426SChris Fallin 1273a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1274a0318f36SChris Fallin // At least the s390x backend requires this, because the 1275a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1276a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1277a0318f36SChris Fallin true 1278d8357426SChris Fallin } 1279d8357426SChris Fallin } 1280d8357426SChris Fallin 1281d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1282d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1283a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1284a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1285a0318f36SChris Fallin 1286a0318f36SChris Fallin let mut state = Default::default(); 1287a0318f36SChris Fallin 1288a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1289a0318f36SChris Fallin alias_keys.sort_unstable(); 1290a0318f36SChris Fallin for key in alias_keys { 1291a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1292a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1293a0318f36SChris Fallin } 1294d8357426SChris Fallin 1295d8357426SChris Fallin for block in 0..self.num_blocks() { 1296a0318f36SChris Fallin let block = BlockIndex::new(block); 1297a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1298a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1299a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1300d8357426SChris Fallin } 1301a0318f36SChris Fallin for succ in self.succs(block) { 1302a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1303a0318f36SChris Fallin } 1304a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1305a0318f36SChris Fallin writeln!( 1306a0318f36SChris Fallin f, 1307a0318f36SChris Fallin " (instruction range: {} .. {})", 1308a0318f36SChris Fallin start.index(), 1309a0318f36SChris Fallin end.index() 1310a0318f36SChris Fallin )?; 1311a0318f36SChris Fallin for inst in start.index()..end.index() { 1312a0318f36SChris Fallin writeln!( 1313a0318f36SChris Fallin f, 1314a0318f36SChris Fallin " Inst {}: {}", 1315a0318f36SChris Fallin inst, 1316a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1317a0318f36SChris Fallin )?; 1318d8357426SChris Fallin } 1319d8357426SChris Fallin } 1320d8357426SChris Fallin 1321d8357426SChris Fallin writeln!(f, "}}")?; 1322d8357426SChris Fallin Ok(()) 1323d8357426SChris Fallin } 1324d8357426SChris Fallin } 1325d8357426SChris Fallin 132683f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 132783f182b3SAndrew Brown /// [MachBuffer]. 132883f182b3SAndrew Brown /// 132983f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 133083f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are 133183f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 133283f182b3SAndrew Brown /// values are inserted. 133383f182b3SAndrew Brown /// 133483f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 133583f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 133683f182b3SAndrew Brown /// then writes the constant values to the buffer. 133783f182b3SAndrew Brown #[derive(Default)] 133883f182b3SAndrew Brown pub struct VCodeConstants { 133983f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 134083f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 134183f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1342eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 134383f182b3SAndrew Brown } 134483f182b3SAndrew Brown impl VCodeConstants { 134583f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 134683f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 134783f182b3SAndrew Brown Self { 134883f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 134983f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 135083f182b3SAndrew Brown well_known_uses: HashMap::new(), 1351eb435f30SChris Fallin u64s: HashMap::new(), 135283f182b3SAndrew Brown } 135383f182b3SAndrew Brown } 135483f182b3SAndrew Brown 135583f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 135683f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 135783f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 135883f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 135983f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 136083f182b3SAndrew Brown match data { 136183f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 136283f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 136383f182b3SAndrew Brown None => { 136483f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 136583f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 136683f182b3SAndrew Brown vcode_constant 136783f182b3SAndrew Brown } 136883f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 136983f182b3SAndrew Brown }, 137083f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1371eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1372eb435f30SChris Fallin Entry::Vacant(v) => { 137383f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1374eb435f30SChris Fallin v.insert(vcode_constant); 137583f182b3SAndrew Brown vcode_constant 137683f182b3SAndrew Brown } 1377eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 137883f182b3SAndrew Brown } 137983f182b3SAndrew Brown } 1380eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1381eb435f30SChris Fallin Entry::Vacant(v) => { 1382eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1383eb435f30SChris Fallin v.insert(vcode_constant); 1384eb435f30SChris Fallin vcode_constant 1385eb435f30SChris Fallin } 1386eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1387eb435f30SChris Fallin }, 138883f182b3SAndrew Brown } 138983f182b3SAndrew Brown } 139083f182b3SAndrew Brown 139183f182b3SAndrew Brown /// Return the number of constants inserted. 139283f182b3SAndrew Brown pub fn len(&self) -> usize { 139383f182b3SAndrew Brown self.constants.len() 139483f182b3SAndrew Brown } 139583f182b3SAndrew Brown 139683f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys inserted in this structure. 139783f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 139883f182b3SAndrew Brown self.constants.keys() 139983f182b3SAndrew Brown } 140083f182b3SAndrew Brown 140183f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this 140283f182b3SAndrew Brown /// structure. 140383f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 140483f182b3SAndrew Brown self.constants.iter() 140583f182b3SAndrew Brown } 140683f182b3SAndrew Brown } 140783f182b3SAndrew Brown 140883f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 140983f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 141083f182b3SAndrew Brown pub struct VCodeConstant(u32); 141183f182b3SAndrew Brown entity_impl!(VCodeConstant); 141283f182b3SAndrew Brown 141383f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 141483f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 141583f182b3SAndrew Brown pub enum VCodeConstantData { 141683f182b3SAndrew Brown /// A constant already present in the Cranelift IR 141783f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 141883f182b3SAndrew Brown Pool(Constant, ConstantData), 141983f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 142083f182b3SAndrew Brown WellKnown(&'static [u8]), 142183f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 142283f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 142383f182b3SAndrew Brown Generated(ConstantData), 1424eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1425eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1426eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1427eb435f30SChris Fallin U64([u8; 8]), 142883f182b3SAndrew Brown } 142983f182b3SAndrew Brown impl VCodeConstantData { 143083f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 143183f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 143283f182b3SAndrew Brown match self { 143383f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 143483f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1435eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 143683f182b3SAndrew Brown } 143783f182b3SAndrew Brown } 143883f182b3SAndrew Brown 143983f182b3SAndrew Brown /// Calculate the alignment of the constant data. 144083f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 144183f182b3SAndrew Brown if self.as_slice().len() <= 8 { 144283f182b3SAndrew Brown 8 144383f182b3SAndrew Brown } else { 144483f182b3SAndrew Brown 16 144583f182b3SAndrew Brown } 144683f182b3SAndrew Brown } 144783f182b3SAndrew Brown } 144883f182b3SAndrew Brown 144983f182b3SAndrew Brown #[cfg(test)] 145083f182b3SAndrew Brown mod test { 145183f182b3SAndrew Brown use super::*; 14525e5e5206SChris Fallin use std::mem::size_of; 145383f182b3SAndrew Brown 145483f182b3SAndrew Brown #[test] 145583f182b3SAndrew Brown fn size_of_constant_structs() { 145683f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 145783f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 145883f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 145983f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 146083f182b3SAndrew Brown assert_eq!( 146183f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 146283f182b3SAndrew Brown 24 146383f182b3SAndrew Brown ); 14645e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 14655e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 14665e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 146783f182b3SAndrew Brown } 146883f182b3SAndrew Brown } 1469