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; 22*9c43749dSSam Parker use crate::ir::{ 23*9c43749dSSam Parker self, types, Constant, ConstantData, DynamicStackSlot, LabelValueLoc, SourceLoc, ValueLabel, 24*9c43749dSSam 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 212*9c43749dSSam Parker /// Offsets of sized stackslots. 213*9c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 214*9c43749dSSam Parker 215*9c43749dSSam Parker /// Offsets of dynamic stackslots. 216*9c43749dSSam 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(); 601a0318f36SChris Fallin self.compute_preds_from_succs(); 602a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 603a0318f36SChris Fallin self.vcode 604d8357426SChris Fallin } 605d8357426SChris Fallin } 606d8357426SChris Fallin 60708353fccSChris Fallin /// Is this type a reference type? 60808353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 60926529006SChris Fallin ty == types::R64 || ty == types::R32 61008353fccSChris Fallin } 61108353fccSChris Fallin 612d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 613d8357426SChris Fallin /// New empty VCode. 614c5bbc874SBenjamin Bouvier fn new( 615c5bbc874SBenjamin Bouvier abi: Box<dyn ABICallee<I = I>>, 616c5bbc874SBenjamin Bouvier emit_info: I::Info, 617c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 61883f182b3SAndrew Brown constants: VCodeConstants, 619c5bbc874SBenjamin Bouvier ) -> VCode<I> { 620a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 621d8357426SChris Fallin VCode { 622d8357426SChris Fallin vreg_types: vec![], 62308353fccSChris Fallin have_ref_values: false, 624a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 625a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 626a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 627b2e28b91SChris Fallin clobbers: FxHashMap::default(), 628a0318f36SChris Fallin is_move: FxHashMap::default(), 629a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 630a0318f36SChris Fallin entry: BlockIndex::new(0), 631a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 632a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 633a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 634a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 635a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 636a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 637a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 638a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 639a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 64072e6be93SChris Fallin block_order, 641d8357426SChris Fallin abi, 642c5bbc874SBenjamin Bouvier emit_info, 643a0318f36SChris Fallin reftyped_vregs: vec![], 644a0318f36SChris Fallin reftyped_vregs_set: FxHashSet::default(), 64583f182b3SAndrew Brown constants, 646a0318f36SChris Fallin debug_value_labels: vec![], 647a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 648d8357426SChris Fallin } 649d8357426SChris Fallin } 650d8357426SChris Fallin 651d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 652d8357426SChris Fallin /// (self.num_blocks() - 1)`. 653d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 654d8357426SChris Fallin self.block_ranges.len() 655d8357426SChris Fallin } 656d8357426SChris Fallin 657d8357426SChris Fallin /// Get the successors for a block. 658a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 659a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 660a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 661d8357426SChris Fallin } 662d8357426SChris Fallin 663a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 664a0318f36SChris Fallin // Compute clobbered registers. 665a0318f36SChris Fallin let mut clobbered = vec![]; 666a0318f36SChris Fallin let mut clobbered_set = FxHashSet::default(); 667d8357426SChris Fallin 668a0318f36SChris Fallin // All moves are included in clobbers. 669a0318f36SChris Fallin for edit in ®alloc.edits { 670a0318f36SChris Fallin let Edit::Move { to, .. } = edit.1; 671a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 672a0318f36SChris Fallin let reg = RealReg::from(preg); 673a0318f36SChris Fallin if clobbered_set.insert(reg) { 674a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 675a0318f36SChris Fallin } 676a0318f36SChris Fallin } 677d8357426SChris Fallin } 678d8357426SChris Fallin 679a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 680a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 681a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 682a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 683a0318f36SChris Fallin // the current function from clobbers, because by 684a0318f36SChris Fallin // definition everything clobbered by the call can be 685a0318f36SChris Fallin // clobbered by this function without saving as well.) 686a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 687d8357426SChris Fallin continue; 688d8357426SChris Fallin } 689d8357426SChris Fallin 690a0318f36SChris Fallin let start = *start as usize; 691a0318f36SChris Fallin let end = *end as usize; 692a0318f36SChris Fallin let operands = &self.operands[start..end]; 693a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 694a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 695a0318f36SChris Fallin // We're interested only in writes (Mods or Defs). 696a0318f36SChris Fallin if operand.kind() == OperandKind::Use { 697a0318f36SChris Fallin continue; 698d8357426SChris Fallin } 699a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 700a0318f36SChris Fallin let reg = RealReg::from(preg); 701a0318f36SChris Fallin if clobbered_set.insert(reg) { 702a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 703a0318f36SChris Fallin } 70408353fccSChris Fallin } 705d8357426SChris Fallin } 706d8357426SChris Fallin 707a0318f36SChris Fallin // Also add explicitly-clobbered registers. 708b2e28b91SChris Fallin for preg in self 709b2e28b91SChris Fallin .clobbers 710b2e28b91SChris Fallin .get(&InsnIndex::new(i)) 711b2e28b91SChris Fallin .cloned() 712b2e28b91SChris Fallin .unwrap_or_default() 713b2e28b91SChris Fallin { 714a0318f36SChris Fallin let reg = RealReg::from(preg); 715a0318f36SChris Fallin if clobbered_set.insert(reg) { 716a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 717a0318f36SChris Fallin } 718a0318f36SChris Fallin } 719a0318f36SChris Fallin } 720d8357426SChris Fallin 721a0318f36SChris Fallin clobbered 722d8357426SChris Fallin } 723d8357426SChris Fallin 724a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 725a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 726a0318f36SChris Fallin /// the regalloc results as well. 727a0318f36SChris Fallin /// 728a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 729a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 730a0318f36SChris Fallin /// is consumed by the emission process. 73111a2ef01SChris Fallin pub fn emit( 732a0318f36SChris Fallin mut self, 733a0318f36SChris Fallin regalloc: ®alloc2::Output, 734a0318f36SChris Fallin want_disasm: bool, 735a0318f36SChris Fallin want_metadata: bool, 736a0318f36SChris Fallin ) -> EmitResult<I> 737d8357426SChris Fallin where 73872e6be93SChris Fallin I: MachInstEmit, 739d8357426SChris Fallin { 740a0318f36SChris Fallin // To write into disasm string. 741a0318f36SChris Fallin use core::fmt::Write; 742a0318f36SChris Fallin 7432b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 74472e6be93SChris Fallin let mut buffer = MachBuffer::new(); 74511a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 746d8357426SChris Fallin 74783f182b3SAndrew Brown // The first M MachLabels are reserved for block indices, the next N MachLabels for 74883f182b3SAndrew Brown // constants. 749a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 75083f182b3SAndrew Brown buffer.reserve_labels_for_constants(&self.constants); 751d8357426SChris Fallin 752ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 753ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 754ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 755ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 756a0318f36SChris Fallin let block = BlockIndex::new(block); 757ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 758ef1b2d2fSChris Fallin cold_blocks.push(block); 759ef1b2d2fSChris Fallin } else { 760ef1b2d2fSChris Fallin final_order.push(block); 761ef1b2d2fSChris Fallin } 762ef1b2d2fSChris Fallin } 763d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 764ef1b2d2fSChris Fallin 765a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 766a0318f36SChris Fallin // number of spillslots. 767a0318f36SChris Fallin // 768a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 769a0318f36SChris Fallin // generate the prologue and set other info, but we can't 770a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 771a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 772a0318f36SChris Fallin // relatively cheap. 773a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 774a0318f36SChris Fallin self.abi.set_num_spillslots(regalloc.num_spillslots); 775a0318f36SChris Fallin self.abi.set_clobbered(clobbers); 776a0318f36SChris Fallin 777a0318f36SChris Fallin // We need to generate the prologue in order to get the ABI 778a0318f36SChris Fallin // object into the right state first. We'll emit it when we 779a0318f36SChris Fallin // hit the right block below. 780a0318f36SChris Fallin let prologue_insts = self.abi.gen_prologue(); 781a0318f36SChris Fallin 782ef1b2d2fSChris Fallin // Emit blocks. 783964c6087SChris Fallin let mut cur_srcloc = None; 78411a2ef01SChris Fallin let mut last_offset = None; 785a0318f36SChris Fallin let mut inst_offsets = vec![]; 786a0318f36SChris Fallin let mut state = I::State::new(&*self.abi); 787a0318f36SChris Fallin 788a0318f36SChris Fallin let mut disasm = String::new(); 789a0318f36SChris Fallin 790a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 791a0318f36SChris Fallin inst_offsets.resize(self.insts.len(), 0); 792a0318f36SChris Fallin } 793a0318f36SChris Fallin 794ef1b2d2fSChris Fallin for block in final_order { 795a0318f36SChris Fallin log::trace!("emitting block {:?}", block); 79672e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 79772e6be93SChris Fallin while new_offset > buffer.cur_offset() { 798d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 79972e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 800a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 801d8357426SChris Fallin } 80272e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 803d8357426SChris Fallin 804a0318f36SChris Fallin let do_emit = |inst: &I, 805a0318f36SChris Fallin allocs: &[Allocation], 806a0318f36SChris Fallin disasm: &mut String, 807a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 808a0318f36SChris Fallin state: &mut I::State| { 809a0318f36SChris Fallin if want_disasm { 810a0318f36SChris Fallin let mut s = state.clone(); 811a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 812a0318f36SChris Fallin } 813a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 814a0318f36SChris Fallin }; 815a0318f36SChris Fallin 816a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 817a0318f36SChris Fallin if block == self.entry { 818a0318f36SChris Fallin log::trace!(" -> entry block"); 819a0318f36SChris Fallin buffer.start_srcloc(SourceLoc::default()); 820a0318f36SChris Fallin state.pre_sourceloc(SourceLoc::default()); 821a0318f36SChris Fallin for inst in &prologue_insts { 822a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 823a0318f36SChris Fallin } 824a0318f36SChris Fallin buffer.end_srcloc(); 825d9d64694SChris Fallin } 826d9d64694SChris Fallin 827a0318f36SChris Fallin // Now emit the regular block body. 82811a2ef01SChris Fallin 829a0318f36SChris Fallin buffer.bind_label(MachLabel::from_block(block)); 830a0318f36SChris Fallin 831a0318f36SChris Fallin if want_disasm { 832a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 833a0318f36SChris Fallin } 834a0318f36SChris Fallin 835a0318f36SChris Fallin if want_metadata { 83611a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 83711a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 83811a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 83911a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 84011a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 84111a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 84211a2ef01SChris Fallin break; 84311a2ef01SChris Fallin } 84411a2ef01SChris Fallin bb_starts[i] = None; 84511a2ef01SChris Fallin } 84611a2ef01SChris Fallin } 84711a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 84811a2ef01SChris Fallin last_offset = Some(cur_offset); 849800cf25bSChris Fallin } 85011a2ef01SChris Fallin 851a0318f36SChris Fallin for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { 852a0318f36SChris Fallin match inst_or_edit { 853a0318f36SChris Fallin InstOrEdit::Inst(iix) => { 854a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 855a0318f36SChris Fallin // If we need to produce debug info, 856a0318f36SChris Fallin // record the offset of each instruction 857a0318f36SChris Fallin // so that we can translate value-label 858a0318f36SChris Fallin // ranges to machine-code offsets. 859a0318f36SChris Fallin 860a0318f36SChris Fallin // Cold blocks violate monotonicity 861a0318f36SChris Fallin // assumptions elsewhere (that 862a0318f36SChris Fallin // instructions in inst-index order are in 863a0318f36SChris Fallin // order in machine code), so we omit 864a0318f36SChris Fallin // their offsets here. Value-label range 865a0318f36SChris Fallin // generation below will skip empty ranges 866a0318f36SChris Fallin // and ranges with to-offsets of zero. 867a0318f36SChris Fallin if !self.block_order.is_cold(block) { 868a0318f36SChris Fallin inst_offsets[iix.index()] = buffer.cur_offset(); 869a0318f36SChris Fallin } 870a0318f36SChris Fallin } 871a0318f36SChris Fallin 872a0318f36SChris Fallin if self.insts[iix.index()].is_move().is_some() { 873a0318f36SChris Fallin // Skip moves in the pre-regalloc program; 874a0318f36SChris Fallin // all of these are incorporated by the 875a0318f36SChris Fallin // regalloc into its unified move handling 876a0318f36SChris Fallin // and they come out the other end, if 877a0318f36SChris Fallin // still needed (not elided), as 878a0318f36SChris Fallin // regalloc-inserted moves. 879a0318f36SChris Fallin continue; 880a0318f36SChris Fallin } 881a0318f36SChris Fallin 882a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 883a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 884964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 885964c6087SChris Fallin if cur_srcloc.is_some() { 88672e6be93SChris Fallin buffer.end_srcloc(); 887b691770fSChris Fallin } 88872e6be93SChris Fallin buffer.start_srcloc(srcloc); 889964c6087SChris Fallin cur_srcloc = Some(srcloc); 890b691770fSChris Fallin } 8914dce5109SChris Fallin state.pre_sourceloc(cur_srcloc.unwrap_or(SourceLoc::default())); 892b691770fSChris Fallin 893a0318f36SChris Fallin // If this is a safepoint, compute a stack map 894a0318f36SChris Fallin // and pass it to the emit state. 895a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 896a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 897a0318f36SChris Fallin // Find the contiguous range of 898a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 899a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 900a0318f36SChris Fallin // for this instruction index. 901a0318f36SChris Fallin let safepoint_slots_start = regalloc 902a0318f36SChris Fallin .safepoint_slots 903a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 904a0318f36SChris Fallin if progpoint.inst() >= iix { 905a0318f36SChris Fallin std::cmp::Ordering::Greater 906a0318f36SChris Fallin } else { 907a0318f36SChris Fallin std::cmp::Ordering::Less 908a0318f36SChris Fallin } 909a0318f36SChris Fallin }) 910a0318f36SChris Fallin .unwrap_err(); 911a0318f36SChris Fallin 912a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 913a0318f36SChris Fallin .iter() 914a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 915a0318f36SChris Fallin { 916a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 917a0318f36SChris Fallin safepoint_slots.push(slot); 918a0318f36SChris Fallin } 919a0318f36SChris Fallin if !safepoint_slots.is_empty() { 920666c2554SChris Fallin let stack_map = self 921666c2554SChris Fallin .abi 922a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 92305bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 92408353fccSChris Fallin } 925a0318f36SChris Fallin } 92608353fccSChris Fallin 927a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 928a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 929de4af90aSYury Delendik 930a0318f36SChris Fallin // If the instruction we are about to emit is 931a0318f36SChris Fallin // a return, place an epilogue at this point 932a0318f36SChris Fallin // (and don't emit the return; the actual 933a0318f36SChris Fallin // epilogue will contain it). 934a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 935a0318f36SChris Fallin for inst in self.abi.gen_epilogue() { 936a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 937a0318f36SChris Fallin } 938c84d6be6SChris Fallin } else { 939a0318f36SChris Fallin // Emit the instruction! 940a0318f36SChris Fallin do_emit( 941a0318f36SChris Fallin &self.insts[iix.index()], 942a0318f36SChris Fallin allocs, 943a0318f36SChris Fallin &mut disasm, 944a0318f36SChris Fallin &mut buffer, 945a0318f36SChris Fallin &mut state, 946a0318f36SChris Fallin ); 947c84d6be6SChris Fallin } 948c84d6be6SChris Fallin } 949a0318f36SChris Fallin 950a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 951a0318f36SChris Fallin // Create a move/spill/reload instruction and 952a0318f36SChris Fallin // immediately emit it. 953a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 954a0318f36SChris Fallin (Some(from), Some(to)) => { 955a0318f36SChris Fallin // Reg-to-reg move. 956a0318f36SChris Fallin let from_rreg = Reg::from(from); 957a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 958a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 959a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 960a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 961a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 962a0318f36SChris Fallin } 963a0318f36SChris Fallin (Some(from), None) => { 964a0318f36SChris Fallin // Spill from register to spillslot. 965a0318f36SChris Fallin let to = to.as_stack().unwrap(); 966a0318f36SChris Fallin let from_rreg = RealReg::from(from); 967a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 968a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 969a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 970a0318f36SChris Fallin } 971a0318f36SChris Fallin (None, Some(to)) => { 972a0318f36SChris Fallin // Load from spillslot to register. 973a0318f36SChris Fallin let from = from.as_stack().unwrap(); 974a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 975a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 976a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 977a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 978a0318f36SChris Fallin } 979a0318f36SChris Fallin (None, None) => { 980a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 981a0318f36SChris Fallin } 982a0318f36SChris Fallin } 983a0318f36SChris Fallin } 984c84d6be6SChris Fallin } 985d8357426SChris Fallin } 986b691770fSChris Fallin 987964c6087SChris Fallin if cur_srcloc.is_some() { 98872e6be93SChris Fallin buffer.end_srcloc(); 989964c6087SChris Fallin cur_srcloc = None; 990b691770fSChris Fallin } 99172e6be93SChris Fallin 992a0318f36SChris Fallin // Do we need an island? Get the worst-case size of the 993a0318f36SChris Fallin // next BB and see if, having emitted that many bytes, we 994a0318f36SChris Fallin // will be beyond the deadline. 995a0318f36SChris Fallin if block.index() < (self.num_blocks() - 1) { 996a0318f36SChris Fallin let next_block = block.index() + 1; 997a0318f36SChris Fallin let next_block_range = self.block_ranges[next_block]; 998a0318f36SChris Fallin let next_block_size = next_block_range.1.index() - next_block_range.0.index(); 999a0318f36SChris Fallin let worst_case_next_bb = I::worst_case_size() * next_block_size as u32; 100072e6be93SChris Fallin if buffer.island_needed(worst_case_next_bb) { 10011532516aSAlex Crichton buffer.emit_island(worst_case_next_bb); 100272e6be93SChris Fallin } 100372e6be93SChris Fallin } 1004d8357426SChris Fallin } 1005d8357426SChris Fallin 100683f182b3SAndrew Brown // Emit the constants used by the function. 100783f182b3SAndrew Brown for (constant, data) in self.constants.iter() { 100883f182b3SAndrew Brown let label = buffer.get_label_for_constant(constant); 100983f182b3SAndrew Brown buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value()); 101083f182b3SAndrew Brown } 101183f182b3SAndrew Brown 1012a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1013de4af90aSYury Delendik 101411a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 101511a2ef01SChris Fallin let mut bb_edges = vec![]; 1016a0318f36SChris Fallin let mut bb_offsets = vec![]; 1017a0318f36SChris Fallin if want_metadata { 101811a2ef01SChris Fallin for block in 0..self.num_blocks() { 101911a2ef01SChris Fallin if bb_starts[block].is_none() { 102011a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 102111a2ef01SChris Fallin continue; 102211a2ef01SChris Fallin } 102311a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 102411a2ef01SChris Fallin 1025a0318f36SChris Fallin bb_offsets.push(from); 102611a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1027a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1028a0318f36SChris Fallin for &succ in succs.iter() { 1029a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 103011a2ef01SChris Fallin bb_edges.push((from, to)); 103111a2ef01SChris Fallin } 103211a2ef01SChris Fallin } 1033800cf25bSChris Fallin } 103411a2ef01SChris Fallin 1035a0318f36SChris Fallin let value_labels_ranges = 1036a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1037a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1038a0318f36SChris Fallin 1039a0318f36SChris Fallin EmitResult { 1040a0318f36SChris Fallin buffer, 1041a0318f36SChris Fallin bb_offsets, 1042a0318f36SChris Fallin bb_edges, 1043a0318f36SChris Fallin inst_offsets, 1044a0318f36SChris Fallin func_body_len, 1045a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 1046*9c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 1047*9c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1048a0318f36SChris Fallin value_labels_ranges, 1049a0318f36SChris Fallin frame_size, 1050a0318f36SChris Fallin } 1051d8357426SChris Fallin } 1052d8357426SChris Fallin 1053a0318f36SChris Fallin fn compute_value_labels_ranges( 1054a0318f36SChris Fallin &self, 1055a0318f36SChris Fallin regalloc: ®alloc2::Output, 1056a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1057a0318f36SChris Fallin func_body_len: u32, 1058a0318f36SChris Fallin ) -> ValueLabelsRanges { 1059a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1060602006ffSbjorn3 return ValueLabelsRanges::default(); 1061997fab55SChris Fallin } 1062997fab55SChris Fallin 1063a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1064a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1065a0318f36SChris Fallin let ranges = value_labels_ranges 1066a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1067a0318f36SChris Fallin .or_insert_with(|| vec![]); 1068a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1069a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1070a0318f36SChris Fallin func_body_len 1071a0318f36SChris Fallin } else { 1072a0318f36SChris Fallin inst_offsets[to.inst().index()] 1073a0318f36SChris Fallin }; 1074a0318f36SChris Fallin 1075a0318f36SChris Fallin // Empty range or to-offset of zero can happen because of 1076a0318f36SChris Fallin // cold blocks (see above). 1077a0318f36SChris Fallin if to_offset == 0 || from_offset == to_offset { 1078a0318f36SChris Fallin continue; 107976d61504Sbjorn3 } 108076d61504Sbjorn3 1081a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1082a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1083a0318f36SChris Fallin } else { 1084a0318f36SChris Fallin // We can't translate spillslot locations at the 1085a0318f36SChris Fallin // moment because ValueLabelLoc requires an 1086a0318f36SChris Fallin // instantaneous SP offset, and this can *change* 1087a0318f36SChris Fallin // within the range we have here because of callsites 1088a0318f36SChris Fallin // adjusting SP temporarily. To avoid the complexity 1089a0318f36SChris Fallin // of accurately plumbing through nominal-SP 1090a0318f36SChris Fallin // adjustment sites, we just omit debug info for 1091a0318f36SChris Fallin // values that are spilled. Not ideal, but debug info 1092a0318f36SChris Fallin // is best-effort. 1093a0318f36SChris Fallin continue; 1094a0318f36SChris Fallin }; 1095a0318f36SChris Fallin 1096a0318f36SChris Fallin ranges.push(ValueLocRange { 1097a0318f36SChris Fallin loc, 1098a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1099a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1100a0318f36SChris Fallin // instruction; that is the same as the end of another 1101a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1102a0318f36SChris Fallin // we are past the previous instruction's end. 1103a0318f36SChris Fallin start: from_offset + 1, 1104a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1105a0318f36SChris Fallin // *include* the end of the last 1106a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1107a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1108a0318f36SChris Fallin // the first instruction not covered. That 1109a0318f36SChris Fallin // instruction's start is the same as the end of the 1110a0318f36SChris Fallin // last instruction that is included, so we go one 1111a0318f36SChris Fallin // byte further to be sure to include it. 1112a0318f36SChris Fallin end: to_offset + 1, 1113a0318f36SChris Fallin }); 1114a0318f36SChris Fallin } 1115a0318f36SChris Fallin 1116a0318f36SChris Fallin value_labels_ranges 1117c84d6be6SChris Fallin } 1118c84d6be6SChris Fallin 1119d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1120d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1121a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1122d8357426SChris Fallin } 1123d8357426SChris Fallin } 1124d8357426SChris Fallin 1125d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1126a0318f36SChris Fallin fn num_insts(&self) -> usize { 1127a0318f36SChris Fallin self.insts.len() 1128d8357426SChris Fallin } 1129d8357426SChris Fallin 1130a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1131a0318f36SChris Fallin self.block_ranges.len() 1132d8357426SChris Fallin } 1133d8357426SChris Fallin 1134a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1135a0318f36SChris Fallin self.entry 1136d8357426SChris Fallin } 1137d8357426SChris Fallin 1138a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1139a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1140a0318f36SChris Fallin InstRange::forward(start, end) 1141d8357426SChris Fallin } 1142d8357426SChris Fallin 1143a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1144a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1145a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1146d8357426SChris Fallin } 1147d8357426SChris Fallin 1148a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1149a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1150a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1151d8357426SChris Fallin } 1152d8357426SChris Fallin 1153a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1154a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 1155a0318f36SChris Fallin &self.block_params[start as usize..end as usize] 1156d8357426SChris Fallin } 1157d8357426SChris Fallin 1158a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1159a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1160a0318f36SChris Fallin let succ_ranges = 1161a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1162a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 1163a0318f36SChris Fallin &self.branch_block_args[branch_block_args_start as usize..branch_block_args_end as usize] 1164d8357426SChris Fallin } 1165d8357426SChris Fallin 1166a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1167a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1168d8357426SChris Fallin MachTerminator::Ret => true, 1169d8357426SChris Fallin _ => false, 1170d8357426SChris Fallin } 1171d8357426SChris Fallin } 1172d8357426SChris Fallin 1173a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1174a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 11755774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1176a0318f36SChris Fallin _ => false, 1177a0318f36SChris Fallin } 117871768bb6SChris Fallin } 117971768bb6SChris Fallin 1180a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1181a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1182d8357426SChris Fallin } 1183d8357426SChris Fallin 1184a0318f36SChris Fallin fn is_move(&self, insn: InsnIndex) -> Option<(Operand, Operand)> { 1185a0318f36SChris Fallin self.is_move.get(&insn).cloned() 1186d8357426SChris Fallin } 1187d8357426SChris Fallin 1188a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1189a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 1190a0318f36SChris Fallin &self.operands[start as usize..end as usize] 1191d8357426SChris Fallin } 1192d8357426SChris Fallin 1193b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1194b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1195be6f060aSChris Fallin } 1196be6f060aSChris Fallin 1197a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1198a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1199d8357426SChris Fallin } 1200d8357426SChris Fallin 1201a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 1202a0318f36SChris Fallin &self.reftyped_vregs[..] 1203d8357426SChris Fallin } 1204d8357426SChris Fallin 1205a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 1206a0318f36SChris Fallin &self.debug_value_labels[..] 1207d8357426SChris Fallin } 1208d8357426SChris Fallin 1209a0318f36SChris Fallin fn is_pinned_vreg(&self, vreg: VReg) -> Option<PReg> { 1210a0318f36SChris Fallin pinned_vreg_to_preg(vreg) 1211d8357426SChris Fallin } 1212d8357426SChris Fallin 1213a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1214a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1215d8357426SChris Fallin } 1216d8357426SChris Fallin 1217a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1218a0318f36SChris Fallin // At least the s390x backend requires this, because the 1219a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1220a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1221a0318f36SChris Fallin true 1222d8357426SChris Fallin } 1223d8357426SChris Fallin } 1224d8357426SChris Fallin 1225d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1226d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1227a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1228a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1229a0318f36SChris Fallin 1230a0318f36SChris Fallin let mut state = Default::default(); 1231a0318f36SChris Fallin 1232a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1233a0318f36SChris Fallin alias_keys.sort_unstable(); 1234a0318f36SChris Fallin for key in alias_keys { 1235a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1236a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1237a0318f36SChris Fallin } 1238d8357426SChris Fallin 1239d8357426SChris Fallin for block in 0..self.num_blocks() { 1240a0318f36SChris Fallin let block = BlockIndex::new(block); 1241a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1242a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1243a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1244d8357426SChris Fallin } 1245a0318f36SChris Fallin for succ in self.succs(block) { 1246a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1247a0318f36SChris Fallin } 1248a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1249a0318f36SChris Fallin writeln!( 1250a0318f36SChris Fallin f, 1251a0318f36SChris Fallin " (instruction range: {} .. {})", 1252a0318f36SChris Fallin start.index(), 1253a0318f36SChris Fallin end.index() 1254a0318f36SChris Fallin )?; 1255a0318f36SChris Fallin for inst in start.index()..end.index() { 1256a0318f36SChris Fallin writeln!( 1257a0318f36SChris Fallin f, 1258a0318f36SChris Fallin " Inst {}: {}", 1259a0318f36SChris Fallin inst, 1260a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1261a0318f36SChris Fallin )?; 1262d8357426SChris Fallin } 1263d8357426SChris Fallin } 1264d8357426SChris Fallin 1265d8357426SChris Fallin writeln!(f, "}}")?; 1266d8357426SChris Fallin Ok(()) 1267d8357426SChris Fallin } 1268d8357426SChris Fallin } 1269d8357426SChris Fallin 127083f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 127183f182b3SAndrew Brown /// [MachBuffer]. 127283f182b3SAndrew Brown /// 127383f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 127483f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are 127583f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 127683f182b3SAndrew Brown /// values are inserted. 127783f182b3SAndrew Brown /// 127883f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 127983f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 128083f182b3SAndrew Brown /// then writes the constant values to the buffer. 128183f182b3SAndrew Brown #[derive(Default)] 128283f182b3SAndrew Brown pub struct VCodeConstants { 128383f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 128483f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 128583f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1286eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 128783f182b3SAndrew Brown } 128883f182b3SAndrew Brown impl VCodeConstants { 128983f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 129083f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 129183f182b3SAndrew Brown Self { 129283f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 129383f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 129483f182b3SAndrew Brown well_known_uses: HashMap::new(), 1295eb435f30SChris Fallin u64s: HashMap::new(), 129683f182b3SAndrew Brown } 129783f182b3SAndrew Brown } 129883f182b3SAndrew Brown 129983f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 130083f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 130183f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 130283f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 130383f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 130483f182b3SAndrew Brown match data { 130583f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 130683f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 130783f182b3SAndrew Brown None => { 130883f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 130983f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 131083f182b3SAndrew Brown vcode_constant 131183f182b3SAndrew Brown } 131283f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 131383f182b3SAndrew Brown }, 131483f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1315eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1316eb435f30SChris Fallin Entry::Vacant(v) => { 131783f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1318eb435f30SChris Fallin v.insert(vcode_constant); 131983f182b3SAndrew Brown vcode_constant 132083f182b3SAndrew Brown } 1321eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 132283f182b3SAndrew Brown } 132383f182b3SAndrew Brown } 1324eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1325eb435f30SChris Fallin Entry::Vacant(v) => { 1326eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1327eb435f30SChris Fallin v.insert(vcode_constant); 1328eb435f30SChris Fallin vcode_constant 1329eb435f30SChris Fallin } 1330eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1331eb435f30SChris Fallin }, 133283f182b3SAndrew Brown } 133383f182b3SAndrew Brown } 133483f182b3SAndrew Brown 133583f182b3SAndrew Brown /// Return the number of constants inserted. 133683f182b3SAndrew Brown pub fn len(&self) -> usize { 133783f182b3SAndrew Brown self.constants.len() 133883f182b3SAndrew Brown } 133983f182b3SAndrew Brown 134083f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys inserted in this structure. 134183f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 134283f182b3SAndrew Brown self.constants.keys() 134383f182b3SAndrew Brown } 134483f182b3SAndrew Brown 134583f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this 134683f182b3SAndrew Brown /// structure. 134783f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 134883f182b3SAndrew Brown self.constants.iter() 134983f182b3SAndrew Brown } 135083f182b3SAndrew Brown } 135183f182b3SAndrew Brown 135283f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 135383f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 135483f182b3SAndrew Brown pub struct VCodeConstant(u32); 135583f182b3SAndrew Brown entity_impl!(VCodeConstant); 135683f182b3SAndrew Brown 135783f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 135883f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 135983f182b3SAndrew Brown pub enum VCodeConstantData { 136083f182b3SAndrew Brown /// A constant already present in the Cranelift IR 136183f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 136283f182b3SAndrew Brown Pool(Constant, ConstantData), 136383f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 136483f182b3SAndrew Brown WellKnown(&'static [u8]), 136583f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 136683f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 136783f182b3SAndrew Brown Generated(ConstantData), 1368eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1369eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1370eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1371eb435f30SChris Fallin U64([u8; 8]), 137283f182b3SAndrew Brown } 137383f182b3SAndrew Brown impl VCodeConstantData { 137483f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 137583f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 137683f182b3SAndrew Brown match self { 137783f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 137883f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1379eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 138083f182b3SAndrew Brown } 138183f182b3SAndrew Brown } 138283f182b3SAndrew Brown 138383f182b3SAndrew Brown /// Calculate the alignment of the constant data. 138483f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 138583f182b3SAndrew Brown if self.as_slice().len() <= 8 { 138683f182b3SAndrew Brown 8 138783f182b3SAndrew Brown } else { 138883f182b3SAndrew Brown 16 138983f182b3SAndrew Brown } 139083f182b3SAndrew Brown } 139183f182b3SAndrew Brown } 139283f182b3SAndrew Brown 139383f182b3SAndrew Brown #[cfg(test)] 139483f182b3SAndrew Brown mod test { 139583f182b3SAndrew Brown use super::*; 13965e5e5206SChris Fallin use std::mem::size_of; 139783f182b3SAndrew Brown 139883f182b3SAndrew Brown #[test] 139983f182b3SAndrew Brown fn size_of_constant_structs() { 140083f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 140183f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 140283f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 140383f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 140483f182b3SAndrew Brown assert_eq!( 140583f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 140683f182b3SAndrew Brown 24 140783f182b3SAndrew Brown ); 14085e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 14095e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 14105e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 141183f182b3SAndrew Brown } 141283f182b3SAndrew Brown } 1413