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; 22f466aa26SChris Fallin use crate::ir::pcc::*; 239ce3ffe1SAlex Crichton use crate::ir::{self, types, Constant, ConstantData, ValueLabel}; 24d8357426SChris Fallin use crate::machinst::*; 252b9fefe8SChris Fallin use crate::timing; 268d022434SBenjamin Bouvier use crate::trace; 27d94173eaSTrevor Elliott use crate::CodegenError; 28729e2640Sbjorn3 use crate::{LabelValueLoc, ValueLocRange}; 29a0318f36SChris Fallin use regalloc2::{ 305c8a603aSUlrich Weigand Edit, Function as RegallocFunction, InstOrEdit, InstRange, MachineEnv, Operand, OperandKind, 319ce3ffe1SAlex Crichton PRegSet, RegClass, 32be6f060aSChris Fallin }; 33d8357426SChris Fallin 349ce3ffe1SAlex Crichton use cranelift_entity::{entity_impl, Keys}; 35eb435f30SChris Fallin use std::collections::hash_map::Entry; 3683f182b3SAndrew Brown use std::collections::HashMap; 37d8357426SChris Fallin use std::fmt; 38d8357426SChris Fallin 39d8357426SChris Fallin /// Index referring to an instruction in VCode. 40a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst; 41a0318f36SChris Fallin 42d8357426SChris Fallin /// Index referring to a basic block in VCode. 43a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block; 44d8357426SChris Fallin 45d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be 46d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. 4772e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 4872e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {} 49d8357426SChris Fallin 50a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after 51a0318f36SChris Fallin /// lowering. This is essentially a standard CFG of basic blocks, 52a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced 53a0318f36SChris Fallin /// by the machine-specific backend. 54a0318f36SChris Fallin /// 55a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not 56a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register 57a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output` 58a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not 59a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the 60a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or 61a0318f36SChris Fallin /// metadata as requested. 62d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 63d8357426SChris Fallin /// VReg IR-level types. 64d8357426SChris Fallin vreg_types: Vec<Type>, 65d8357426SChris Fallin 66d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 6748cf2c2fSChris Fallin insts: Vec<I>, 68d8357426SChris Fallin 69a0318f36SChris Fallin /// Operands: pre-regalloc references to virtual registers with 70a0318f36SChris Fallin /// constraints, in one flattened array. This allows the regalloc 71a0318f36SChris Fallin /// to efficiently access all operands without requiring expensive 72a0318f36SChris Fallin /// matches or method invocations on insts. 73a0318f36SChris Fallin operands: Vec<Operand>, 74a0318f36SChris Fallin 75a0318f36SChris Fallin /// Operand index ranges: for each instruction in `insts`, there 76a0318f36SChris Fallin /// is a tuple here providing the range in `operands` for that 77a0318f36SChris Fallin /// instruction's operands. 78a0318f36SChris Fallin operand_ranges: Vec<(u32, u32)>, 79a0318f36SChris Fallin 80b2e28b91SChris Fallin /// Clobbers: a sparse map from instruction indices to clobber masks. 81b2e28b91SChris Fallin clobbers: FxHashMap<InsnIndex, PRegSet>, 82a0318f36SChris Fallin 83b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 84b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 858a9b1a90SBenjamin Bouvier srclocs: Vec<RelSourceLoc>, 86b691770fSChris Fallin 87d8357426SChris Fallin /// Entry block. 88d8357426SChris Fallin entry: BlockIndex, 89d8357426SChris Fallin 90d8357426SChris Fallin /// Block instruction indices. 9148cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 92d8357426SChris Fallin 93a0318f36SChris Fallin /// Block successors: index range in the `block_succs_preds` list. 94a0318f36SChris Fallin block_succ_range: Vec<(u32, u32)>, 95d8357426SChris Fallin 96a0318f36SChris Fallin /// Block predecessors: index range in the `block_succs_preds` list. 97a0318f36SChris Fallin block_pred_range: Vec<(u32, u32)>, 98a0318f36SChris Fallin 99a0318f36SChris Fallin /// Block successor and predecessor lists, concatenated into one 100a0318f36SChris Fallin /// Vec. The `block_succ_range` and `block_pred_range` lists of 101a0318f36SChris Fallin /// tuples above give (start, end) ranges within this list that 102a0318f36SChris Fallin /// correspond to each basic block's successors or predecessors, 103a0318f36SChris Fallin /// respectively. 104a0318f36SChris Fallin block_succs_preds: Vec<regalloc2::Block>, 105a0318f36SChris Fallin 106a0318f36SChris Fallin /// Block parameters: index range in `block_params` below. 107a0318f36SChris Fallin block_params_range: Vec<(u32, u32)>, 108a0318f36SChris Fallin 109a0318f36SChris Fallin /// Block parameter lists, concatenated into one vec. The 110a0318f36SChris Fallin /// `block_params_range` list of tuples above gives (start, end) 111a0318f36SChris Fallin /// ranges within this list that correspond to each basic block's 112a0318f36SChris Fallin /// blockparam vregs. 113a0318f36SChris Fallin block_params: Vec<regalloc2::VReg>, 114a0318f36SChris Fallin 115a0318f36SChris Fallin /// Outgoing block arguments on branch instructions, concatenated 116a0318f36SChris Fallin /// into one list. 117a0318f36SChris Fallin /// 118a0318f36SChris Fallin /// Note that this is conceptually a 3D array: we have a VReg list 119a0318f36SChris Fallin /// per block, per successor. We flatten those three dimensions 120a0318f36SChris Fallin /// into this 1D vec, then store index ranges in two levels of 121a0318f36SChris Fallin /// indirection. 122a0318f36SChris Fallin /// 123a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 124a0318f36SChris Fallin branch_block_args: Vec<regalloc2::VReg>, 125a0318f36SChris Fallin 126a0318f36SChris Fallin /// Array of sequences of (start, end) tuples in 127a0318f36SChris Fallin /// `branch_block_args`, one for each successor; these sequences 128a0318f36SChris Fallin /// for each block are concatenated. 129a0318f36SChris Fallin /// 130a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 131a0318f36SChris Fallin branch_block_arg_range: Vec<(u32, u32)>, 132a0318f36SChris Fallin 133a0318f36SChris Fallin /// For a given block, indices in `branch_block_arg_range` 134a0318f36SChris Fallin /// corresponding to all of its successors. 135a0318f36SChris Fallin branch_block_arg_succ_range: Vec<(u32, u32)>, 136a0318f36SChris Fallin 137a0318f36SChris Fallin /// VReg aliases. Each key in this table is translated to its 138a0318f36SChris Fallin /// value when gathering Operands from instructions. Aliases are 139a0318f36SChris Fallin /// not chased transitively (we do not further look up the 140a0318f36SChris Fallin /// translated reg to see if it is another alias). 141a0318f36SChris Fallin /// 142a0318f36SChris Fallin /// We use these aliases to rename an instruction's expected 143a0318f36SChris Fallin /// result vregs to the returned vregs from lowering, which are 144a0318f36SChris Fallin /// usually freshly-allocated temps. 145a0318f36SChris Fallin /// 146a0318f36SChris Fallin /// Operands and branch arguments will already have been 147a0318f36SChris Fallin /// translated through this alias table; but it helps to make 148a0318f36SChris Fallin /// sense of instructions when pretty-printed, for example. 149a0318f36SChris Fallin vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>, 150d8357426SChris Fallin 15172e6be93SChris Fallin /// Block-order information. 15272e6be93SChris Fallin block_order: BlockLoweringOrder, 153d8357426SChris Fallin 154d8357426SChris Fallin /// ABI object. 1552986f6b0SChris Fallin pub(crate) abi: Callee<I::ABIMachineSpec>, 15608353fccSChris Fallin 157c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 158c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 159c5bbc874SBenjamin Bouvier emit_info: I::Info, 160c5bbc874SBenjamin Bouvier 161a0318f36SChris Fallin /// Reference-typed `regalloc2::VReg`s. The regalloc requires 162a0318f36SChris Fallin /// these in a dense slice (as opposed to querying the 163a0318f36SChris Fallin /// reftype-status of each vreg) for efficient iteration. 164a0318f36SChris Fallin reftyped_vregs: Vec<VReg>, 16508353fccSChris Fallin 16683f182b3SAndrew Brown /// Constants. 1674513d9caSChris Fallin pub(crate) constants: VCodeConstants, 168997fab55SChris Fallin 169a0318f36SChris Fallin /// Value labels for debuginfo attached to vregs. 170a0318f36SChris Fallin debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, 171f18a1f14SNick Fitzgerald 1722986f6b0SChris Fallin pub(crate) sigs: SigSet, 173f466aa26SChris Fallin 174f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code verification. 175f466aa26SChris Fallin facts: Vec<Option<Fact>>, 176d8357426SChris Fallin } 177d8357426SChris Fallin 178a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed 179a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly, 180a0318f36SChris Fallin /// and optionally metadata about the code layout. 18149dd8fd7SAlex Crichton pub struct EmitResult { 182a0318f36SChris Fallin /// The MachBuffer containing the machine code. 18349dd8fd7SAlex Crichton pub buffer: MachBufferFinalized<Stencil>, 184a0318f36SChris Fallin 185a0318f36SChris Fallin /// Offset of each basic block, recorded during emission. Computed 186a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 187a0318f36SChris Fallin pub bb_offsets: Vec<CodeOffset>, 188a0318f36SChris Fallin 189a0318f36SChris Fallin /// Final basic-block edges, in terms of code offsets of 190a0318f36SChris Fallin /// bb-starts. Computed only if `debug_value_labels` is non-empty. 191a0318f36SChris Fallin pub bb_edges: Vec<(CodeOffset, CodeOffset)>, 192a0318f36SChris Fallin 193a0318f36SChris Fallin /// Final length of function body. 194a0318f36SChris Fallin pub func_body_len: CodeOffset, 195a0318f36SChris Fallin 196a0318f36SChris Fallin /// The pretty-printed disassembly, if any. This uses the same 197a0318f36SChris Fallin /// pretty-printing for MachInsts as the pre-regalloc VCode Debug 198a0318f36SChris Fallin /// implementation, but additionally includes the prologue and 199a0318f36SChris Fallin /// epilogue(s), and makes use of the regalloc results. 200a0318f36SChris Fallin pub disasm: Option<String>, 201a0318f36SChris Fallin 2029c43749dSSam Parker /// Offsets of sized stackslots. 2039c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 2049c43749dSSam Parker 2059c43749dSSam Parker /// Offsets of dynamic stackslots. 2069c43749dSSam Parker pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>, 207a0318f36SChris Fallin 208a0318f36SChris Fallin /// Value-labels information (debug metadata). 209a0318f36SChris Fallin pub value_labels_ranges: ValueLabelsRanges, 210a0318f36SChris Fallin 211a0318f36SChris Fallin /// Stack frame size. 212a0318f36SChris Fallin pub frame_size: u32, 213d9d64694SChris Fallin } 214d9d64694SChris Fallin 215a0318f36SChris Fallin /// A builder for a VCode function body. 216d8357426SChris Fallin /// 217a0318f36SChris Fallin /// This builder has the ability to accept instructions in either 218a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that 219a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst> 220a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions 221a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will 222a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine 223a0318f36SChris Fallin /// order. 224a0318f36SChris Fallin /// 225a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the 226a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the 227a0318f36SChris Fallin /// order of construction. Note that this means we do not know the 228a0318f36SChris Fallin /// final block or instruction indices when building, so we do not 229a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending 230a0318f36SChris Fallin /// terminator instructions with successor blocks.) 231d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 232d8357426SChris Fallin /// In-progress VCode. 2332986f6b0SChris Fallin pub(crate) vcode: VCode<I>, 234d8357426SChris Fallin 235a0318f36SChris Fallin /// In what direction is the build occuring? 236a0318f36SChris Fallin direction: VCodeBuildDirection, 23708353fccSChris Fallin 23872e6be93SChris Fallin /// Index of the last block-start in the vcode. 239a0318f36SChris Fallin block_start: usize, 240d8357426SChris Fallin 241d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 242d8357426SChris Fallin succ_start: usize, 243b691770fSChris Fallin 244a0318f36SChris Fallin /// Start of blockparams for the current block in the concatenated 245a0318f36SChris Fallin /// blockparams list. 246a0318f36SChris Fallin block_params_start: usize, 247a0318f36SChris Fallin 248a0318f36SChris Fallin /// Start of successor blockparam arg list entries in 249a0318f36SChris Fallin /// the concatenated branch_block_arg_range list. 250a0318f36SChris Fallin branch_block_arg_succ_start: usize, 251a0318f36SChris Fallin 252b691770fSChris Fallin /// Current source location. 2538a9b1a90SBenjamin Bouvier cur_srcloc: RelSourceLoc, 254a0318f36SChris Fallin 255a0318f36SChris Fallin /// Debug-value label in-progress map, keyed by label. For each 256a0318f36SChris Fallin /// label, we keep disjoint ranges mapping to vregs. We'll flatten 257a0318f36SChris Fallin /// this into (vreg, range, label) tuples when done. 258a0318f36SChris Fallin debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>, 259a0318f36SChris Fallin } 260a0318f36SChris Fallin 261a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode. 262a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)] 263a0318f36SChris Fallin pub enum VCodeBuildDirection { 264a0318f36SChris Fallin // TODO: add `Forward` once we need it and can test it adequately. 265a0318f36SChris Fallin /// Backward-build pass: we expect the producer to call `emit()` 266a0318f36SChris Fallin /// with instructions in reverse program order within each block. 267a0318f36SChris Fallin Backward, 268d8357426SChris Fallin } 269d8357426SChris Fallin 270d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 271d8357426SChris Fallin /// Create a new VCodeBuilder. 272c5bbc874SBenjamin Bouvier pub fn new( 273f18a1f14SNick Fitzgerald sigs: SigSet, 274f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 275c5bbc874SBenjamin Bouvier emit_info: I::Info, 276c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 27783f182b3SAndrew Brown constants: VCodeConstants, 278a0318f36SChris Fallin direction: VCodeBuildDirection, 279c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 280f18a1f14SNick Fitzgerald let vcode = VCode::new(sigs, abi, emit_info, block_order, constants); 28108353fccSChris Fallin 282d8357426SChris Fallin VCodeBuilder { 283d8357426SChris Fallin vcode, 284a0318f36SChris Fallin direction, 28572e6be93SChris Fallin block_start: 0, 286d8357426SChris Fallin succ_start: 0, 287a0318f36SChris Fallin block_params_start: 0, 288a0318f36SChris Fallin branch_block_arg_succ_start: 0, 2898a9b1a90SBenjamin Bouvier cur_srcloc: Default::default(), 290a0318f36SChris Fallin debug_info: FxHashMap::default(), 291d8357426SChris Fallin } 292d8357426SChris Fallin } 293d8357426SChris Fallin 294b6e7cc38SJamey Sharp pub fn init_retval_area(&mut self, vregs: &mut VRegAllocator<I>) -> CodegenResult<()> { 295b6e7cc38SJamey Sharp self.vcode.abi.init_retval_area(&self.vcode.sigs, vregs) 296f18a1f14SNick Fitzgerald } 297f18a1f14SNick Fitzgerald 298d8357426SChris Fallin /// Access the ABI object. 299f18a1f14SNick Fitzgerald pub fn abi(&self) -> &Callee<I::ABIMachineSpec> { 300f18a1f14SNick Fitzgerald &self.vcode.abi 301f18a1f14SNick Fitzgerald } 302f18a1f14SNick Fitzgerald 303f18a1f14SNick Fitzgerald /// Access the ABI object. 304f18a1f14SNick Fitzgerald pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> { 305f0c60f46SNick Fitzgerald &mut self.vcode.abi 306d8357426SChris Fallin } 307d8357426SChris Fallin 308f18a1f14SNick Fitzgerald pub fn sigs(&self) -> &SigSet { 309f18a1f14SNick Fitzgerald &self.vcode.sigs 310f18a1f14SNick Fitzgerald } 311f18a1f14SNick Fitzgerald 312f18a1f14SNick Fitzgerald pub fn sigs_mut(&mut self) -> &mut SigSet { 313f18a1f14SNick Fitzgerald &mut self.vcode.sigs 314f18a1f14SNick Fitzgerald } 315f18a1f14SNick Fitzgerald 31672e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 31772e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 31872e6be93SChris Fallin &self.vcode.block_order 3191d90751bSBenjamin Bouvier } 3201d90751bSBenjamin Bouvier 321d8357426SChris Fallin /// Set the current block as the entry block. 322d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 323d8357426SChris Fallin self.vcode.entry = block; 324d8357426SChris Fallin } 325d8357426SChris Fallin 326d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 327d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 32872e6be93SChris Fallin pub fn end_bb(&mut self) { 32972e6be93SChris Fallin let start_idx = self.block_start; 330a0318f36SChris Fallin let end_idx = self.vcode.insts.len(); 33172e6be93SChris Fallin self.block_start = end_idx; 332d8357426SChris Fallin // Add the instruction index range to the list of blocks. 333a0318f36SChris Fallin self.vcode 334a0318f36SChris Fallin .block_ranges 335a0318f36SChris Fallin .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx))); 336d8357426SChris Fallin // End the successors list. 337a0318f36SChris Fallin let succ_end = self.vcode.block_succs_preds.len(); 338d8357426SChris Fallin self.vcode 339d8357426SChris Fallin .block_succ_range 340a0318f36SChris Fallin .push((self.succ_start as u32, succ_end as u32)); 341d8357426SChris Fallin self.succ_start = succ_end; 342a0318f36SChris Fallin // End the blockparams list. 343a0318f36SChris Fallin let block_params_end = self.vcode.block_params.len(); 344a0318f36SChris Fallin self.vcode 345a0318f36SChris Fallin .block_params_range 346a0318f36SChris Fallin .push((self.block_params_start as u32, block_params_end as u32)); 347a0318f36SChris Fallin self.block_params_start = block_params_end; 348a0318f36SChris Fallin // End the branch blockparam args list. 349a0318f36SChris Fallin let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); 350a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.push(( 351a0318f36SChris Fallin self.branch_block_arg_succ_start as u32, 352a0318f36SChris Fallin branch_block_arg_succ_end as u32, 353a0318f36SChris Fallin )); 354a0318f36SChris Fallin self.branch_block_arg_succ_start = branch_block_arg_succ_end; 355d8357426SChris Fallin } 356d8357426SChris Fallin 357d94173eaSTrevor Elliott pub fn add_block_param(&mut self, param: VirtualReg) { 358a0318f36SChris Fallin self.vcode.block_params.push(param.into()); 359a0318f36SChris Fallin } 360a0318f36SChris Fallin 3615774e068SChris Fallin fn add_branch_args_for_succ(&mut self, args: &[Reg]) { 362a0318f36SChris Fallin let start = self.vcode.branch_block_args.len(); 363a0318f36SChris Fallin self.vcode 364a0318f36SChris Fallin .branch_block_args 365a0318f36SChris Fallin .extend(args.iter().map(|&arg| VReg::from(arg))); 366a0318f36SChris Fallin let end = self.vcode.branch_block_args.len(); 367a0318f36SChris Fallin self.vcode 368a0318f36SChris Fallin .branch_block_arg_range 369a0318f36SChris Fallin .push((start as u32, end as u32)); 370a0318f36SChris Fallin } 371a0318f36SChris Fallin 372a0318f36SChris Fallin /// Push an instruction for the current BB and current IR inst 373a0318f36SChris Fallin /// within the BB. 374a0318f36SChris Fallin pub fn push(&mut self, insn: I) { 37572e6be93SChris Fallin self.vcode.insts.push(insn); 37672e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 37772e6be93SChris Fallin } 37872e6be93SChris Fallin 3795774e068SChris Fallin /// Add a successor block with branch args. 3805774e068SChris Fallin pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { 3815774e068SChris Fallin self.vcode.block_succs_preds.push(block); 3825774e068SChris Fallin self.add_branch_args_for_succ(args); 3835774e068SChris Fallin } 3845774e068SChris Fallin 385b691770fSChris Fallin /// Set the current source location. 3868a9b1a90SBenjamin Bouvier pub fn set_srcloc(&mut self, srcloc: RelSourceLoc) { 387b691770fSChris Fallin self.cur_srcloc = srcloc; 388d8357426SChris Fallin } 389d8357426SChris Fallin 390a0318f36SChris Fallin /// Add a debug value label to a register. 391a0318f36SChris Fallin pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { 392a0318f36SChris Fallin // We'll fix up labels in reverse(). Because we're generating 393a0318f36SChris Fallin // code bottom-to-top, the liverange of the label goes *from* 394a0318f36SChris Fallin // the last index at which was defined (or 0, which is the end 395a0318f36SChris Fallin // of the eventual function) *to* just this instruction, and 396a0318f36SChris Fallin // no further. 397a0318f36SChris Fallin let inst = InsnIndex::new(self.vcode.insts.len()); 398a0318f36SChris Fallin let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); 399a0318f36SChris Fallin let last = labels 400a0318f36SChris Fallin .last() 401a0318f36SChris Fallin .map(|(_start, end, _vreg)| *end) 402a0318f36SChris Fallin .unwrap_or(InsnIndex::new(0)); 403a0318f36SChris Fallin labels.push((last, inst, reg.into())); 404a0318f36SChris Fallin } 405a0318f36SChris Fallin 406a0318f36SChris Fallin pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { 407a0318f36SChris Fallin let from = from.into(); 408fef8a90fSChris Fallin let resolved_to = self.vcode.resolve_vreg_alias(to.into()); 409a0318f36SChris Fallin // Disallow cycles (see below). 410a0318f36SChris Fallin assert_ne!(resolved_to, from); 411a0318f36SChris Fallin self.vcode.vreg_aliases.insert(from, resolved_to); 412a0318f36SChris Fallin } 413a0318f36SChris Fallin 41483f182b3SAndrew Brown /// Access the constants. 41583f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 41683f182b3SAndrew Brown &mut self.vcode.constants 41783f182b3SAndrew Brown } 41883f182b3SAndrew Brown 419a0318f36SChris Fallin fn compute_preds_from_succs(&mut self) { 420a0318f36SChris Fallin // Compute predecessors from successors. In order to gather 421a0318f36SChris Fallin // all preds for a block into a contiguous sequence, we build 422a0318f36SChris Fallin // a list of (succ, pred) tuples and then sort. 423a0318f36SChris Fallin let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> = 424a0318f36SChris Fallin Vec::with_capacity(self.vcode.block_succs_preds.len()); 425a0318f36SChris Fallin for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() { 426a0318f36SChris Fallin let pred = BlockIndex::new(pred); 427a0318f36SChris Fallin for i in start..end { 428a0318f36SChris Fallin let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index()); 429a0318f36SChris Fallin succ_pred_edges.push((succ, pred)); 430a0318f36SChris Fallin } 431a0318f36SChris Fallin } 432a0318f36SChris Fallin succ_pred_edges.sort_unstable(); 433a0318f36SChris Fallin 434a0318f36SChris Fallin let mut i = 0; 435a0318f36SChris Fallin for succ in 0..self.vcode.num_blocks() { 436a0318f36SChris Fallin let succ = BlockIndex::new(succ); 437a0318f36SChris Fallin let start = self.vcode.block_succs_preds.len(); 438a0318f36SChris Fallin while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ { 439a0318f36SChris Fallin let pred = succ_pred_edges[i].1; 440a0318f36SChris Fallin self.vcode.block_succs_preds.push(pred); 441a0318f36SChris Fallin i += 1; 442a0318f36SChris Fallin } 443a0318f36SChris Fallin let end = self.vcode.block_succs_preds.len(); 444a0318f36SChris Fallin self.vcode.block_pred_range.push((start as u32, end as u32)); 445d8357426SChris Fallin } 446d8357426SChris Fallin } 447d8357426SChris Fallin 448a0318f36SChris Fallin /// Called once, when a build in Backward order is complete, to 449a0318f36SChris Fallin /// perform the overall reversal (into final forward order) and 450a0318f36SChris Fallin /// finalize metadata accordingly. 451a0318f36SChris Fallin fn reverse_and_finalize(&mut self) { 452a0318f36SChris Fallin let n_insts = self.vcode.insts.len(); 453a0318f36SChris Fallin if n_insts == 0 { 454a0318f36SChris Fallin return; 455a0318f36SChris Fallin } 456a0318f36SChris Fallin 457a0318f36SChris Fallin // Reverse the per-block and per-inst sequences. 458a0318f36SChris Fallin self.vcode.block_ranges.reverse(); 459a0318f36SChris Fallin // block_params_range is indexed by block (and blocks were 460a0318f36SChris Fallin // traversed in reverse) so we reverse it; but block-param 461a0318f36SChris Fallin // sequences in the concatenated vec can remain in reverse 462a0318f36SChris Fallin // order (it is effectively an arena of arbitrarily-placed 463a0318f36SChris Fallin // referenced sequences). 464a0318f36SChris Fallin self.vcode.block_params_range.reverse(); 465a0318f36SChris Fallin // Likewise, we reverse block_succ_range, but the block_succ 466a0318f36SChris Fallin // concatenated array can remain as-is. 467a0318f36SChris Fallin self.vcode.block_succ_range.reverse(); 468a0318f36SChris Fallin self.vcode.insts.reverse(); 469a0318f36SChris Fallin self.vcode.srclocs.reverse(); 470a0318f36SChris Fallin // Likewise, branch_block_arg_succ_range is indexed by block 471a0318f36SChris Fallin // so must be reversed. 472a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.reverse(); 473a0318f36SChris Fallin 474a0318f36SChris Fallin // To translate an instruction index *endpoint* in reversed 475a0318f36SChris Fallin // order to forward order, compute `n_insts - i`. 476a0318f36SChris Fallin // 477a0318f36SChris Fallin // Why not `n_insts - 1 - i`? That would be correct to 478a0318f36SChris Fallin // translate an individual instruction index (for ten insts 0 479a0318f36SChris Fallin // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes 480a0318f36SChris Fallin // 0). But for the usual inclusive-start, exclusive-end range 481a0318f36SChris Fallin // idiom, inclusive starts become exclusive ends and 482a0318f36SChris Fallin // vice-versa, so e.g. an (inclusive) start of 0 becomes an 483a0318f36SChris Fallin // (exclusive) end of 10. 484a0318f36SChris Fallin let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); 485a0318f36SChris Fallin 486a0318f36SChris Fallin // Edit the block-range instruction indices. 487a0318f36SChris Fallin for tuple in &mut self.vcode.block_ranges { 488a0318f36SChris Fallin let (start, end) = *tuple; 489a0318f36SChris Fallin *tuple = (translate(end), translate(start)); // Note reversed order. 490a0318f36SChris Fallin } 491a0318f36SChris Fallin 492a0318f36SChris Fallin // Generate debug-value labels based on per-label maps. 493a0318f36SChris Fallin for (label, tuples) in &self.debug_info { 494a0318f36SChris Fallin for &(start, end, vreg) in tuples { 495fef8a90fSChris Fallin let vreg = self.vcode.resolve_vreg_alias(vreg); 496a0318f36SChris Fallin let fwd_start = translate(end); 497a0318f36SChris Fallin let fwd_end = translate(start); 498a0318f36SChris Fallin self.vcode 499a0318f36SChris Fallin .debug_value_labels 500a0318f36SChris Fallin .push((vreg, fwd_start, fwd_end, label.as_u32())); 501a0318f36SChris Fallin } 502a0318f36SChris Fallin } 503a0318f36SChris Fallin 504a0318f36SChris Fallin // Now sort debug value labels by VReg, as required 505a0318f36SChris Fallin // by regalloc2. 506a0318f36SChris Fallin self.vcode 507a0318f36SChris Fallin .debug_value_labels 508a0318f36SChris Fallin .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); 509a0318f36SChris Fallin } 510a0318f36SChris Fallin 5115c8a603aSUlrich Weigand fn collect_operands(&mut self) { 512a0318f36SChris Fallin for (i, insn) in self.vcode.insts.iter().enumerate() { 513a0318f36SChris Fallin // Push operands from the instruction onto the operand list. 514a0318f36SChris Fallin // 515a0318f36SChris Fallin // We rename through the vreg alias table as we collect 516a0318f36SChris Fallin // the operands. This is better than a separate post-pass 517a0318f36SChris Fallin // over operands, because it has more cache locality: 518a0318f36SChris Fallin // operands only need to pass through L1 once. This is 519a0318f36SChris Fallin // also better than renaming instructions' 520a0318f36SChris Fallin // operands/registers while lowering, because here we only 521a0318f36SChris Fallin // need to do the `match` over the instruction to visit 522a0318f36SChris Fallin // its register fields (which is slow, branchy code) once. 523a0318f36SChris Fallin 524a0318f36SChris Fallin let vreg_aliases = &self.vcode.vreg_aliases; 5255c8a603aSUlrich Weigand let allocatable = PRegSet::from(self.vcode.machine_env()); 526a007e02bSTrevor Elliott let mut op_collector = 527a007e02bSTrevor Elliott OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| { 528fef8a90fSChris Fallin VCode::<I>::resolve_vreg_alias_impl(vreg_aliases, vreg) 529a0318f36SChris Fallin }); 530a0318f36SChris Fallin insn.get_operands(&mut op_collector); 531a0318f36SChris Fallin let (ops, clobbers) = op_collector.finish(); 532a0318f36SChris Fallin self.vcode.operand_ranges.push(ops); 533a0318f36SChris Fallin 534b2e28b91SChris Fallin if clobbers != PRegSet::default() { 535b2e28b91SChris Fallin self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); 536a0318f36SChris Fallin } 537a0318f36SChris Fallin 538a0318f36SChris Fallin if let Some((dst, src)) = insn.is_move() { 539fac4a915STrevor Elliott // We should never see non-virtual registers present in move 540fac4a915STrevor Elliott // instructions. 541fac4a915STrevor Elliott assert!( 542fac4a915STrevor Elliott src.is_virtual(), 543fac4a915STrevor Elliott "the real register {:?} was used as the source of a move instruction", 544fac4a915STrevor Elliott src 545fac4a915STrevor Elliott ); 546fac4a915STrevor Elliott assert!( 547fac4a915STrevor Elliott dst.to_reg().is_virtual(), 548fac4a915STrevor Elliott "the real register {:?} was used as the destination of a move instruction", 549fac4a915STrevor Elliott dst.to_reg() 550fac4a915STrevor Elliott ); 551a0318f36SChris Fallin } 552a0318f36SChris Fallin } 553a0318f36SChris Fallin 554a0318f36SChris Fallin // Translate blockparam args via the vreg aliases table as well. 555a0318f36SChris Fallin for arg in &mut self.vcode.branch_block_args { 556fef8a90fSChris Fallin let new_arg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg); 5578d022434SBenjamin Bouvier trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); 558a0318f36SChris Fallin *arg = new_arg; 559a0318f36SChris Fallin } 560a0318f36SChris Fallin } 561a0318f36SChris Fallin 562a0318f36SChris Fallin /// Build the final VCode. 5635c8a603aSUlrich Weigand pub fn build(mut self, vregs: VRegAllocator<I>) -> VCode<I> { 564d94173eaSTrevor Elliott self.vcode.vreg_types = vregs.vreg_types; 565f466aa26SChris Fallin self.vcode.facts = vregs.facts; 566d94173eaSTrevor Elliott self.vcode.reftyped_vregs = vregs.reftyped_vregs; 567d94173eaSTrevor Elliott 568a0318f36SChris Fallin if self.direction == VCodeBuildDirection::Backward { 569a0318f36SChris Fallin self.reverse_and_finalize(); 570a0318f36SChris Fallin } 5715c8a603aSUlrich Weigand self.collect_operands(); 5722154c63dSAlex Crichton 5732154c63dSAlex Crichton // Apply register aliases to the `reftyped_vregs` list since this list 5742154c63dSAlex Crichton // will be returned directly to `regalloc2` eventually and all 5752154c63dSAlex Crichton // operands/results of instructions will use the alias-resolved vregs 5762154c63dSAlex Crichton // from `regalloc2`'s perspective. 5772127c3a3SAlex Crichton // 5782127c3a3SAlex Crichton // Also note that `reftyped_vregs` can't have duplicates, so after the 5792127c3a3SAlex Crichton // aliases are applied duplicates are removed. 5802154c63dSAlex Crichton for reg in self.vcode.reftyped_vregs.iter_mut() { 581fef8a90fSChris Fallin *reg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg); 5822154c63dSAlex Crichton } 5832127c3a3SAlex Crichton self.vcode.reftyped_vregs.sort(); 5842127c3a3SAlex Crichton self.vcode.reftyped_vregs.dedup(); 5852154c63dSAlex Crichton 586a0318f36SChris Fallin self.compute_preds_from_succs(); 587a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 588a0318f36SChris Fallin self.vcode 589d8357426SChris Fallin } 590d8357426SChris Fallin } 591d8357426SChris Fallin 59208353fccSChris Fallin /// Is this type a reference type? 59308353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 59426529006SChris Fallin ty == types::R64 || ty == types::R32 59508353fccSChris Fallin } 59608353fccSChris Fallin 597d4a4d4f9SSingleAccretion const NO_INST_OFFSET: CodeOffset = u32::MAX; 598d4a4d4f9SSingleAccretion 599d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 600d8357426SChris Fallin /// New empty VCode. 601c5bbc874SBenjamin Bouvier fn new( 602f18a1f14SNick Fitzgerald sigs: SigSet, 603f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 604c5bbc874SBenjamin Bouvier emit_info: I::Info, 605c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 60683f182b3SAndrew Brown constants: VCodeConstants, 607c5bbc874SBenjamin Bouvier ) -> VCode<I> { 608a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 609d8357426SChris Fallin VCode { 610f18a1f14SNick Fitzgerald sigs, 611d8357426SChris Fallin vreg_types: vec![], 612a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 613a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 614a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 615b2e28b91SChris Fallin clobbers: FxHashMap::default(), 616a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 617a0318f36SChris Fallin entry: BlockIndex::new(0), 618a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 619a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 620a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 621a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 622a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 623a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 624a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 625a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 626a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 62772e6be93SChris Fallin block_order, 628d8357426SChris Fallin abi, 629c5bbc874SBenjamin Bouvier emit_info, 630a0318f36SChris Fallin reftyped_vregs: vec![], 63183f182b3SAndrew Brown constants, 632a0318f36SChris Fallin debug_value_labels: vec![], 633a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 634f466aa26SChris Fallin facts: vec![], 635d8357426SChris Fallin } 636d8357426SChris Fallin } 637d8357426SChris Fallin 6385c8a603aSUlrich Weigand /// Get the ABI-dependent MachineEnv for managing register allocation. 6395c8a603aSUlrich Weigand pub fn machine_env(&self) -> &MachineEnv { 6405c8a603aSUlrich Weigand self.abi.machine_env(&self.sigs) 6415c8a603aSUlrich Weigand } 6425c8a603aSUlrich Weigand 643d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 644d8357426SChris Fallin /// (self.num_blocks() - 1)`. 645d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 646d8357426SChris Fallin self.block_ranges.len() 647d8357426SChris Fallin } 648d8357426SChris Fallin 6496fe69d00SNick Fitzgerald /// The number of lowered instructions. 6506fe69d00SNick Fitzgerald pub fn num_insts(&self) -> usize { 6516fe69d00SNick Fitzgerald self.insts.len() 6526fe69d00SNick Fitzgerald } 6536fe69d00SNick Fitzgerald 654d8357426SChris Fallin /// Get the successors for a block. 655a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 656a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 657a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 658d8357426SChris Fallin } 659d8357426SChris Fallin 660a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 6611a17dfb5SJamey Sharp let mut clobbered = PRegSet::default(); 662d8357426SChris Fallin 663a0318f36SChris Fallin // All moves are included in clobbers. 6641a17dfb5SJamey Sharp for (_, Edit::Move { to, .. }) in ®alloc.edits { 665a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 6661a17dfb5SJamey Sharp clobbered.add(preg); 667a0318f36SChris Fallin } 668d8357426SChris Fallin } 669d8357426SChris Fallin 670a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 671a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 672a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 673a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 674a0318f36SChris Fallin // the current function from clobbers, because by 675a0318f36SChris Fallin // definition everything clobbered by the call can be 676a0318f36SChris Fallin // clobbered by this function without saving as well.) 677a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 678d8357426SChris Fallin continue; 679d8357426SChris Fallin } 680d8357426SChris Fallin 681a0318f36SChris Fallin let start = *start as usize; 682a0318f36SChris Fallin let end = *end as usize; 683a0318f36SChris Fallin let operands = &self.operands[start..end]; 684a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 685a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 6861a17dfb5SJamey Sharp if operand.kind() == OperandKind::Def { 687a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 6881a17dfb5SJamey Sharp clobbered.add(preg); 689a0318f36SChris Fallin } 69008353fccSChris Fallin } 691d8357426SChris Fallin } 692d8357426SChris Fallin 693a0318f36SChris Fallin // Also add explicitly-clobbered registers. 6941a17dfb5SJamey Sharp if let Some(&inst_clobbered) = self.clobbers.get(&InsnIndex::new(i)) { 6951a17dfb5SJamey Sharp clobbered.union_from(inst_clobbered); 696a0318f36SChris Fallin } 697a0318f36SChris Fallin } 698d8357426SChris Fallin 699a0318f36SChris Fallin clobbered 7001a17dfb5SJamey Sharp .into_iter() 7011a17dfb5SJamey Sharp .map(|preg| Writable::from_reg(RealReg::from(preg))) 7021a17dfb5SJamey Sharp .collect() 703d8357426SChris Fallin } 704d8357426SChris Fallin 705a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 706a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 707a0318f36SChris Fallin /// the regalloc results as well. 708a0318f36SChris Fallin /// 709a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 710a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 711a0318f36SChris Fallin /// is consumed by the emission process. 71211a2ef01SChris Fallin pub fn emit( 713a0318f36SChris Fallin mut self, 714a0318f36SChris Fallin regalloc: ®alloc2::Output, 715a0318f36SChris Fallin want_disasm: bool, 71649dd8fd7SAlex Crichton flags: &settings::Flags, 7177eb89140SRemo Senekowitsch ctrl_plane: &mut ControlPlane, 71849dd8fd7SAlex Crichton ) -> EmitResult 719d8357426SChris Fallin where 720f18a1f14SNick Fitzgerald I: VCodeInst, 721d8357426SChris Fallin { 722a0318f36SChris Fallin // To write into disasm string. 723a0318f36SChris Fallin use core::fmt::Write; 724a0318f36SChris Fallin 7252b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 72672e6be93SChris Fallin let mut buffer = MachBuffer::new(); 72711a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 728d8357426SChris Fallin 72949dd8fd7SAlex Crichton // The first M MachLabels are reserved for block indices. 730a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 73149dd8fd7SAlex Crichton 73249dd8fd7SAlex Crichton // Register all allocated constants with the `MachBuffer` to ensure that 73349dd8fd7SAlex Crichton // any references to the constants during instructions can be handled 73449dd8fd7SAlex Crichton // correctly. 73549dd8fd7SAlex Crichton buffer.register_constants(&self.constants); 736d8357426SChris Fallin 737ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 738ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 739ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 740ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 741a0318f36SChris Fallin let block = BlockIndex::new(block); 742ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 743ef1b2d2fSChris Fallin cold_blocks.push(block); 744ef1b2d2fSChris Fallin } else { 745ef1b2d2fSChris Fallin final_order.push(block); 746ef1b2d2fSChris Fallin } 747ef1b2d2fSChris Fallin } 748d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 749ef1b2d2fSChris Fallin 750a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 751a0318f36SChris Fallin // number of spillslots. 752a0318f36SChris Fallin // 753a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 754a0318f36SChris Fallin // generate the prologue and set other info, but we can't 755a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 756a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 757a0318f36SChris Fallin // relatively cheap. 758a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 7595d4e319cSJamey Sharp self.abi 7605d4e319cSJamey Sharp .compute_frame_layout(&self.sigs, regalloc.num_spillslots, clobbers); 761a0318f36SChris Fallin 762ef1b2d2fSChris Fallin // Emit blocks. 763964c6087SChris Fallin let mut cur_srcloc = None; 76411a2ef01SChris Fallin let mut last_offset = None; 765a0318f36SChris Fallin let mut inst_offsets = vec![]; 7667eb89140SRemo Senekowitsch let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane)); 767a0318f36SChris Fallin 768a0318f36SChris Fallin let mut disasm = String::new(); 769a0318f36SChris Fallin 770a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 771d4a4d4f9SSingleAccretion inst_offsets.resize(self.insts.len(), NO_INST_OFFSET); 772a0318f36SChris Fallin } 773a0318f36SChris Fallin 774863659e0SChris Fallin // Count edits per block ahead of time; this is needed for 775863659e0SChris Fallin // lookahead island emission. (We could derive it per-block 776863659e0SChris Fallin // with binary search in the edit list, but it's more 777863659e0SChris Fallin // efficient to do it in one pass here.) 778863659e0SChris Fallin let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; 779863659e0SChris Fallin let mut edit_idx = 0; 780863659e0SChris Fallin for block in 0..self.num_blocks() { 781863659e0SChris Fallin let end_inst = self.block_ranges[block].1; 782863659e0SChris Fallin let start_edit_idx = edit_idx; 783863659e0SChris Fallin while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { 784863659e0SChris Fallin edit_idx += 1; 785863659e0SChris Fallin } 786863659e0SChris Fallin let end_edit_idx = edit_idx; 787863659e0SChris Fallin ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); 788863659e0SChris Fallin } 789863659e0SChris Fallin 790d8b29089SAnton Kirilov let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); 791475d1ba5SAlex Crichton let mut bb_padding = match flags.bb_padding_log2_minus_one() { 79249dd8fd7SAlex Crichton 0 => Vec::new(), 79349dd8fd7SAlex Crichton n => vec![0; 1 << (n - 1)], 79449dd8fd7SAlex Crichton }; 795475d1ba5SAlex Crichton let mut total_bb_padding = 0; 796d8b29089SAnton Kirilov 797863659e0SChris Fallin for (block_order_idx, &block) in final_order.iter().enumerate() { 7988d022434SBenjamin Bouvier trace!("emitting block {:?}", block); 79960e4a004SAfonso Bordado 80060e4a004SAfonso Bordado // Call the new block hook for state 80160e4a004SAfonso Bordado state.on_new_block(); 80260e4a004SAfonso Bordado 80360e4a004SAfonso Bordado // Emit NOPs to align the block. 80472e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 80572e6be93SChris Fallin while new_offset > buffer.cur_offset() { 806d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 80772e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 808a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 809d8357426SChris Fallin } 81072e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 811d8357426SChris Fallin 812a0318f36SChris Fallin let do_emit = |inst: &I, 813a0318f36SChris Fallin allocs: &[Allocation], 814a0318f36SChris Fallin disasm: &mut String, 815a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 816a0318f36SChris Fallin state: &mut I::State| { 8172986f6b0SChris Fallin if want_disasm && !inst.is_args() { 818a0318f36SChris Fallin let mut s = state.clone(); 819a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 820a0318f36SChris Fallin } 821a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 822a0318f36SChris Fallin }; 823a0318f36SChris Fallin 824a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 825a0318f36SChris Fallin if block == self.entry { 8268d022434SBenjamin Bouvier trace!(" -> entry block"); 8278a9b1a90SBenjamin Bouvier buffer.start_srcloc(Default::default()); 82886652959SUlrich Weigand for inst in &self.abi.gen_prologue() { 829a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 830a0318f36SChris Fallin } 831a0318f36SChris Fallin buffer.end_srcloc(); 832d9d64694SChris Fallin } 833d9d64694SChris Fallin 834a0318f36SChris Fallin // Now emit the regular block body. 83511a2ef01SChris Fallin 8367eb89140SRemo Senekowitsch buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut()); 837a0318f36SChris Fallin 838a0318f36SChris Fallin if want_disasm { 839a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 840a0318f36SChris Fallin } 841a0318f36SChris Fallin 84249dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 84311a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 84411a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 84511a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 84611a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 84711a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 84811a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 84911a2ef01SChris Fallin break; 85011a2ef01SChris Fallin } 85111a2ef01SChris Fallin bb_starts[i] = None; 85211a2ef01SChris Fallin } 85311a2ef01SChris Fallin } 85411a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 85511a2ef01SChris Fallin last_offset = Some(cur_offset); 856800cf25bSChris Fallin } 85711a2ef01SChris Fallin 858d8b29089SAnton Kirilov if let Some(block_start) = I::gen_block_start( 859d8b29089SAnton Kirilov self.block_order.is_indirect_branch_target(block), 860d8b29089SAnton Kirilov is_forward_edge_cfi_enabled, 861d8b29089SAnton Kirilov ) { 862d8b29089SAnton Kirilov do_emit(&block_start, &[], &mut disasm, &mut buffer, &mut state); 863d8b29089SAnton Kirilov } 864d8b29089SAnton Kirilov 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 // Update the srcloc at this point in the buffer. 887a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 888964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 889964c6087SChris Fallin if cur_srcloc.is_some() { 89072e6be93SChris Fallin buffer.end_srcloc(); 891b691770fSChris Fallin } 89272e6be93SChris Fallin buffer.start_srcloc(srcloc); 893964c6087SChris Fallin cur_srcloc = Some(srcloc); 894b691770fSChris Fallin } 895b691770fSChris Fallin 896a0318f36SChris Fallin // If this is a safepoint, compute a stack map 897a0318f36SChris Fallin // and pass it to the emit state. 898a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 899a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 900a0318f36SChris Fallin // Find the contiguous range of 901a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 902a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 903a0318f36SChris Fallin // for this instruction index. 904a0318f36SChris Fallin let safepoint_slots_start = regalloc 905a0318f36SChris Fallin .safepoint_slots 906a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 907a0318f36SChris Fallin if progpoint.inst() >= iix { 908a0318f36SChris Fallin std::cmp::Ordering::Greater 909a0318f36SChris Fallin } else { 910a0318f36SChris Fallin std::cmp::Ordering::Less 911a0318f36SChris Fallin } 912a0318f36SChris Fallin }) 913a0318f36SChris Fallin .unwrap_err(); 914a0318f36SChris Fallin 915a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 916a0318f36SChris Fallin .iter() 917a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 918a0318f36SChris Fallin { 919a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 920a0318f36SChris Fallin safepoint_slots.push(slot); 921a0318f36SChris Fallin } 922a0318f36SChris Fallin if !safepoint_slots.is_empty() { 923666c2554SChris Fallin let stack_map = self 924666c2554SChris Fallin .abi 925a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 92605bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 92708353fccSChris Fallin } 928a0318f36SChris Fallin } 92908353fccSChris Fallin 930a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 931a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 932de4af90aSYury Delendik 933a0318f36SChris Fallin // If the instruction we are about to emit is 934a0318f36SChris Fallin // a return, place an epilogue at this point 935a0318f36SChris Fallin // (and don't emit the return; the actual 936a0318f36SChris Fallin // epilogue will contain it). 937a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 93886652959SUlrich Weigand for inst in self.abi.gen_epilogue() { 939a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 940a0318f36SChris Fallin } 941c84d6be6SChris Fallin } else { 942a0318f36SChris Fallin // Emit the instruction! 943a0318f36SChris Fallin do_emit( 944a0318f36SChris Fallin &self.insts[iix.index()], 945a0318f36SChris Fallin allocs, 946a0318f36SChris Fallin &mut disasm, 947a0318f36SChris Fallin &mut buffer, 948a0318f36SChris Fallin &mut state, 949a0318f36SChris Fallin ); 950c84d6be6SChris Fallin } 951c84d6be6SChris Fallin } 952a0318f36SChris Fallin 953a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 954a0318f36SChris Fallin // Create a move/spill/reload instruction and 955a0318f36SChris Fallin // immediately emit it. 956a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 957a0318f36SChris Fallin (Some(from), Some(to)) => { 958a0318f36SChris Fallin // Reg-to-reg move. 959a0318f36SChris Fallin let from_rreg = Reg::from(from); 960a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 961a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 962a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 963a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 964a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 965a0318f36SChris Fallin } 966a0318f36SChris Fallin (Some(from), None) => { 967a0318f36SChris Fallin // Spill from register to spillslot. 968a0318f36SChris Fallin let to = to.as_stack().unwrap(); 969a0318f36SChris Fallin let from_rreg = RealReg::from(from); 970a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 971a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 972a0318f36SChris Fallin } 973a0318f36SChris Fallin (None, Some(to)) => { 974a0318f36SChris Fallin // Load from spillslot to register. 975a0318f36SChris Fallin let from = from.as_stack().unwrap(); 976a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 977a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 978a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 979a0318f36SChris Fallin } 980a0318f36SChris Fallin (None, None) => { 981a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 982a0318f36SChris Fallin } 983a0318f36SChris Fallin } 984a0318f36SChris Fallin } 985c84d6be6SChris Fallin } 986d8357426SChris Fallin } 987b691770fSChris Fallin 988964c6087SChris Fallin if cur_srcloc.is_some() { 98972e6be93SChris Fallin buffer.end_srcloc(); 990964c6087SChris Fallin cur_srcloc = None; 991b691770fSChris Fallin } 99272e6be93SChris Fallin 99349dd8fd7SAlex Crichton // Do we need an island? Get the worst-case size of the next BB, add 99449dd8fd7SAlex Crichton // it to the optional padding behind the block, and pass this to the 99549dd8fd7SAlex Crichton // `MachBuffer` to determine if an island is necessary. 99649dd8fd7SAlex Crichton let worst_case_next_bb = if block_order_idx < final_order.len() - 1 { 997863659e0SChris Fallin let next_block = final_order[block_order_idx + 1]; 998863659e0SChris Fallin let next_block_range = self.block_ranges[next_block.index()]; 999863659e0SChris Fallin let next_block_size = 1000863659e0SChris Fallin (next_block_range.1.index() - next_block_range.0.index()) as u32; 1001863659e0SChris Fallin let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; 100249dd8fd7SAlex Crichton I::worst_case_size() * (next_block_size + next_block_ra_insertions) 100349dd8fd7SAlex Crichton } else { 100449dd8fd7SAlex Crichton 0 100549dd8fd7SAlex Crichton }; 100649dd8fd7SAlex Crichton let padding = if bb_padding.is_empty() { 100749dd8fd7SAlex Crichton 0 100849dd8fd7SAlex Crichton } else { 100949dd8fd7SAlex Crichton bb_padding.len() as u32 + I::LabelUse::ALIGN - 1 101049dd8fd7SAlex Crichton }; 101149dd8fd7SAlex Crichton if buffer.island_needed(padding + worst_case_next_bb) { 1012f8c03d5aSAlex Crichton buffer.emit_island(padding + worst_case_next_bb, ctrl_plane); 101372e6be93SChris Fallin } 101449dd8fd7SAlex Crichton 101549dd8fd7SAlex Crichton // Insert padding, if configured, to stress the `MachBuffer`'s 101649dd8fd7SAlex Crichton // relocation and island calculations. 1017475d1ba5SAlex Crichton // 1018475d1ba5SAlex Crichton // Padding can get quite large during fuzzing though so place a 1019475d1ba5SAlex Crichton // total cap on it where when a per-function threshold is exceeded 1020475d1ba5SAlex Crichton // the padding is turned back down to zero. This avoids a small-ish 1021475d1ba5SAlex Crichton // test case generating a GB+ memory footprint in Cranelift for 1022475d1ba5SAlex Crichton // example. 102349dd8fd7SAlex Crichton if !bb_padding.is_empty() { 102449dd8fd7SAlex Crichton buffer.put_data(&bb_padding); 102549dd8fd7SAlex Crichton buffer.align_to(I::LabelUse::ALIGN); 1026475d1ba5SAlex Crichton total_bb_padding += bb_padding.len(); 1027475d1ba5SAlex Crichton if total_bb_padding > (150 << 20) { 1028475d1ba5SAlex Crichton bb_padding = Vec::new(); 1029475d1ba5SAlex Crichton } 103072e6be93SChris Fallin } 1031d8357426SChris Fallin } 1032d8357426SChris Fallin 1033d4a4d4f9SSingleAccretion // Do any optimizations on branches at tail of buffer, as if we had 1034d4a4d4f9SSingleAccretion // bound one last label. 1035d4a4d4f9SSingleAccretion buffer.optimize_branches(ctrl_plane); 1036d4a4d4f9SSingleAccretion 10377eb89140SRemo Senekowitsch // emission state is not needed anymore, move control plane back out 10387eb89140SRemo Senekowitsch *ctrl_plane = state.take_ctrl_plane(); 10397eb89140SRemo Senekowitsch 1040a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1041de4af90aSYury Delendik 104211a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 104311a2ef01SChris Fallin let mut bb_edges = vec![]; 1044a0318f36SChris Fallin let mut bb_offsets = vec![]; 104549dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 104611a2ef01SChris Fallin for block in 0..self.num_blocks() { 104711a2ef01SChris Fallin if bb_starts[block].is_none() { 104811a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 104911a2ef01SChris Fallin continue; 105011a2ef01SChris Fallin } 105111a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 105211a2ef01SChris Fallin 1053a0318f36SChris Fallin bb_offsets.push(from); 105411a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1055a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1056a0318f36SChris Fallin for &succ in succs.iter() { 1057a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 105811a2ef01SChris Fallin bb_edges.push((from, to)); 105911a2ef01SChris Fallin } 106011a2ef01SChris Fallin } 1061800cf25bSChris Fallin } 106211a2ef01SChris Fallin 1063d4a4d4f9SSingleAccretion self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len); 1064a0318f36SChris Fallin let value_labels_ranges = 1065a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1066a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1067a0318f36SChris Fallin 1068a0318f36SChris Fallin EmitResult { 106949dd8fd7SAlex Crichton buffer: buffer.finish(&self.constants, ctrl_plane), 1070a0318f36SChris Fallin bb_offsets, 1071a0318f36SChris Fallin bb_edges, 1072a0318f36SChris Fallin func_body_len, 1073a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10749c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10759c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1076a0318f36SChris Fallin value_labels_ranges, 1077a0318f36SChris Fallin frame_size, 1078a0318f36SChris Fallin } 1079d8357426SChris Fallin } 1080d8357426SChris Fallin 1081d4a4d4f9SSingleAccretion fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) { 1082d4a4d4f9SSingleAccretion if self.debug_value_labels.is_empty() { 1083d4a4d4f9SSingleAccretion return; 1084d4a4d4f9SSingleAccretion } 1085d4a4d4f9SSingleAccretion 1086d4a4d4f9SSingleAccretion // During emission, branch removal can make offsets of instructions incorrect. 1087d4a4d4f9SSingleAccretion // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj] 1088d4a4d4f9SSingleAccretion // It will be recorded as (say): [30] [34] [38] [42] [<would be 46>] 1089d4a4d4f9SSingleAccretion // When the jumps get removed we are left with (in "inst_offsets"): 1090d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1091d4a4d4f9SSingleAccretion // [30] [34] [38] [42] [34] 1092d4a4d4f9SSingleAccretion // Which violates the monotonicity invariant. This method sets offsets of these 1093d4a4d4f9SSingleAccretion // removed instructions such as to make them appear zero-sized: 1094d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1095d4a4d4f9SSingleAccretion // [30] [34] [34] [34] [34] 1096d4a4d4f9SSingleAccretion // 1097d4a4d4f9SSingleAccretion let mut next_offset = func_body_len; 1098d4a4d4f9SSingleAccretion for inst_index in (0..(inst_offsets.len() - 1)).rev() { 1099d4a4d4f9SSingleAccretion let inst_offset = inst_offsets[inst_index]; 1100d4a4d4f9SSingleAccretion 1101d4a4d4f9SSingleAccretion // Not all instructions get their offsets recorded. 1102d4a4d4f9SSingleAccretion if inst_offset == NO_INST_OFFSET { 1103d4a4d4f9SSingleAccretion continue; 1104d4a4d4f9SSingleAccretion } 1105d4a4d4f9SSingleAccretion 1106d4a4d4f9SSingleAccretion if inst_offset > next_offset { 1107d4a4d4f9SSingleAccretion trace!( 1108d4a4d4f9SSingleAccretion "Fixing code offset of the removed Inst {}: {} -> {}", 1109d4a4d4f9SSingleAccretion inst_index, 1110d4a4d4f9SSingleAccretion inst_offset, 1111d4a4d4f9SSingleAccretion next_offset 1112d4a4d4f9SSingleAccretion ); 1113d4a4d4f9SSingleAccretion inst_offsets[inst_index] = next_offset; 1114d4a4d4f9SSingleAccretion continue; 1115d4a4d4f9SSingleAccretion } 1116d4a4d4f9SSingleAccretion 1117d4a4d4f9SSingleAccretion next_offset = inst_offset; 1118d4a4d4f9SSingleAccretion } 1119d4a4d4f9SSingleAccretion } 1120d4a4d4f9SSingleAccretion 1121a0318f36SChris Fallin fn compute_value_labels_ranges( 1122a0318f36SChris Fallin &self, 1123a0318f36SChris Fallin regalloc: ®alloc2::Output, 1124a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1125a0318f36SChris Fallin func_body_len: u32, 1126a0318f36SChris Fallin ) -> ValueLabelsRanges { 1127a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1128602006ffSbjorn3 return ValueLabelsRanges::default(); 1129997fab55SChris Fallin } 1130997fab55SChris Fallin 1131a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1132a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1133a0318f36SChris Fallin let ranges = value_labels_ranges 1134a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1135a0318f36SChris Fallin .or_insert_with(|| vec![]); 1136a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1137a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1138a0318f36SChris Fallin func_body_len 1139a0318f36SChris Fallin } else { 1140a0318f36SChris Fallin inst_offsets[to.inst().index()] 1141a0318f36SChris Fallin }; 1142a0318f36SChris Fallin 1143d4a4d4f9SSingleAccretion // Empty ranges or unavailable offsets can happen 1144d4a4d4f9SSingleAccretion // due to cold blocks and branch removal (see above). 1145d4a4d4f9SSingleAccretion if from_offset == NO_INST_OFFSET 1146d4a4d4f9SSingleAccretion || to_offset == NO_INST_OFFSET 1147d4a4d4f9SSingleAccretion || from_offset == to_offset 1148d4a4d4f9SSingleAccretion { 1149a0318f36SChris Fallin continue; 115076d61504Sbjorn3 } 115176d61504Sbjorn3 1152a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1153a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1154a0318f36SChris Fallin } else { 11557b16eccdSSingleAccretion let slot = alloc.as_stack().unwrap(); 11567b16eccdSSingleAccretion let sp_offset = self.abi.get_spillslot_offset(slot); 11577b16eccdSSingleAccretion let sp_to_caller_sp_offset = self.abi.nominal_sp_to_caller_sp_offset(); 11587b16eccdSSingleAccretion let caller_sp_to_cfa_offset = 11597b16eccdSSingleAccretion crate::isa::unwind::systemv::caller_sp_to_cfa_offset(); 11607b16eccdSSingleAccretion let cfa_to_sp_offset = -((sp_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64); 11617b16eccdSSingleAccretion LabelValueLoc::CFAOffset(cfa_to_sp_offset + sp_offset) 1162a0318f36SChris Fallin }; 1163a0318f36SChris Fallin 1164a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1165a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1166a0318f36SChris Fallin // instruction; that is the same as the end of another 1167a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1168a0318f36SChris Fallin // we are past the previous instruction's end. 1169d4a4d4f9SSingleAccretion let start = from_offset + 1; 1170d4a4d4f9SSingleAccretion 1171a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1172a0318f36SChris Fallin // *include* the end of the last 1173a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1174a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1175a0318f36SChris Fallin // the first instruction not covered. That 1176a0318f36SChris Fallin // instruction's start is the same as the end of the 1177a0318f36SChris Fallin // last instruction that is included, so we go one 1178a0318f36SChris Fallin // byte further to be sure to include it. 1179d4a4d4f9SSingleAccretion let end = to_offset + 1; 1180d4a4d4f9SSingleAccretion 11817b16eccdSSingleAccretion // Coalesce adjacent ranges that for the same location 11827b16eccdSSingleAccretion // to minimize output size here and for the consumers. 11837b16eccdSSingleAccretion if let Some(last_loc_range) = ranges.last_mut() { 11847b16eccdSSingleAccretion if last_loc_range.loc == loc && last_loc_range.end == start { 11857b16eccdSSingleAccretion trace!( 11867b16eccdSSingleAccretion "Extending debug range for VL{} in {:?} to {}", 11877b16eccdSSingleAccretion label, 11887b16eccdSSingleAccretion loc, 11897b16eccdSSingleAccretion end 11907b16eccdSSingleAccretion ); 11917b16eccdSSingleAccretion last_loc_range.end = end; 11927b16eccdSSingleAccretion continue; 11937b16eccdSSingleAccretion } 11947b16eccdSSingleAccretion } 11957b16eccdSSingleAccretion 1196d4a4d4f9SSingleAccretion trace!( 1197d4a4d4f9SSingleAccretion "Recording debug range for VL{} in {:?}: [Inst {}..Inst {}) [{}..{})", 1198d4a4d4f9SSingleAccretion label, 1199d4a4d4f9SSingleAccretion loc, 1200d4a4d4f9SSingleAccretion from.inst().index(), 1201d4a4d4f9SSingleAccretion to.inst().index(), 1202d4a4d4f9SSingleAccretion start, 1203d4a4d4f9SSingleAccretion end 1204d4a4d4f9SSingleAccretion ); 1205d4a4d4f9SSingleAccretion 1206d4a4d4f9SSingleAccretion ranges.push(ValueLocRange { loc, start, end }); 1207a0318f36SChris Fallin } 1208a0318f36SChris Fallin 1209a0318f36SChris Fallin value_labels_ranges 1210c84d6be6SChris Fallin } 1211c84d6be6SChris Fallin 1212d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1213d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1214a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1215d8357426SChris Fallin } 12162154c63dSAlex Crichton 1217*6397f388SJamey Sharp fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 1218fef8a90fSChris Fallin Self::resolve_vreg_alias_impl(&self.vreg_aliases, from) 1219fef8a90fSChris Fallin } 1220fef8a90fSChris Fallin 1221fef8a90fSChris Fallin /// Implementation of alias resolution. Separate helper that does 1222fef8a90fSChris Fallin /// not borrow `self` in order to allow working around borrowing 1223fef8a90fSChris Fallin /// restrictions. 1224fef8a90fSChris Fallin fn resolve_vreg_alias_impl( 1225fef8a90fSChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 1226fef8a90fSChris Fallin from: regalloc2::VReg, 1227fef8a90fSChris Fallin ) -> regalloc2::VReg { 1228fef8a90fSChris Fallin // We prevent cycles from existing by resolving targets of 1229fef8a90fSChris Fallin // aliases eagerly before setting them. If the target resolves 1230fef8a90fSChris Fallin // to the origin of the alias, then a cycle would be created 1231fef8a90fSChris Fallin // and the alias is disallowed. Because of the structure of 1232fef8a90fSChris Fallin // SSA code (one instruction can refer to another's defs but 1233fef8a90fSChris Fallin // not vice-versa, except indirectly through 1234fef8a90fSChris Fallin // phis/blockparams), cycles should not occur as we use 1235fef8a90fSChris Fallin // aliases to redirect vregs to the temps that actually define 1236fef8a90fSChris Fallin // them. 1237fef8a90fSChris Fallin 1238fef8a90fSChris Fallin let mut vreg = from; 1239fef8a90fSChris Fallin while let Some(to) = aliases.get(&vreg) { 1240fef8a90fSChris Fallin vreg = *to; 1241fef8a90fSChris Fallin } 1242fef8a90fSChris Fallin vreg 1243fef8a90fSChris Fallin } 1244fef8a90fSChris Fallin 12452154c63dSAlex Crichton #[inline] 124670d2a26eSJamey Sharp fn debug_assert_no_vreg_aliases(&self, mut list: impl Iterator<Item = VReg>) { 124770d2a26eSJamey Sharp debug_assert!(list.all(|vreg| !self.vreg_aliases.contains_key(&vreg))); 12482154c63dSAlex Crichton } 1249f466aa26SChris Fallin 12509e4d4462SChris Fallin /// Get the type of a VReg. 12519e4d4462SChris Fallin pub fn vreg_type(&self, vreg: VReg) -> Type { 12529e4d4462SChris Fallin self.vreg_types[vreg.vreg()] 12539e4d4462SChris Fallin } 12549e4d4462SChris Fallin 1255f466aa26SChris Fallin /// Get the fact, if any, for a given VReg. 1256f466aa26SChris Fallin pub fn vreg_fact(&self, vreg: VReg) -> Option<&Fact> { 1257fef8a90fSChris Fallin let vreg = self.resolve_vreg_alias(vreg); 12589e4d4462SChris Fallin self.facts[vreg.vreg()].as_ref() 1259f466aa26SChris Fallin } 1260f466aa26SChris Fallin 12618d19280aSChris Fallin /// Set the fact for a given VReg. 12628d19280aSChris Fallin pub fn set_vreg_fact(&mut self, vreg: VReg, fact: Fact) { 12638d19280aSChris Fallin let vreg = self.resolve_vreg_alias(vreg); 1264f262c311SChris Fallin trace!("set fact on {}: {:?}", vreg, fact); 12658d19280aSChris Fallin self.facts[vreg.vreg()] = Some(fact); 12668d19280aSChris Fallin } 12678d19280aSChris Fallin 1268f466aa26SChris Fallin /// Does a given instruction define any facts? 1269f466aa26SChris Fallin pub fn inst_defines_facts(&self, inst: InsnIndex) -> bool { 1270f466aa26SChris Fallin self.inst_operands(inst) 1271f466aa26SChris Fallin .iter() 1272f466aa26SChris Fallin .filter(|o| o.kind() == OperandKind::Def) 1273f466aa26SChris Fallin .map(|o| o.vreg()) 12742e7f9414SChris Fallin .any(|vreg| self.facts[vreg.vreg()].is_some()) 1275f466aa26SChris Fallin } 1276f466aa26SChris Fallin } 1277f466aa26SChris Fallin 1278f466aa26SChris Fallin impl<I: VCodeInst> std::ops::Index<InsnIndex> for VCode<I> { 1279f466aa26SChris Fallin type Output = I; 1280f466aa26SChris Fallin fn index(&self, idx: InsnIndex) -> &Self::Output { 1281f466aa26SChris Fallin &self.insts[idx.index()] 1282f466aa26SChris Fallin } 1283d8357426SChris Fallin } 1284d8357426SChris Fallin 1285d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1286a0318f36SChris Fallin fn num_insts(&self) -> usize { 1287a0318f36SChris Fallin self.insts.len() 1288d8357426SChris Fallin } 1289d8357426SChris Fallin 1290a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1291a0318f36SChris Fallin self.block_ranges.len() 1292d8357426SChris Fallin } 1293d8357426SChris Fallin 1294a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1295a0318f36SChris Fallin self.entry 1296d8357426SChris Fallin } 1297d8357426SChris Fallin 1298a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1299a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1300a0318f36SChris Fallin InstRange::forward(start, end) 1301d8357426SChris Fallin } 1302d8357426SChris Fallin 1303a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1304a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1305a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1306d8357426SChris Fallin } 1307d8357426SChris Fallin 1308a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1309a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1310a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1311d8357426SChris Fallin } 1312d8357426SChris Fallin 1313a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1314c5379051STrevor Elliott // As a special case we don't return block params for the entry block, as all the arguments 1315c5379051STrevor Elliott // will be defined by the `Inst::Args` instruction. 1316c5379051STrevor Elliott if block == self.entry { 1317c5379051STrevor Elliott return &[]; 1318c5379051STrevor Elliott } 1319c5379051STrevor Elliott 1320a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 13212154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 13222154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 13232154c63dSAlex Crichton // double-check just to be sure. 132470d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 132570d2a26eSJamey Sharp ret 1326d8357426SChris Fallin } 1327d8357426SChris Fallin 1328a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1329a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1330a0318f36SChris Fallin let succ_ranges = 1331a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1332a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 13332154c63dSAlex Crichton let ret = &self.branch_block_args 13342154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 133570d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 133670d2a26eSJamey Sharp ret 1337d8357426SChris Fallin } 1338d8357426SChris Fallin 1339a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1340a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1341c5379051STrevor Elliott // We treat blocks terminated by an unconditional trap like a return for regalloc. 1342c5379051STrevor Elliott MachTerminator::None => self.insts[insn.index()].is_trap(), 13434154fa47SNick Fitzgerald MachTerminator::Ret | MachTerminator::RetCall => true, 13444154fa47SNick Fitzgerald MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false, 1345d8357426SChris Fallin } 1346d8357426SChris Fallin } 1347d8357426SChris Fallin 1348a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1349a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 13505774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1351a0318f36SChris Fallin _ => false, 1352a0318f36SChris Fallin } 135371768bb6SChris Fallin } 135471768bb6SChris Fallin 1355a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1356a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1357d8357426SChris Fallin } 1358d8357426SChris Fallin 1359a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1360a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 13612154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 136270d2a26eSJamey Sharp // It should be true by construction that `Operand`s do not contain any 136370d2a26eSJamey Sharp // aliased vregs since they're all collected and mapped when the VCode 136470d2a26eSJamey Sharp // is itself constructed. 136570d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|op| op.vreg())); 13662154c63dSAlex Crichton ret 1367d8357426SChris Fallin } 1368d8357426SChris Fallin 1369b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1370b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1371be6f060aSChris Fallin } 1372be6f060aSChris Fallin 1373a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1374a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1375d8357426SChris Fallin } 1376d8357426SChris Fallin 1377a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 137870d2a26eSJamey Sharp let ret = &self.reftyped_vregs; 137970d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 138070d2a26eSJamey Sharp ret 1381d8357426SChris Fallin } 1382d8357426SChris Fallin 1383a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 13842154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 138570d2a26eSJamey Sharp // generated and aliases are fully defined, so double-check that 13862154c63dSAlex Crichton // aliases are not lingering. 138770d2a26eSJamey Sharp let ret = &self.debug_value_labels; 138870d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|&(vreg, ..)| vreg)); 138970d2a26eSJamey Sharp ret 1390d8357426SChris Fallin } 1391d8357426SChris Fallin 1392a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1393a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1394d8357426SChris Fallin } 1395d8357426SChris Fallin 1396a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1397a0318f36SChris Fallin // At least the s390x backend requires this, because the 1398a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1399a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1400a0318f36SChris Fallin true 1401d8357426SChris Fallin } 1402d8357426SChris Fallin } 1403d8357426SChris Fallin 1404d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1405d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1406a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1407a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1408a0318f36SChris Fallin 1409a0318f36SChris Fallin let mut state = Default::default(); 1410a0318f36SChris Fallin 1411a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1412a0318f36SChris Fallin alias_keys.sort_unstable(); 1413a0318f36SChris Fallin for key in alias_keys { 1414a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1415a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1416a0318f36SChris Fallin } 1417d8357426SChris Fallin 1418d8357426SChris Fallin for block in 0..self.num_blocks() { 1419a0318f36SChris Fallin let block = BlockIndex::new(block); 1420a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1421a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1422a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1423d8357426SChris Fallin } 1424a0318f36SChris Fallin for succ in self.succs(block) { 1425a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1426a0318f36SChris Fallin } 1427a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1428a0318f36SChris Fallin writeln!( 1429a0318f36SChris Fallin f, 1430a0318f36SChris Fallin " (instruction range: {} .. {})", 1431a0318f36SChris Fallin start.index(), 1432a0318f36SChris Fallin end.index() 1433a0318f36SChris Fallin )?; 1434a0318f36SChris Fallin for inst in start.index()..end.index() { 1435a0318f36SChris Fallin writeln!( 1436a0318f36SChris Fallin f, 1437a0318f36SChris Fallin " Inst {}: {}", 1438a0318f36SChris Fallin inst, 1439a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1440a0318f36SChris Fallin )?; 1441f466aa26SChris Fallin for operand in self.inst_operands(InsnIndex::new(inst)) { 1442f466aa26SChris Fallin if operand.kind() == OperandKind::Def { 1443f466aa26SChris Fallin if let Some(fact) = &self.facts[operand.vreg().vreg()] { 1444fef8a90fSChris Fallin writeln!(f, " v{} ! {}", operand.vreg().vreg(), fact)?; 1445f466aa26SChris Fallin } 1446f466aa26SChris Fallin } 1447f466aa26SChris Fallin } 1448d8357426SChris Fallin } 1449d8357426SChris Fallin } 1450d8357426SChris Fallin 1451d8357426SChris Fallin writeln!(f, "}}")?; 1452d8357426SChris Fallin Ok(()) 1453d8357426SChris Fallin } 1454d8357426SChris Fallin } 1455d8357426SChris Fallin 1456d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder. 1457d94173eaSTrevor Elliott pub struct VRegAllocator<I> { 1458d94173eaSTrevor Elliott /// Next virtual register number to allocate. 1459d94173eaSTrevor Elliott next_vreg: usize, 1460d94173eaSTrevor Elliott 1461d94173eaSTrevor Elliott /// VReg IR-level types. 1462d94173eaSTrevor Elliott vreg_types: Vec<Type>, 1463d94173eaSTrevor Elliott 1464d94173eaSTrevor Elliott /// A set with the same contents as `reftyped_vregs`, in order to 1465d94173eaSTrevor Elliott /// avoid inserting more than once. 1466d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet<VReg>, 1467d94173eaSTrevor Elliott 1468d94173eaSTrevor Elliott /// Reference-typed `regalloc2::VReg`s. The regalloc requires 1469d94173eaSTrevor Elliott /// these in a dense slice (as opposed to querying the 1470d94173eaSTrevor Elliott /// reftype-status of each vreg) for efficient iteration. 1471d94173eaSTrevor Elliott reftyped_vregs: Vec<VReg>, 1472d94173eaSTrevor Elliott 147317eeba0eSChris Fallin /// A deferred error, to be bubbled up to the top level of the 147417eeba0eSChris Fallin /// lowering algorithm. We take this approach because we cannot 147517eeba0eSChris Fallin /// currently propagate a `Result` upward through ISLE code (the 147617eeba0eSChris Fallin /// lowering rules) or some ABI code. 147717eeba0eSChris Fallin deferred_error: Option<CodegenError>, 147817eeba0eSChris Fallin 1479f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code. 1480f466aa26SChris Fallin facts: Vec<Option<Fact>>, 1481f466aa26SChris Fallin 1482d94173eaSTrevor Elliott /// The type of instruction that this allocator makes registers for. 1483d94173eaSTrevor Elliott _inst: core::marker::PhantomData<I>, 1484d94173eaSTrevor Elliott } 1485d94173eaSTrevor Elliott 1486d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> { 1487d94173eaSTrevor Elliott /// Make a new VRegAllocator. 1488d94173eaSTrevor Elliott pub fn new() -> Self { 1489d94173eaSTrevor Elliott Self { 1490d94173eaSTrevor Elliott next_vreg: first_user_vreg_index(), 1491d94173eaSTrevor Elliott vreg_types: vec![], 1492f466aa26SChris Fallin facts: vec![], 1493d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet::default(), 1494d94173eaSTrevor Elliott reftyped_vregs: vec![], 149517eeba0eSChris Fallin deferred_error: None, 1496d94173eaSTrevor Elliott _inst: core::marker::PhantomData::default(), 1497d94173eaSTrevor Elliott } 1498d94173eaSTrevor Elliott } 1499d94173eaSTrevor Elliott 1500d94173eaSTrevor Elliott /// Allocate a fresh ValueRegs. 1501d94173eaSTrevor Elliott pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> { 150217eeba0eSChris Fallin if self.deferred_error.is_some() { 150317eeba0eSChris Fallin return Err(CodegenError::CodeTooLarge); 150417eeba0eSChris Fallin } 1505d94173eaSTrevor Elliott let v = self.next_vreg; 1506d94173eaSTrevor Elliott let (regclasses, tys) = I::rc_for_type(ty)?; 1507d94173eaSTrevor Elliott self.next_vreg += regclasses.len(); 1508d94173eaSTrevor Elliott if self.next_vreg >= VReg::MAX { 1509d94173eaSTrevor Elliott return Err(CodegenError::CodeTooLarge); 1510d94173eaSTrevor Elliott } 1511d94173eaSTrevor Elliott 1512d94173eaSTrevor Elliott let regs: ValueRegs<Reg> = match regclasses { 1513d94173eaSTrevor Elliott &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), 1514d94173eaSTrevor Elliott &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), 1515d94173eaSTrevor Elliott // We can extend this if/when we support 32-bit targets; e.g., 1516d94173eaSTrevor Elliott // an i128 on a 32-bit machine will need up to four machine regs 1517d94173eaSTrevor Elliott // for a `Value`. 1518d94173eaSTrevor Elliott _ => panic!("Value must reside in 1 or 2 registers"), 1519d94173eaSTrevor Elliott }; 1520d94173eaSTrevor Elliott for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { 1521d94173eaSTrevor Elliott self.set_vreg_type(reg.to_virtual_reg().unwrap(), reg_ty); 1522d94173eaSTrevor Elliott } 1523f466aa26SChris Fallin 1524f466aa26SChris Fallin // Create empty facts for each allocated vreg. 1525f466aa26SChris Fallin self.facts 1526f466aa26SChris Fallin .resize(usize::try_from(self.next_vreg).unwrap(), None); 1527f466aa26SChris Fallin 1528d94173eaSTrevor Elliott Ok(regs) 1529d94173eaSTrevor Elliott } 1530d94173eaSTrevor Elliott 153117eeba0eSChris Fallin /// Allocate a fresh ValueRegs, deferring any out-of-vregs 153217eeba0eSChris Fallin /// errors. This is useful in places where we cannot bubble a 153317eeba0eSChris Fallin /// `CodegenResult` upward easily, and which are known to be 153417eeba0eSChris Fallin /// invoked from within the lowering loop that checks the deferred 153517eeba0eSChris Fallin /// error status below. 153617eeba0eSChris Fallin pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg> { 153717eeba0eSChris Fallin match self.alloc(ty) { 153817eeba0eSChris Fallin Ok(x) => x, 153917eeba0eSChris Fallin Err(e) => { 154017eeba0eSChris Fallin self.deferred_error = Some(e); 154117eeba0eSChris Fallin self.bogus_for_deferred_error(ty) 154217eeba0eSChris Fallin } 154317eeba0eSChris Fallin } 154417eeba0eSChris Fallin } 154517eeba0eSChris Fallin 154617eeba0eSChris Fallin /// Take any deferred error that was accumulated by `alloc_with_deferred_error`. 154717eeba0eSChris Fallin pub fn take_deferred_error(&mut self) -> Option<CodegenError> { 154817eeba0eSChris Fallin self.deferred_error.take() 154917eeba0eSChris Fallin } 155017eeba0eSChris Fallin 155117eeba0eSChris Fallin /// Produce an bogus VReg placeholder with the proper number of 155217eeba0eSChris Fallin /// registers for the given type. This is meant to be used with 155317eeba0eSChris Fallin /// deferred allocation errors (see `Lower::alloc_tmp()`). 155417eeba0eSChris Fallin fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg> { 155517eeba0eSChris Fallin let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type"); 155617eeba0eSChris Fallin match regclasses { 155717eeba0eSChris Fallin &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()), 155817eeba0eSChris Fallin &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()), 155917eeba0eSChris Fallin _ => panic!("Value must reside in 1 or 2 registers"), 156017eeba0eSChris Fallin } 156117eeba0eSChris Fallin } 156217eeba0eSChris Fallin 1563d94173eaSTrevor Elliott /// Set the type of this virtual register. 1564d94173eaSTrevor Elliott pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 1565d94173eaSTrevor Elliott if self.vreg_types.len() <= vreg.index() { 156670bca801STrevor Elliott self.vreg_types.resize(vreg.index() + 1, ir::types::INVALID); 1567d94173eaSTrevor Elliott } 1568d94173eaSTrevor Elliott self.vreg_types[vreg.index()] = ty; 1569d94173eaSTrevor Elliott if is_reftype(ty) { 1570d94173eaSTrevor Elliott let vreg: VReg = vreg.into(); 1571d94173eaSTrevor Elliott if self.reftyped_vregs_set.insert(vreg) { 1572d94173eaSTrevor Elliott self.reftyped_vregs.push(vreg); 1573d94173eaSTrevor Elliott } 1574d94173eaSTrevor Elliott } 1575d94173eaSTrevor Elliott } 1576f466aa26SChris Fallin 1577f466aa26SChris Fallin /// Set the proof-carrying code fact on a given virtual register. 1578f466aa26SChris Fallin /// 1579f466aa26SChris Fallin /// Returns the old fact, if any (only one fact can be stored). 1580f466aa26SChris Fallin pub fn set_fact(&mut self, vreg: VirtualReg, fact: Fact) -> Option<Fact> { 1581fef8a90fSChris Fallin trace!("vreg {:?} has fact: {:?}", vreg, fact); 1582f466aa26SChris Fallin self.facts[vreg.index()].replace(fact) 1583f466aa26SChris Fallin } 1584f466aa26SChris Fallin 1585fef8a90fSChris Fallin /// Take (and remove) a fact about a VReg. Used when setting up 1586fef8a90fSChris Fallin /// aliases: we want to move a fact from the alias vreg to the 1587fef8a90fSChris Fallin /// aliased vreg, to preserve facts about a value that were stated 1588fef8a90fSChris Fallin /// before we lowered its producer. 1589fef8a90fSChris Fallin pub fn take_fact(&mut self, vreg: VirtualReg) -> Option<Fact> { 1590fef8a90fSChris Fallin self.facts[vreg.index()].take() 1591fef8a90fSChris Fallin } 1592fef8a90fSChris Fallin 1593f262c311SChris Fallin /// Set a fact only if one doesn't already exist. 1594f262c311SChris Fallin pub fn set_fact_if_missing(&mut self, vreg: VirtualReg, fact: Fact) { 1595f262c311SChris Fallin if self.facts[vreg.index()].is_none() { 1596f262c311SChris Fallin self.set_fact(vreg, fact); 1597f262c311SChris Fallin } 1598f262c311SChris Fallin } 1599f262c311SChris Fallin 1600f466aa26SChris Fallin /// Allocate a fresh ValueRegs, with a given fact to apply if 1601f466aa26SChris Fallin /// the value fits in one VReg. 1602f466aa26SChris Fallin pub fn alloc_with_maybe_fact( 1603f466aa26SChris Fallin &mut self, 1604f466aa26SChris Fallin ty: Type, 1605f466aa26SChris Fallin fact: Option<Fact>, 1606f466aa26SChris Fallin ) -> CodegenResult<ValueRegs<Reg>> { 1607f466aa26SChris Fallin let result = self.alloc(ty)?; 1608f466aa26SChris Fallin 1609f466aa26SChris Fallin // Ensure that we don't lose a fact on a value that splits 1610f466aa26SChris Fallin // into multiple VRegs. 1611f466aa26SChris Fallin assert!(result.len() == 1 || fact.is_none()); 1612f466aa26SChris Fallin if let Some(fact) = fact { 1613f466aa26SChris Fallin self.set_fact(result.regs()[0].to_virtual_reg().unwrap(), fact); 1614f466aa26SChris Fallin } 1615f466aa26SChris Fallin 1616f466aa26SChris Fallin Ok(result) 1617f466aa26SChris Fallin } 1618d94173eaSTrevor Elliott } 1619d94173eaSTrevor Elliott 162083f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 162183f182b3SAndrew Brown /// [MachBuffer]. 162283f182b3SAndrew Brown /// 162383f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 1624d38d387aSAlex Crichton /// [VCodeConstants.insert]; an intermediate handle, `VCodeConstant`, tracks what constants are 162583f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 162683f182b3SAndrew Brown /// values are inserted. 162783f182b3SAndrew Brown /// 162883f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 162983f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 163083f182b3SAndrew Brown /// then writes the constant values to the buffer. 163183f182b3SAndrew Brown #[derive(Default)] 163283f182b3SAndrew Brown pub struct VCodeConstants { 163383f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 163483f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 163583f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1636eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 163783f182b3SAndrew Brown } 163883f182b3SAndrew Brown impl VCodeConstants { 163983f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 164083f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 164183f182b3SAndrew Brown Self { 164283f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 164383f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 164483f182b3SAndrew Brown well_known_uses: HashMap::new(), 1645eb435f30SChris Fallin u64s: HashMap::new(), 164683f182b3SAndrew Brown } 164783f182b3SAndrew Brown } 164883f182b3SAndrew Brown 164983f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 165083f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 165183f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 165283f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 165383f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 165483f182b3SAndrew Brown match data { 165583f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 165683f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 165783f182b3SAndrew Brown None => { 165883f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 165983f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 166083f182b3SAndrew Brown vcode_constant 166183f182b3SAndrew Brown } 166283f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 166383f182b3SAndrew Brown }, 166483f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1665eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1666eb435f30SChris Fallin Entry::Vacant(v) => { 166783f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1668eb435f30SChris Fallin v.insert(vcode_constant); 166983f182b3SAndrew Brown vcode_constant 167083f182b3SAndrew Brown } 1671eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 167283f182b3SAndrew Brown } 167383f182b3SAndrew Brown } 1674eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1675eb435f30SChris Fallin Entry::Vacant(v) => { 1676eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1677eb435f30SChris Fallin v.insert(vcode_constant); 1678eb435f30SChris Fallin vcode_constant 1679eb435f30SChris Fallin } 1680eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1681eb435f30SChris Fallin }, 168283f182b3SAndrew Brown } 168383f182b3SAndrew Brown } 168483f182b3SAndrew Brown 168583f182b3SAndrew Brown /// Return the number of constants inserted. 168683f182b3SAndrew Brown pub fn len(&self) -> usize { 168783f182b3SAndrew Brown self.constants.len() 168883f182b3SAndrew Brown } 168983f182b3SAndrew Brown 1690d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys inserted in this structure. 169183f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 169283f182b3SAndrew Brown self.constants.keys() 169383f182b3SAndrew Brown } 169483f182b3SAndrew Brown 1695d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys and the data (as a byte slice) inserted in this 169683f182b3SAndrew Brown /// structure. 169783f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 169883f182b3SAndrew Brown self.constants.iter() 169983f182b3SAndrew Brown } 170049dd8fd7SAlex Crichton 170149dd8fd7SAlex Crichton /// Returns the data associated with the specified constant. 170249dd8fd7SAlex Crichton pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData { 170349dd8fd7SAlex Crichton &self.constants[c] 170449dd8fd7SAlex Crichton } 170597f6a8b3SSaúl Cabrera 170697f6a8b3SSaúl Cabrera /// Checks if the given [VCodeConstantData] is registered as 170797f6a8b3SSaúl Cabrera /// used by the pool. 170897f6a8b3SSaúl Cabrera pub fn pool_uses(&self, constant: &VCodeConstantData) -> bool { 170997f6a8b3SSaúl Cabrera match constant { 171097f6a8b3SSaúl Cabrera VCodeConstantData::Pool(c, _) => self.pool_uses.contains_key(c), 171197f6a8b3SSaúl Cabrera _ => false, 171297f6a8b3SSaúl Cabrera } 171397f6a8b3SSaúl Cabrera } 171483f182b3SAndrew Brown } 171583f182b3SAndrew Brown 171683f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 171783f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 171883f182b3SAndrew Brown pub struct VCodeConstant(u32); 171983f182b3SAndrew Brown entity_impl!(VCodeConstant); 172083f182b3SAndrew Brown 172183f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 172283f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 172383f182b3SAndrew Brown pub enum VCodeConstantData { 172483f182b3SAndrew Brown /// A constant already present in the Cranelift IR 172583f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 172683f182b3SAndrew Brown Pool(Constant, ConstantData), 172783f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 172883f182b3SAndrew Brown WellKnown(&'static [u8]), 172983f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 173083f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 173183f182b3SAndrew Brown Generated(ConstantData), 1732eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1733eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1734eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1735eb435f30SChris Fallin U64([u8; 8]), 173683f182b3SAndrew Brown } 173783f182b3SAndrew Brown impl VCodeConstantData { 173883f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 173983f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 174083f182b3SAndrew Brown match self { 174183f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 174283f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1743eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 174483f182b3SAndrew Brown } 174583f182b3SAndrew Brown } 174683f182b3SAndrew Brown 174783f182b3SAndrew Brown /// Calculate the alignment of the constant data. 174883f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 174983f182b3SAndrew Brown if self.as_slice().len() <= 8 { 175083f182b3SAndrew Brown 8 175183f182b3SAndrew Brown } else { 175283f182b3SAndrew Brown 16 175383f182b3SAndrew Brown } 175483f182b3SAndrew Brown } 175583f182b3SAndrew Brown } 175683f182b3SAndrew Brown 175783f182b3SAndrew Brown #[cfg(test)] 175883f182b3SAndrew Brown mod test { 175983f182b3SAndrew Brown use super::*; 17605e5e5206SChris Fallin use std::mem::size_of; 176183f182b3SAndrew Brown 176283f182b3SAndrew Brown #[test] 176383f182b3SAndrew Brown fn size_of_constant_structs() { 176483f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 176583f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 176683f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 176783f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 176883f182b3SAndrew Brown assert_eq!( 176983f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 177083f182b3SAndrew Brown 24 177183f182b3SAndrew Brown ); 17725e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 17735e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 17745e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 177583f182b3SAndrew Brown } 177683f182b3SAndrew Brown } 1777