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 294f18a1f14SNick Fitzgerald pub fn init_abi(&mut self, temps: Vec<Writable<Reg>>) { 295f18a1f14SNick Fitzgerald self.vcode.abi.init(&self.vcode.sigs, temps); 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>> { 661a0318f36SChris Fallin // Compute clobbered registers. 662a0318f36SChris Fallin let mut clobbered = vec![]; 663a0318f36SChris Fallin let mut clobbered_set = FxHashSet::default(); 664d8357426SChris Fallin 665a0318f36SChris Fallin // All moves are included in clobbers. 666a0318f36SChris Fallin for edit in ®alloc.edits { 667a0318f36SChris Fallin let Edit::Move { to, .. } = edit.1; 668a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 669a0318f36SChris Fallin let reg = RealReg::from(preg); 670a0318f36SChris Fallin if clobbered_set.insert(reg) { 671a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 672a0318f36SChris Fallin } 673a0318f36SChris Fallin } 674d8357426SChris Fallin } 675d8357426SChris Fallin 676a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 677a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 678a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 679a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 680a0318f36SChris Fallin // the current function from clobbers, because by 681a0318f36SChris Fallin // definition everything clobbered by the call can be 682a0318f36SChris Fallin // clobbered by this function without saving as well.) 683a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 684d8357426SChris Fallin continue; 685d8357426SChris Fallin } 686d8357426SChris Fallin 687a0318f36SChris Fallin let start = *start as usize; 688a0318f36SChris Fallin let end = *end as usize; 689a0318f36SChris Fallin let operands = &self.operands[start..end]; 690a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 691a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 692a0318f36SChris Fallin // We're interested only in writes (Mods or Defs). 693a0318f36SChris Fallin if operand.kind() == OperandKind::Use { 694a0318f36SChris Fallin continue; 695d8357426SChris Fallin } 696a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 697a0318f36SChris Fallin let reg = RealReg::from(preg); 698a0318f36SChris Fallin if clobbered_set.insert(reg) { 699a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 700a0318f36SChris Fallin } 70108353fccSChris Fallin } 702d8357426SChris Fallin } 703d8357426SChris Fallin 704a0318f36SChris Fallin // Also add explicitly-clobbered registers. 705b2e28b91SChris Fallin for preg in self 706b2e28b91SChris Fallin .clobbers 707b2e28b91SChris Fallin .get(&InsnIndex::new(i)) 708b2e28b91SChris Fallin .cloned() 709b2e28b91SChris Fallin .unwrap_or_default() 710b2e28b91SChris Fallin { 711a0318f36SChris Fallin let reg = RealReg::from(preg); 712a0318f36SChris Fallin if clobbered_set.insert(reg) { 713a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 714a0318f36SChris Fallin } 715a0318f36SChris Fallin } 716a0318f36SChris Fallin } 717d8357426SChris Fallin 718a0318f36SChris Fallin clobbered 719d8357426SChris Fallin } 720d8357426SChris Fallin 721a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 722a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 723a0318f36SChris Fallin /// the regalloc results as well. 724a0318f36SChris Fallin /// 725a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 726a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 727a0318f36SChris Fallin /// is consumed by the emission process. 72811a2ef01SChris Fallin pub fn emit( 729a0318f36SChris Fallin mut self, 730a0318f36SChris Fallin regalloc: ®alloc2::Output, 731a0318f36SChris Fallin want_disasm: bool, 73249dd8fd7SAlex Crichton flags: &settings::Flags, 7337eb89140SRemo Senekowitsch ctrl_plane: &mut ControlPlane, 73449dd8fd7SAlex Crichton ) -> EmitResult 735d8357426SChris Fallin where 736f18a1f14SNick Fitzgerald I: VCodeInst, 737d8357426SChris Fallin { 738a0318f36SChris Fallin // To write into disasm string. 739a0318f36SChris Fallin use core::fmt::Write; 740a0318f36SChris Fallin 7412b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 74272e6be93SChris Fallin let mut buffer = MachBuffer::new(); 74311a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 744d8357426SChris Fallin 74549dd8fd7SAlex Crichton // The first M MachLabels are reserved for block indices. 746a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 74749dd8fd7SAlex Crichton 74849dd8fd7SAlex Crichton // Register all allocated constants with the `MachBuffer` to ensure that 74949dd8fd7SAlex Crichton // any references to the constants during instructions can be handled 75049dd8fd7SAlex Crichton // correctly. 75149dd8fd7SAlex Crichton buffer.register_constants(&self.constants); 752d8357426SChris Fallin 753ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 754ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 755ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 756ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 757a0318f36SChris Fallin let block = BlockIndex::new(block); 758ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 759ef1b2d2fSChris Fallin cold_blocks.push(block); 760ef1b2d2fSChris Fallin } else { 761ef1b2d2fSChris Fallin final_order.push(block); 762ef1b2d2fSChris Fallin } 763ef1b2d2fSChris Fallin } 764d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 765ef1b2d2fSChris Fallin 766a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 767a0318f36SChris Fallin // number of spillslots. 768a0318f36SChris Fallin // 769a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 770a0318f36SChris Fallin // generate the prologue and set other info, but we can't 771a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 772a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 773a0318f36SChris Fallin // relatively cheap. 774a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 7755d4e319cSJamey Sharp self.abi 7765d4e319cSJamey Sharp .compute_frame_layout(&self.sigs, regalloc.num_spillslots, clobbers); 777a0318f36SChris Fallin 778ef1b2d2fSChris Fallin // Emit blocks. 779964c6087SChris Fallin let mut cur_srcloc = None; 78011a2ef01SChris Fallin let mut last_offset = None; 781a0318f36SChris Fallin let mut inst_offsets = vec![]; 7827eb89140SRemo Senekowitsch let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane)); 783a0318f36SChris Fallin 784a0318f36SChris Fallin let mut disasm = String::new(); 785a0318f36SChris Fallin 786a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 787d4a4d4f9SSingleAccretion inst_offsets.resize(self.insts.len(), NO_INST_OFFSET); 788a0318f36SChris Fallin } 789a0318f36SChris Fallin 790863659e0SChris Fallin // Count edits per block ahead of time; this is needed for 791863659e0SChris Fallin // lookahead island emission. (We could derive it per-block 792863659e0SChris Fallin // with binary search in the edit list, but it's more 793863659e0SChris Fallin // efficient to do it in one pass here.) 794863659e0SChris Fallin let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; 795863659e0SChris Fallin let mut edit_idx = 0; 796863659e0SChris Fallin for block in 0..self.num_blocks() { 797863659e0SChris Fallin let end_inst = self.block_ranges[block].1; 798863659e0SChris Fallin let start_edit_idx = edit_idx; 799863659e0SChris Fallin while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { 800863659e0SChris Fallin edit_idx += 1; 801863659e0SChris Fallin } 802863659e0SChris Fallin let end_edit_idx = edit_idx; 803863659e0SChris Fallin ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); 804863659e0SChris Fallin } 805863659e0SChris Fallin 806d8b29089SAnton Kirilov let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); 807475d1ba5SAlex Crichton let mut bb_padding = match flags.bb_padding_log2_minus_one() { 80849dd8fd7SAlex Crichton 0 => Vec::new(), 80949dd8fd7SAlex Crichton n => vec![0; 1 << (n - 1)], 81049dd8fd7SAlex Crichton }; 811475d1ba5SAlex Crichton let mut total_bb_padding = 0; 812d8b29089SAnton Kirilov 813863659e0SChris Fallin for (block_order_idx, &block) in final_order.iter().enumerate() { 8148d022434SBenjamin Bouvier trace!("emitting block {:?}", block); 81560e4a004SAfonso Bordado 81660e4a004SAfonso Bordado // Call the new block hook for state 81760e4a004SAfonso Bordado state.on_new_block(); 81860e4a004SAfonso Bordado 81960e4a004SAfonso Bordado // Emit NOPs to align the block. 82072e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 82172e6be93SChris Fallin while new_offset > buffer.cur_offset() { 822d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 82372e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 824a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 825d8357426SChris Fallin } 82672e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 827d8357426SChris Fallin 828a0318f36SChris Fallin let do_emit = |inst: &I, 829a0318f36SChris Fallin allocs: &[Allocation], 830a0318f36SChris Fallin disasm: &mut String, 831a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 832a0318f36SChris Fallin state: &mut I::State| { 8332986f6b0SChris Fallin if want_disasm && !inst.is_args() { 834a0318f36SChris Fallin let mut s = state.clone(); 835a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 836a0318f36SChris Fallin } 837a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 838a0318f36SChris Fallin }; 839a0318f36SChris Fallin 840a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 841a0318f36SChris Fallin if block == self.entry { 8428d022434SBenjamin Bouvier trace!(" -> entry block"); 8438a9b1a90SBenjamin Bouvier buffer.start_srcloc(Default::default()); 84486652959SUlrich Weigand for inst in &self.abi.gen_prologue() { 845a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 846a0318f36SChris Fallin } 847a0318f36SChris Fallin buffer.end_srcloc(); 848d9d64694SChris Fallin } 849d9d64694SChris Fallin 850a0318f36SChris Fallin // Now emit the regular block body. 85111a2ef01SChris Fallin 8527eb89140SRemo Senekowitsch buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut()); 853a0318f36SChris Fallin 854a0318f36SChris Fallin if want_disasm { 855a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 856a0318f36SChris Fallin } 857a0318f36SChris Fallin 85849dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 85911a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 86011a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 86111a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 86211a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 86311a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 86411a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 86511a2ef01SChris Fallin break; 86611a2ef01SChris Fallin } 86711a2ef01SChris Fallin bb_starts[i] = None; 86811a2ef01SChris Fallin } 86911a2ef01SChris Fallin } 87011a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 87111a2ef01SChris Fallin last_offset = Some(cur_offset); 872800cf25bSChris Fallin } 87311a2ef01SChris Fallin 874d8b29089SAnton Kirilov if let Some(block_start) = I::gen_block_start( 875d8b29089SAnton Kirilov self.block_order.is_indirect_branch_target(block), 876d8b29089SAnton Kirilov is_forward_edge_cfi_enabled, 877d8b29089SAnton Kirilov ) { 878d8b29089SAnton Kirilov do_emit(&block_start, &[], &mut disasm, &mut buffer, &mut state); 879d8b29089SAnton Kirilov } 880d8b29089SAnton Kirilov 881a0318f36SChris Fallin for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { 882a0318f36SChris Fallin match inst_or_edit { 883a0318f36SChris Fallin InstOrEdit::Inst(iix) => { 884a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 885a0318f36SChris Fallin // If we need to produce debug info, 886a0318f36SChris Fallin // record the offset of each instruction 887a0318f36SChris Fallin // so that we can translate value-label 888a0318f36SChris Fallin // ranges to machine-code offsets. 889a0318f36SChris Fallin 890a0318f36SChris Fallin // Cold blocks violate monotonicity 891a0318f36SChris Fallin // assumptions elsewhere (that 892a0318f36SChris Fallin // instructions in inst-index order are in 893a0318f36SChris Fallin // order in machine code), so we omit 894a0318f36SChris Fallin // their offsets here. Value-label range 895a0318f36SChris Fallin // generation below will skip empty ranges 896a0318f36SChris Fallin // and ranges with to-offsets of zero. 897a0318f36SChris Fallin if !self.block_order.is_cold(block) { 898a0318f36SChris Fallin inst_offsets[iix.index()] = buffer.cur_offset(); 899a0318f36SChris Fallin } 900a0318f36SChris Fallin } 901a0318f36SChris Fallin 902a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 903a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 904964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 905964c6087SChris Fallin if cur_srcloc.is_some() { 90672e6be93SChris Fallin buffer.end_srcloc(); 907b691770fSChris Fallin } 90872e6be93SChris Fallin buffer.start_srcloc(srcloc); 909964c6087SChris Fallin cur_srcloc = Some(srcloc); 910b691770fSChris Fallin } 911b691770fSChris Fallin 912a0318f36SChris Fallin // If this is a safepoint, compute a stack map 913a0318f36SChris Fallin // and pass it to the emit state. 914a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 915a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 916a0318f36SChris Fallin // Find the contiguous range of 917a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 918a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 919a0318f36SChris Fallin // for this instruction index. 920a0318f36SChris Fallin let safepoint_slots_start = regalloc 921a0318f36SChris Fallin .safepoint_slots 922a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 923a0318f36SChris Fallin if progpoint.inst() >= iix { 924a0318f36SChris Fallin std::cmp::Ordering::Greater 925a0318f36SChris Fallin } else { 926a0318f36SChris Fallin std::cmp::Ordering::Less 927a0318f36SChris Fallin } 928a0318f36SChris Fallin }) 929a0318f36SChris Fallin .unwrap_err(); 930a0318f36SChris Fallin 931a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 932a0318f36SChris Fallin .iter() 933a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 934a0318f36SChris Fallin { 935a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 936a0318f36SChris Fallin safepoint_slots.push(slot); 937a0318f36SChris Fallin } 938a0318f36SChris Fallin if !safepoint_slots.is_empty() { 939666c2554SChris Fallin let stack_map = self 940666c2554SChris Fallin .abi 941a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 94205bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 94308353fccSChris Fallin } 944a0318f36SChris Fallin } 94508353fccSChris Fallin 946a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 947a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 948de4af90aSYury Delendik 949a0318f36SChris Fallin // If the instruction we are about to emit is 950a0318f36SChris Fallin // a return, place an epilogue at this point 951a0318f36SChris Fallin // (and don't emit the return; the actual 952a0318f36SChris Fallin // epilogue will contain it). 953a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 95486652959SUlrich Weigand for inst in self.abi.gen_epilogue() { 955a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 956a0318f36SChris Fallin } 957c84d6be6SChris Fallin } else { 958a0318f36SChris Fallin // Emit the instruction! 959a0318f36SChris Fallin do_emit( 960a0318f36SChris Fallin &self.insts[iix.index()], 961a0318f36SChris Fallin allocs, 962a0318f36SChris Fallin &mut disasm, 963a0318f36SChris Fallin &mut buffer, 964a0318f36SChris Fallin &mut state, 965a0318f36SChris Fallin ); 966c84d6be6SChris Fallin } 967c84d6be6SChris Fallin } 968a0318f36SChris Fallin 969a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 970a0318f36SChris Fallin // Create a move/spill/reload instruction and 971a0318f36SChris Fallin // immediately emit it. 972a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 973a0318f36SChris Fallin (Some(from), Some(to)) => { 974a0318f36SChris Fallin // Reg-to-reg move. 975a0318f36SChris Fallin let from_rreg = Reg::from(from); 976a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 977a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 978a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 979a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 980a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 981a0318f36SChris Fallin } 982a0318f36SChris Fallin (Some(from), None) => { 983a0318f36SChris Fallin // Spill from register to spillslot. 984a0318f36SChris Fallin let to = to.as_stack().unwrap(); 985a0318f36SChris Fallin let from_rreg = RealReg::from(from); 986a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 987a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 988a0318f36SChris Fallin } 989a0318f36SChris Fallin (None, Some(to)) => { 990a0318f36SChris Fallin // Load from spillslot to register. 991a0318f36SChris Fallin let from = from.as_stack().unwrap(); 992a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 993a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 994a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 995a0318f36SChris Fallin } 996a0318f36SChris Fallin (None, None) => { 997a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 998a0318f36SChris Fallin } 999a0318f36SChris Fallin } 1000a0318f36SChris Fallin } 1001c84d6be6SChris Fallin } 1002d8357426SChris Fallin } 1003b691770fSChris Fallin 1004964c6087SChris Fallin if cur_srcloc.is_some() { 100572e6be93SChris Fallin buffer.end_srcloc(); 1006964c6087SChris Fallin cur_srcloc = None; 1007b691770fSChris Fallin } 100872e6be93SChris Fallin 100949dd8fd7SAlex Crichton // Do we need an island? Get the worst-case size of the next BB, add 101049dd8fd7SAlex Crichton // it to the optional padding behind the block, and pass this to the 101149dd8fd7SAlex Crichton // `MachBuffer` to determine if an island is necessary. 101249dd8fd7SAlex Crichton let worst_case_next_bb = if block_order_idx < final_order.len() - 1 { 1013863659e0SChris Fallin let next_block = final_order[block_order_idx + 1]; 1014863659e0SChris Fallin let next_block_range = self.block_ranges[next_block.index()]; 1015863659e0SChris Fallin let next_block_size = 1016863659e0SChris Fallin (next_block_range.1.index() - next_block_range.0.index()) as u32; 1017863659e0SChris Fallin let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; 101849dd8fd7SAlex Crichton I::worst_case_size() * (next_block_size + next_block_ra_insertions) 101949dd8fd7SAlex Crichton } else { 102049dd8fd7SAlex Crichton 0 102149dd8fd7SAlex Crichton }; 102249dd8fd7SAlex Crichton let padding = if bb_padding.is_empty() { 102349dd8fd7SAlex Crichton 0 102449dd8fd7SAlex Crichton } else { 102549dd8fd7SAlex Crichton bb_padding.len() as u32 + I::LabelUse::ALIGN - 1 102649dd8fd7SAlex Crichton }; 102749dd8fd7SAlex Crichton if buffer.island_needed(padding + worst_case_next_bb) { 1028f8c03d5aSAlex Crichton buffer.emit_island(padding + worst_case_next_bb, ctrl_plane); 102972e6be93SChris Fallin } 103049dd8fd7SAlex Crichton 103149dd8fd7SAlex Crichton // Insert padding, if configured, to stress the `MachBuffer`'s 103249dd8fd7SAlex Crichton // relocation and island calculations. 1033475d1ba5SAlex Crichton // 1034475d1ba5SAlex Crichton // Padding can get quite large during fuzzing though so place a 1035475d1ba5SAlex Crichton // total cap on it where when a per-function threshold is exceeded 1036475d1ba5SAlex Crichton // the padding is turned back down to zero. This avoids a small-ish 1037475d1ba5SAlex Crichton // test case generating a GB+ memory footprint in Cranelift for 1038475d1ba5SAlex Crichton // example. 103949dd8fd7SAlex Crichton if !bb_padding.is_empty() { 104049dd8fd7SAlex Crichton buffer.put_data(&bb_padding); 104149dd8fd7SAlex Crichton buffer.align_to(I::LabelUse::ALIGN); 1042475d1ba5SAlex Crichton total_bb_padding += bb_padding.len(); 1043475d1ba5SAlex Crichton if total_bb_padding > (150 << 20) { 1044475d1ba5SAlex Crichton bb_padding = Vec::new(); 1045475d1ba5SAlex Crichton } 104672e6be93SChris Fallin } 1047d8357426SChris Fallin } 1048d8357426SChris Fallin 1049d4a4d4f9SSingleAccretion // Do any optimizations on branches at tail of buffer, as if we had 1050d4a4d4f9SSingleAccretion // bound one last label. 1051d4a4d4f9SSingleAccretion buffer.optimize_branches(ctrl_plane); 1052d4a4d4f9SSingleAccretion 10537eb89140SRemo Senekowitsch // emission state is not needed anymore, move control plane back out 10547eb89140SRemo Senekowitsch *ctrl_plane = state.take_ctrl_plane(); 10557eb89140SRemo Senekowitsch 1056a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1057de4af90aSYury Delendik 105811a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 105911a2ef01SChris Fallin let mut bb_edges = vec![]; 1060a0318f36SChris Fallin let mut bb_offsets = vec![]; 106149dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 106211a2ef01SChris Fallin for block in 0..self.num_blocks() { 106311a2ef01SChris Fallin if bb_starts[block].is_none() { 106411a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 106511a2ef01SChris Fallin continue; 106611a2ef01SChris Fallin } 106711a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 106811a2ef01SChris Fallin 1069a0318f36SChris Fallin bb_offsets.push(from); 107011a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1071a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1072a0318f36SChris Fallin for &succ in succs.iter() { 1073a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 107411a2ef01SChris Fallin bb_edges.push((from, to)); 107511a2ef01SChris Fallin } 107611a2ef01SChris Fallin } 1077800cf25bSChris Fallin } 107811a2ef01SChris Fallin 1079d4a4d4f9SSingleAccretion self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len); 1080a0318f36SChris Fallin let value_labels_ranges = 1081a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1082a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1083a0318f36SChris Fallin 1084a0318f36SChris Fallin EmitResult { 108549dd8fd7SAlex Crichton buffer: buffer.finish(&self.constants, ctrl_plane), 1086a0318f36SChris Fallin bb_offsets, 1087a0318f36SChris Fallin bb_edges, 1088a0318f36SChris Fallin func_body_len, 1089a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10909c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10919c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1092a0318f36SChris Fallin value_labels_ranges, 1093a0318f36SChris Fallin frame_size, 1094a0318f36SChris Fallin } 1095d8357426SChris Fallin } 1096d8357426SChris Fallin 1097d4a4d4f9SSingleAccretion fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) { 1098d4a4d4f9SSingleAccretion if self.debug_value_labels.is_empty() { 1099d4a4d4f9SSingleAccretion return; 1100d4a4d4f9SSingleAccretion } 1101d4a4d4f9SSingleAccretion 1102d4a4d4f9SSingleAccretion // During emission, branch removal can make offsets of instructions incorrect. 1103d4a4d4f9SSingleAccretion // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj] 1104d4a4d4f9SSingleAccretion // It will be recorded as (say): [30] [34] [38] [42] [<would be 46>] 1105d4a4d4f9SSingleAccretion // When the jumps get removed we are left with (in "inst_offsets"): 1106d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1107d4a4d4f9SSingleAccretion // [30] [34] [38] [42] [34] 1108d4a4d4f9SSingleAccretion // Which violates the monotonicity invariant. This method sets offsets of these 1109d4a4d4f9SSingleAccretion // removed instructions such as to make them appear zero-sized: 1110d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1111d4a4d4f9SSingleAccretion // [30] [34] [34] [34] [34] 1112d4a4d4f9SSingleAccretion // 1113d4a4d4f9SSingleAccretion let mut next_offset = func_body_len; 1114d4a4d4f9SSingleAccretion for inst_index in (0..(inst_offsets.len() - 1)).rev() { 1115d4a4d4f9SSingleAccretion let inst_offset = inst_offsets[inst_index]; 1116d4a4d4f9SSingleAccretion 1117d4a4d4f9SSingleAccretion // Not all instructions get their offsets recorded. 1118d4a4d4f9SSingleAccretion if inst_offset == NO_INST_OFFSET { 1119d4a4d4f9SSingleAccretion continue; 1120d4a4d4f9SSingleAccretion } 1121d4a4d4f9SSingleAccretion 1122d4a4d4f9SSingleAccretion if inst_offset > next_offset { 1123d4a4d4f9SSingleAccretion trace!( 1124d4a4d4f9SSingleAccretion "Fixing code offset of the removed Inst {}: {} -> {}", 1125d4a4d4f9SSingleAccretion inst_index, 1126d4a4d4f9SSingleAccretion inst_offset, 1127d4a4d4f9SSingleAccretion next_offset 1128d4a4d4f9SSingleAccretion ); 1129d4a4d4f9SSingleAccretion inst_offsets[inst_index] = next_offset; 1130d4a4d4f9SSingleAccretion continue; 1131d4a4d4f9SSingleAccretion } 1132d4a4d4f9SSingleAccretion 1133d4a4d4f9SSingleAccretion next_offset = inst_offset; 1134d4a4d4f9SSingleAccretion } 1135d4a4d4f9SSingleAccretion } 1136d4a4d4f9SSingleAccretion 1137a0318f36SChris Fallin fn compute_value_labels_ranges( 1138a0318f36SChris Fallin &self, 1139a0318f36SChris Fallin regalloc: ®alloc2::Output, 1140a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1141a0318f36SChris Fallin func_body_len: u32, 1142a0318f36SChris Fallin ) -> ValueLabelsRanges { 1143a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1144602006ffSbjorn3 return ValueLabelsRanges::default(); 1145997fab55SChris Fallin } 1146997fab55SChris Fallin 1147a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1148a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1149a0318f36SChris Fallin let ranges = value_labels_ranges 1150a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1151a0318f36SChris Fallin .or_insert_with(|| vec![]); 1152a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1153a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1154a0318f36SChris Fallin func_body_len 1155a0318f36SChris Fallin } else { 1156a0318f36SChris Fallin inst_offsets[to.inst().index()] 1157a0318f36SChris Fallin }; 1158a0318f36SChris Fallin 1159d4a4d4f9SSingleAccretion // Empty ranges or unavailable offsets can happen 1160d4a4d4f9SSingleAccretion // due to cold blocks and branch removal (see above). 1161d4a4d4f9SSingleAccretion if from_offset == NO_INST_OFFSET 1162d4a4d4f9SSingleAccretion || to_offset == NO_INST_OFFSET 1163d4a4d4f9SSingleAccretion || from_offset == to_offset 1164d4a4d4f9SSingleAccretion { 1165a0318f36SChris Fallin continue; 116676d61504Sbjorn3 } 116776d61504Sbjorn3 1168a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1169a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1170a0318f36SChris Fallin } else { 11717b16eccdSSingleAccretion let slot = alloc.as_stack().unwrap(); 11727b16eccdSSingleAccretion let sp_offset = self.abi.get_spillslot_offset(slot); 11737b16eccdSSingleAccretion let sp_to_caller_sp_offset = self.abi.nominal_sp_to_caller_sp_offset(); 11747b16eccdSSingleAccretion let caller_sp_to_cfa_offset = 11757b16eccdSSingleAccretion crate::isa::unwind::systemv::caller_sp_to_cfa_offset(); 11767b16eccdSSingleAccretion let cfa_to_sp_offset = -((sp_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64); 11777b16eccdSSingleAccretion LabelValueLoc::CFAOffset(cfa_to_sp_offset + sp_offset) 1178a0318f36SChris Fallin }; 1179a0318f36SChris Fallin 1180a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1181a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1182a0318f36SChris Fallin // instruction; that is the same as the end of another 1183a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1184a0318f36SChris Fallin // we are past the previous instruction's end. 1185d4a4d4f9SSingleAccretion let start = from_offset + 1; 1186d4a4d4f9SSingleAccretion 1187a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1188a0318f36SChris Fallin // *include* the end of the last 1189a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1190a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1191a0318f36SChris Fallin // the first instruction not covered. That 1192a0318f36SChris Fallin // instruction's start is the same as the end of the 1193a0318f36SChris Fallin // last instruction that is included, so we go one 1194a0318f36SChris Fallin // byte further to be sure to include it. 1195d4a4d4f9SSingleAccretion let end = to_offset + 1; 1196d4a4d4f9SSingleAccretion 11977b16eccdSSingleAccretion // Coalesce adjacent ranges that for the same location 11987b16eccdSSingleAccretion // to minimize output size here and for the consumers. 11997b16eccdSSingleAccretion if let Some(last_loc_range) = ranges.last_mut() { 12007b16eccdSSingleAccretion if last_loc_range.loc == loc && last_loc_range.end == start { 12017b16eccdSSingleAccretion trace!( 12027b16eccdSSingleAccretion "Extending debug range for VL{} in {:?} to {}", 12037b16eccdSSingleAccretion label, 12047b16eccdSSingleAccretion loc, 12057b16eccdSSingleAccretion end 12067b16eccdSSingleAccretion ); 12077b16eccdSSingleAccretion last_loc_range.end = end; 12087b16eccdSSingleAccretion continue; 12097b16eccdSSingleAccretion } 12107b16eccdSSingleAccretion } 12117b16eccdSSingleAccretion 1212d4a4d4f9SSingleAccretion trace!( 1213d4a4d4f9SSingleAccretion "Recording debug range for VL{} in {:?}: [Inst {}..Inst {}) [{}..{})", 1214d4a4d4f9SSingleAccretion label, 1215d4a4d4f9SSingleAccretion loc, 1216d4a4d4f9SSingleAccretion from.inst().index(), 1217d4a4d4f9SSingleAccretion to.inst().index(), 1218d4a4d4f9SSingleAccretion start, 1219d4a4d4f9SSingleAccretion end 1220d4a4d4f9SSingleAccretion ); 1221d4a4d4f9SSingleAccretion 1222d4a4d4f9SSingleAccretion ranges.push(ValueLocRange { loc, start, end }); 1223a0318f36SChris Fallin } 1224a0318f36SChris Fallin 1225a0318f36SChris Fallin value_labels_ranges 1226c84d6be6SChris Fallin } 1227c84d6be6SChris Fallin 1228d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1229d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1230a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1231d8357426SChris Fallin } 12322154c63dSAlex Crichton 1233fef8a90fSChris Fallin pub fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 1234fef8a90fSChris Fallin Self::resolve_vreg_alias_impl(&self.vreg_aliases, from) 1235fef8a90fSChris Fallin } 1236fef8a90fSChris Fallin 1237fef8a90fSChris Fallin /// Implementation of alias resolution. Separate helper that does 1238fef8a90fSChris Fallin /// not borrow `self` in order to allow working around borrowing 1239fef8a90fSChris Fallin /// restrictions. 1240fef8a90fSChris Fallin fn resolve_vreg_alias_impl( 1241fef8a90fSChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 1242fef8a90fSChris Fallin from: regalloc2::VReg, 1243fef8a90fSChris Fallin ) -> regalloc2::VReg { 1244fef8a90fSChris Fallin // We prevent cycles from existing by resolving targets of 1245fef8a90fSChris Fallin // aliases eagerly before setting them. If the target resolves 1246fef8a90fSChris Fallin // to the origin of the alias, then a cycle would be created 1247fef8a90fSChris Fallin // and the alias is disallowed. Because of the structure of 1248fef8a90fSChris Fallin // SSA code (one instruction can refer to another's defs but 1249fef8a90fSChris Fallin // not vice-versa, except indirectly through 1250fef8a90fSChris Fallin // phis/blockparams), cycles should not occur as we use 1251fef8a90fSChris Fallin // aliases to redirect vregs to the temps that actually define 1252fef8a90fSChris Fallin // them. 1253fef8a90fSChris Fallin 1254fef8a90fSChris Fallin let mut vreg = from; 1255fef8a90fSChris Fallin while let Some(to) = aliases.get(&vreg) { 1256fef8a90fSChris Fallin vreg = *to; 1257fef8a90fSChris Fallin } 1258fef8a90fSChris Fallin vreg 1259fef8a90fSChris Fallin } 1260fef8a90fSChris Fallin 12612154c63dSAlex Crichton #[inline] 1262*70d2a26eSJamey Sharp fn debug_assert_no_vreg_aliases(&self, mut list: impl Iterator<Item = VReg>) { 1263*70d2a26eSJamey Sharp debug_assert!(list.all(|vreg| !self.vreg_aliases.contains_key(&vreg))); 12642154c63dSAlex Crichton } 1265f466aa26SChris Fallin 12669e4d4462SChris Fallin /// Get the type of a VReg. 12679e4d4462SChris Fallin pub fn vreg_type(&self, vreg: VReg) -> Type { 12689e4d4462SChris Fallin self.vreg_types[vreg.vreg()] 12699e4d4462SChris Fallin } 12709e4d4462SChris Fallin 1271f466aa26SChris Fallin /// Get the fact, if any, for a given VReg. 1272f466aa26SChris Fallin pub fn vreg_fact(&self, vreg: VReg) -> Option<&Fact> { 1273fef8a90fSChris Fallin let vreg = self.resolve_vreg_alias(vreg); 12749e4d4462SChris Fallin self.facts[vreg.vreg()].as_ref() 1275f466aa26SChris Fallin } 1276f466aa26SChris Fallin 12778d19280aSChris Fallin /// Set the fact for a given VReg. 12788d19280aSChris Fallin pub fn set_vreg_fact(&mut self, vreg: VReg, fact: Fact) { 12798d19280aSChris Fallin let vreg = self.resolve_vreg_alias(vreg); 1280f262c311SChris Fallin trace!("set fact on {}: {:?}", vreg, fact); 12818d19280aSChris Fallin self.facts[vreg.vreg()] = Some(fact); 12828d19280aSChris Fallin } 12838d19280aSChris Fallin 1284f466aa26SChris Fallin /// Does a given instruction define any facts? 1285f466aa26SChris Fallin pub fn inst_defines_facts(&self, inst: InsnIndex) -> bool { 1286f466aa26SChris Fallin self.inst_operands(inst) 1287f466aa26SChris Fallin .iter() 1288f466aa26SChris Fallin .filter(|o| o.kind() == OperandKind::Def) 1289f466aa26SChris Fallin .map(|o| o.vreg()) 12902e7f9414SChris Fallin .any(|vreg| self.facts[vreg.vreg()].is_some()) 1291f466aa26SChris Fallin } 1292f466aa26SChris Fallin } 1293f466aa26SChris Fallin 1294f466aa26SChris Fallin impl<I: VCodeInst> std::ops::Index<InsnIndex> for VCode<I> { 1295f466aa26SChris Fallin type Output = I; 1296f466aa26SChris Fallin fn index(&self, idx: InsnIndex) -> &Self::Output { 1297f466aa26SChris Fallin &self.insts[idx.index()] 1298f466aa26SChris Fallin } 1299d8357426SChris Fallin } 1300d8357426SChris Fallin 1301d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1302a0318f36SChris Fallin fn num_insts(&self) -> usize { 1303a0318f36SChris Fallin self.insts.len() 1304d8357426SChris Fallin } 1305d8357426SChris Fallin 1306a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1307a0318f36SChris Fallin self.block_ranges.len() 1308d8357426SChris Fallin } 1309d8357426SChris Fallin 1310a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1311a0318f36SChris Fallin self.entry 1312d8357426SChris Fallin } 1313d8357426SChris Fallin 1314a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1315a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1316a0318f36SChris Fallin InstRange::forward(start, end) 1317d8357426SChris Fallin } 1318d8357426SChris Fallin 1319a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1320a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1321a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1322d8357426SChris Fallin } 1323d8357426SChris Fallin 1324a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1325a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1326a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1327d8357426SChris Fallin } 1328d8357426SChris Fallin 1329a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1330c5379051STrevor Elliott // As a special case we don't return block params for the entry block, as all the arguments 1331c5379051STrevor Elliott // will be defined by the `Inst::Args` instruction. 1332c5379051STrevor Elliott if block == self.entry { 1333c5379051STrevor Elliott return &[]; 1334c5379051STrevor Elliott } 1335c5379051STrevor Elliott 1336a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 13372154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 13382154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 13392154c63dSAlex Crichton // double-check just to be sure. 1340*70d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 1341*70d2a26eSJamey Sharp ret 1342d8357426SChris Fallin } 1343d8357426SChris Fallin 1344a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1345a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1346a0318f36SChris Fallin let succ_ranges = 1347a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1348a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 13492154c63dSAlex Crichton let ret = &self.branch_block_args 13502154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 1351*70d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 1352*70d2a26eSJamey Sharp ret 1353d8357426SChris Fallin } 1354d8357426SChris Fallin 1355a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1356a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1357c5379051STrevor Elliott // We treat blocks terminated by an unconditional trap like a return for regalloc. 1358c5379051STrevor Elliott MachTerminator::None => self.insts[insn.index()].is_trap(), 13594154fa47SNick Fitzgerald MachTerminator::Ret | MachTerminator::RetCall => true, 13604154fa47SNick Fitzgerald MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false, 1361d8357426SChris Fallin } 1362d8357426SChris Fallin } 1363d8357426SChris Fallin 1364a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1365a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 13665774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1367a0318f36SChris Fallin _ => false, 1368a0318f36SChris Fallin } 136971768bb6SChris Fallin } 137071768bb6SChris Fallin 1371a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1372a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1373d8357426SChris Fallin } 1374d8357426SChris Fallin 1375a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1376a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 13772154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 1378*70d2a26eSJamey Sharp // It should be true by construction that `Operand`s do not contain any 1379*70d2a26eSJamey Sharp // aliased vregs since they're all collected and mapped when the VCode 1380*70d2a26eSJamey Sharp // is itself constructed. 1381*70d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|op| op.vreg())); 13822154c63dSAlex Crichton ret 1383d8357426SChris Fallin } 1384d8357426SChris Fallin 1385b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1386b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1387be6f060aSChris Fallin } 1388be6f060aSChris Fallin 1389a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1390a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1391d8357426SChris Fallin } 1392d8357426SChris Fallin 1393a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 1394*70d2a26eSJamey Sharp let ret = &self.reftyped_vregs; 1395*70d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 1396*70d2a26eSJamey Sharp ret 1397d8357426SChris Fallin } 1398d8357426SChris Fallin 1399a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 14002154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 1401*70d2a26eSJamey Sharp // generated and aliases are fully defined, so double-check that 14022154c63dSAlex Crichton // aliases are not lingering. 1403*70d2a26eSJamey Sharp let ret = &self.debug_value_labels; 1404*70d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|&(vreg, ..)| vreg)); 1405*70d2a26eSJamey Sharp ret 1406d8357426SChris Fallin } 1407d8357426SChris Fallin 1408a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1409a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1410d8357426SChris Fallin } 1411d8357426SChris Fallin 1412a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1413a0318f36SChris Fallin // At least the s390x backend requires this, because the 1414a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1415a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1416a0318f36SChris Fallin true 1417d8357426SChris Fallin } 1418d8357426SChris Fallin } 1419d8357426SChris Fallin 1420d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1421d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1422a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1423a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1424a0318f36SChris Fallin 1425a0318f36SChris Fallin let mut state = Default::default(); 1426a0318f36SChris Fallin 1427a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1428a0318f36SChris Fallin alias_keys.sort_unstable(); 1429a0318f36SChris Fallin for key in alias_keys { 1430a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1431a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1432a0318f36SChris Fallin } 1433d8357426SChris Fallin 1434d8357426SChris Fallin for block in 0..self.num_blocks() { 1435a0318f36SChris Fallin let block = BlockIndex::new(block); 1436a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1437a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1438a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1439d8357426SChris Fallin } 1440a0318f36SChris Fallin for succ in self.succs(block) { 1441a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1442a0318f36SChris Fallin } 1443a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1444a0318f36SChris Fallin writeln!( 1445a0318f36SChris Fallin f, 1446a0318f36SChris Fallin " (instruction range: {} .. {})", 1447a0318f36SChris Fallin start.index(), 1448a0318f36SChris Fallin end.index() 1449a0318f36SChris Fallin )?; 1450a0318f36SChris Fallin for inst in start.index()..end.index() { 1451a0318f36SChris Fallin writeln!( 1452a0318f36SChris Fallin f, 1453a0318f36SChris Fallin " Inst {}: {}", 1454a0318f36SChris Fallin inst, 1455a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1456a0318f36SChris Fallin )?; 1457f466aa26SChris Fallin for operand in self.inst_operands(InsnIndex::new(inst)) { 1458f466aa26SChris Fallin if operand.kind() == OperandKind::Def { 1459f466aa26SChris Fallin if let Some(fact) = &self.facts[operand.vreg().vreg()] { 1460fef8a90fSChris Fallin writeln!(f, " v{} ! {}", operand.vreg().vreg(), fact)?; 1461f466aa26SChris Fallin } 1462f466aa26SChris Fallin } 1463f466aa26SChris Fallin } 1464d8357426SChris Fallin } 1465d8357426SChris Fallin } 1466d8357426SChris Fallin 1467d8357426SChris Fallin writeln!(f, "}}")?; 1468d8357426SChris Fallin Ok(()) 1469d8357426SChris Fallin } 1470d8357426SChris Fallin } 1471d8357426SChris Fallin 1472d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder. 1473d94173eaSTrevor Elliott pub struct VRegAllocator<I> { 1474d94173eaSTrevor Elliott /// Next virtual register number to allocate. 1475d94173eaSTrevor Elliott next_vreg: usize, 1476d94173eaSTrevor Elliott 1477d94173eaSTrevor Elliott /// VReg IR-level types. 1478d94173eaSTrevor Elliott vreg_types: Vec<Type>, 1479d94173eaSTrevor Elliott 1480d94173eaSTrevor Elliott /// A set with the same contents as `reftyped_vregs`, in order to 1481d94173eaSTrevor Elliott /// avoid inserting more than once. 1482d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet<VReg>, 1483d94173eaSTrevor Elliott 1484d94173eaSTrevor Elliott /// Reference-typed `regalloc2::VReg`s. The regalloc requires 1485d94173eaSTrevor Elliott /// these in a dense slice (as opposed to querying the 1486d94173eaSTrevor Elliott /// reftype-status of each vreg) for efficient iteration. 1487d94173eaSTrevor Elliott reftyped_vregs: Vec<VReg>, 1488d94173eaSTrevor Elliott 148917eeba0eSChris Fallin /// A deferred error, to be bubbled up to the top level of the 149017eeba0eSChris Fallin /// lowering algorithm. We take this approach because we cannot 149117eeba0eSChris Fallin /// currently propagate a `Result` upward through ISLE code (the 149217eeba0eSChris Fallin /// lowering rules) or some ABI code. 149317eeba0eSChris Fallin deferred_error: Option<CodegenError>, 149417eeba0eSChris Fallin 1495f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code. 1496f466aa26SChris Fallin facts: Vec<Option<Fact>>, 1497f466aa26SChris Fallin 1498d94173eaSTrevor Elliott /// The type of instruction that this allocator makes registers for. 1499d94173eaSTrevor Elliott _inst: core::marker::PhantomData<I>, 1500d94173eaSTrevor Elliott } 1501d94173eaSTrevor Elliott 1502d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> { 1503d94173eaSTrevor Elliott /// Make a new VRegAllocator. 1504d94173eaSTrevor Elliott pub fn new() -> Self { 1505d94173eaSTrevor Elliott Self { 1506d94173eaSTrevor Elliott next_vreg: first_user_vreg_index(), 1507d94173eaSTrevor Elliott vreg_types: vec![], 1508f466aa26SChris Fallin facts: vec![], 1509d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet::default(), 1510d94173eaSTrevor Elliott reftyped_vregs: vec![], 151117eeba0eSChris Fallin deferred_error: None, 1512d94173eaSTrevor Elliott _inst: core::marker::PhantomData::default(), 1513d94173eaSTrevor Elliott } 1514d94173eaSTrevor Elliott } 1515d94173eaSTrevor Elliott 1516d94173eaSTrevor Elliott /// Allocate a fresh ValueRegs. 1517d94173eaSTrevor Elliott pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> { 151817eeba0eSChris Fallin if self.deferred_error.is_some() { 151917eeba0eSChris Fallin return Err(CodegenError::CodeTooLarge); 152017eeba0eSChris Fallin } 1521d94173eaSTrevor Elliott let v = self.next_vreg; 1522d94173eaSTrevor Elliott let (regclasses, tys) = I::rc_for_type(ty)?; 1523d94173eaSTrevor Elliott self.next_vreg += regclasses.len(); 1524d94173eaSTrevor Elliott if self.next_vreg >= VReg::MAX { 1525d94173eaSTrevor Elliott return Err(CodegenError::CodeTooLarge); 1526d94173eaSTrevor Elliott } 1527d94173eaSTrevor Elliott 1528d94173eaSTrevor Elliott let regs: ValueRegs<Reg> = match regclasses { 1529d94173eaSTrevor Elliott &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), 1530d94173eaSTrevor Elliott &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), 1531d94173eaSTrevor Elliott // We can extend this if/when we support 32-bit targets; e.g., 1532d94173eaSTrevor Elliott // an i128 on a 32-bit machine will need up to four machine regs 1533d94173eaSTrevor Elliott // for a `Value`. 1534d94173eaSTrevor Elliott _ => panic!("Value must reside in 1 or 2 registers"), 1535d94173eaSTrevor Elliott }; 1536d94173eaSTrevor Elliott for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { 1537d94173eaSTrevor Elliott self.set_vreg_type(reg.to_virtual_reg().unwrap(), reg_ty); 1538d94173eaSTrevor Elliott } 1539f466aa26SChris Fallin 1540f466aa26SChris Fallin // Create empty facts for each allocated vreg. 1541f466aa26SChris Fallin self.facts 1542f466aa26SChris Fallin .resize(usize::try_from(self.next_vreg).unwrap(), None); 1543f466aa26SChris Fallin 1544d94173eaSTrevor Elliott Ok(regs) 1545d94173eaSTrevor Elliott } 1546d94173eaSTrevor Elliott 154717eeba0eSChris Fallin /// Allocate a fresh ValueRegs, deferring any out-of-vregs 154817eeba0eSChris Fallin /// errors. This is useful in places where we cannot bubble a 154917eeba0eSChris Fallin /// `CodegenResult` upward easily, and which are known to be 155017eeba0eSChris Fallin /// invoked from within the lowering loop that checks the deferred 155117eeba0eSChris Fallin /// error status below. 155217eeba0eSChris Fallin pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg> { 155317eeba0eSChris Fallin match self.alloc(ty) { 155417eeba0eSChris Fallin Ok(x) => x, 155517eeba0eSChris Fallin Err(e) => { 155617eeba0eSChris Fallin self.deferred_error = Some(e); 155717eeba0eSChris Fallin self.bogus_for_deferred_error(ty) 155817eeba0eSChris Fallin } 155917eeba0eSChris Fallin } 156017eeba0eSChris Fallin } 156117eeba0eSChris Fallin 156217eeba0eSChris Fallin /// Take any deferred error that was accumulated by `alloc_with_deferred_error`. 156317eeba0eSChris Fallin pub fn take_deferred_error(&mut self) -> Option<CodegenError> { 156417eeba0eSChris Fallin self.deferred_error.take() 156517eeba0eSChris Fallin } 156617eeba0eSChris Fallin 156717eeba0eSChris Fallin /// Produce an bogus VReg placeholder with the proper number of 156817eeba0eSChris Fallin /// registers for the given type. This is meant to be used with 156917eeba0eSChris Fallin /// deferred allocation errors (see `Lower::alloc_tmp()`). 157017eeba0eSChris Fallin fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg> { 157117eeba0eSChris Fallin let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type"); 157217eeba0eSChris Fallin match regclasses { 157317eeba0eSChris Fallin &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()), 157417eeba0eSChris Fallin &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()), 157517eeba0eSChris Fallin _ => panic!("Value must reside in 1 or 2 registers"), 157617eeba0eSChris Fallin } 157717eeba0eSChris Fallin } 157817eeba0eSChris Fallin 1579d94173eaSTrevor Elliott /// Set the type of this virtual register. 1580d94173eaSTrevor Elliott pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 1581d94173eaSTrevor Elliott if self.vreg_types.len() <= vreg.index() { 158270bca801STrevor Elliott self.vreg_types.resize(vreg.index() + 1, ir::types::INVALID); 1583d94173eaSTrevor Elliott } 1584d94173eaSTrevor Elliott self.vreg_types[vreg.index()] = ty; 1585d94173eaSTrevor Elliott if is_reftype(ty) { 1586d94173eaSTrevor Elliott let vreg: VReg = vreg.into(); 1587d94173eaSTrevor Elliott if self.reftyped_vregs_set.insert(vreg) { 1588d94173eaSTrevor Elliott self.reftyped_vregs.push(vreg); 1589d94173eaSTrevor Elliott } 1590d94173eaSTrevor Elliott } 1591d94173eaSTrevor Elliott } 1592f466aa26SChris Fallin 1593f466aa26SChris Fallin /// Set the proof-carrying code fact on a given virtual register. 1594f466aa26SChris Fallin /// 1595f466aa26SChris Fallin /// Returns the old fact, if any (only one fact can be stored). 1596f466aa26SChris Fallin pub fn set_fact(&mut self, vreg: VirtualReg, fact: Fact) -> Option<Fact> { 1597fef8a90fSChris Fallin trace!("vreg {:?} has fact: {:?}", vreg, fact); 1598f466aa26SChris Fallin self.facts[vreg.index()].replace(fact) 1599f466aa26SChris Fallin } 1600f466aa26SChris Fallin 1601fef8a90fSChris Fallin /// Take (and remove) a fact about a VReg. Used when setting up 1602fef8a90fSChris Fallin /// aliases: we want to move a fact from the alias vreg to the 1603fef8a90fSChris Fallin /// aliased vreg, to preserve facts about a value that were stated 1604fef8a90fSChris Fallin /// before we lowered its producer. 1605fef8a90fSChris Fallin pub fn take_fact(&mut self, vreg: VirtualReg) -> Option<Fact> { 1606fef8a90fSChris Fallin self.facts[vreg.index()].take() 1607fef8a90fSChris Fallin } 1608fef8a90fSChris Fallin 1609f262c311SChris Fallin /// Set a fact only if one doesn't already exist. 1610f262c311SChris Fallin pub fn set_fact_if_missing(&mut self, vreg: VirtualReg, fact: Fact) { 1611f262c311SChris Fallin if self.facts[vreg.index()].is_none() { 1612f262c311SChris Fallin self.set_fact(vreg, fact); 1613f262c311SChris Fallin } 1614f262c311SChris Fallin } 1615f262c311SChris Fallin 1616f466aa26SChris Fallin /// Allocate a fresh ValueRegs, with a given fact to apply if 1617f466aa26SChris Fallin /// the value fits in one VReg. 1618f466aa26SChris Fallin pub fn alloc_with_maybe_fact( 1619f466aa26SChris Fallin &mut self, 1620f466aa26SChris Fallin ty: Type, 1621f466aa26SChris Fallin fact: Option<Fact>, 1622f466aa26SChris Fallin ) -> CodegenResult<ValueRegs<Reg>> { 1623f466aa26SChris Fallin let result = self.alloc(ty)?; 1624f466aa26SChris Fallin 1625f466aa26SChris Fallin // Ensure that we don't lose a fact on a value that splits 1626f466aa26SChris Fallin // into multiple VRegs. 1627f466aa26SChris Fallin assert!(result.len() == 1 || fact.is_none()); 1628f466aa26SChris Fallin if let Some(fact) = fact { 1629f466aa26SChris Fallin self.set_fact(result.regs()[0].to_virtual_reg().unwrap(), fact); 1630f466aa26SChris Fallin } 1631f466aa26SChris Fallin 1632f466aa26SChris Fallin Ok(result) 1633f466aa26SChris Fallin } 1634d94173eaSTrevor Elliott } 1635d94173eaSTrevor Elliott 163683f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 163783f182b3SAndrew Brown /// [MachBuffer]. 163883f182b3SAndrew Brown /// 163983f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 1640d38d387aSAlex Crichton /// [VCodeConstants.insert]; an intermediate handle, `VCodeConstant`, tracks what constants are 164183f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 164283f182b3SAndrew Brown /// values are inserted. 164383f182b3SAndrew Brown /// 164483f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 164583f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 164683f182b3SAndrew Brown /// then writes the constant values to the buffer. 164783f182b3SAndrew Brown #[derive(Default)] 164883f182b3SAndrew Brown pub struct VCodeConstants { 164983f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 165083f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 165183f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1652eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 165383f182b3SAndrew Brown } 165483f182b3SAndrew Brown impl VCodeConstants { 165583f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 165683f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 165783f182b3SAndrew Brown Self { 165883f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 165983f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 166083f182b3SAndrew Brown well_known_uses: HashMap::new(), 1661eb435f30SChris Fallin u64s: HashMap::new(), 166283f182b3SAndrew Brown } 166383f182b3SAndrew Brown } 166483f182b3SAndrew Brown 166583f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 166683f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 166783f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 166883f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 166983f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 167083f182b3SAndrew Brown match data { 167183f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 167283f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 167383f182b3SAndrew Brown None => { 167483f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 167583f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 167683f182b3SAndrew Brown vcode_constant 167783f182b3SAndrew Brown } 167883f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 167983f182b3SAndrew Brown }, 168083f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1681eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1682eb435f30SChris Fallin Entry::Vacant(v) => { 168383f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1684eb435f30SChris Fallin v.insert(vcode_constant); 168583f182b3SAndrew Brown vcode_constant 168683f182b3SAndrew Brown } 1687eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 168883f182b3SAndrew Brown } 168983f182b3SAndrew Brown } 1690eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1691eb435f30SChris Fallin Entry::Vacant(v) => { 1692eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1693eb435f30SChris Fallin v.insert(vcode_constant); 1694eb435f30SChris Fallin vcode_constant 1695eb435f30SChris Fallin } 1696eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1697eb435f30SChris Fallin }, 169883f182b3SAndrew Brown } 169983f182b3SAndrew Brown } 170083f182b3SAndrew Brown 170183f182b3SAndrew Brown /// Return the number of constants inserted. 170283f182b3SAndrew Brown pub fn len(&self) -> usize { 170383f182b3SAndrew Brown self.constants.len() 170483f182b3SAndrew Brown } 170583f182b3SAndrew Brown 1706d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys inserted in this structure. 170783f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 170883f182b3SAndrew Brown self.constants.keys() 170983f182b3SAndrew Brown } 171083f182b3SAndrew Brown 1711d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys and the data (as a byte slice) inserted in this 171283f182b3SAndrew Brown /// structure. 171383f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 171483f182b3SAndrew Brown self.constants.iter() 171583f182b3SAndrew Brown } 171649dd8fd7SAlex Crichton 171749dd8fd7SAlex Crichton /// Returns the data associated with the specified constant. 171849dd8fd7SAlex Crichton pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData { 171949dd8fd7SAlex Crichton &self.constants[c] 172049dd8fd7SAlex Crichton } 172197f6a8b3SSaúl Cabrera 172297f6a8b3SSaúl Cabrera /// Checks if the given [VCodeConstantData] is registered as 172397f6a8b3SSaúl Cabrera /// used by the pool. 172497f6a8b3SSaúl Cabrera pub fn pool_uses(&self, constant: &VCodeConstantData) -> bool { 172597f6a8b3SSaúl Cabrera match constant { 172697f6a8b3SSaúl Cabrera VCodeConstantData::Pool(c, _) => self.pool_uses.contains_key(c), 172797f6a8b3SSaúl Cabrera _ => false, 172897f6a8b3SSaúl Cabrera } 172997f6a8b3SSaúl Cabrera } 173083f182b3SAndrew Brown } 173183f182b3SAndrew Brown 173283f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 173383f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 173483f182b3SAndrew Brown pub struct VCodeConstant(u32); 173583f182b3SAndrew Brown entity_impl!(VCodeConstant); 173683f182b3SAndrew Brown 173783f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 173883f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 173983f182b3SAndrew Brown pub enum VCodeConstantData { 174083f182b3SAndrew Brown /// A constant already present in the Cranelift IR 174183f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 174283f182b3SAndrew Brown Pool(Constant, ConstantData), 174383f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 174483f182b3SAndrew Brown WellKnown(&'static [u8]), 174583f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 174683f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 174783f182b3SAndrew Brown Generated(ConstantData), 1748eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1749eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1750eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1751eb435f30SChris Fallin U64([u8; 8]), 175283f182b3SAndrew Brown } 175383f182b3SAndrew Brown impl VCodeConstantData { 175483f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 175583f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 175683f182b3SAndrew Brown match self { 175783f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 175883f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1759eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 176083f182b3SAndrew Brown } 176183f182b3SAndrew Brown } 176283f182b3SAndrew Brown 176383f182b3SAndrew Brown /// Calculate the alignment of the constant data. 176483f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 176583f182b3SAndrew Brown if self.as_slice().len() <= 8 { 176683f182b3SAndrew Brown 8 176783f182b3SAndrew Brown } else { 176883f182b3SAndrew Brown 16 176983f182b3SAndrew Brown } 177083f182b3SAndrew Brown } 177183f182b3SAndrew Brown } 177283f182b3SAndrew Brown 177383f182b3SAndrew Brown #[cfg(test)] 177483f182b3SAndrew Brown mod test { 177583f182b3SAndrew Brown use super::*; 17765e5e5206SChris Fallin use std::mem::size_of; 177783f182b3SAndrew Brown 177883f182b3SAndrew Brown #[test] 177983f182b3SAndrew Brown fn size_of_constant_structs() { 178083f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 178183f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 178283f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 178383f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 178483f182b3SAndrew Brown assert_eq!( 178583f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 178683f182b3SAndrew Brown 24 178783f182b3SAndrew Brown ); 17885e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 17895e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 17905e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 179183f182b3SAndrew Brown } 179283f182b3SAndrew Brown } 1793