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 20f466aa26SChris Fallin use crate::ir::pcc::*; 219ce3ffe1SAlex Crichton use crate::ir::{self, types, Constant, ConstantData, ValueLabel}; 22d8357426SChris Fallin use crate::machinst::*; 232b9fefe8SChris Fallin use crate::timing; 248d022434SBenjamin Bouvier use crate::trace; 25d94173eaSTrevor Elliott use crate::CodegenError; 26729e2640Sbjorn3 use crate::{LabelValueLoc, ValueLocRange}; 27a0318f36SChris Fallin use regalloc2::{ 285c8a603aSUlrich Weigand Edit, Function as RegallocFunction, InstOrEdit, InstRange, MachineEnv, Operand, OperandKind, 299ce3ffe1SAlex Crichton PRegSet, RegClass, 30be6f060aSChris Fallin }; 31*132ef1e4SKirpal Grewal use rustc_hash::FxHashMap; 32d8357426SChris Fallin 339ce3ffe1SAlex Crichton use cranelift_entity::{entity_impl, Keys}; 34eb435f30SChris Fallin use std::collections::hash_map::Entry; 3583f182b3SAndrew Brown use std::collections::HashMap; 36d8357426SChris Fallin use std::fmt; 37d8357426SChris Fallin 38d8357426SChris Fallin /// Index referring to an instruction in VCode. 39a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst; 40a0318f36SChris Fallin 41d8357426SChris Fallin /// Index referring to a basic block in VCode. 42a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block; 43d8357426SChris Fallin 44d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be 45d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. 4672e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 4772e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {} 48d8357426SChris Fallin 49a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after 50a0318f36SChris Fallin /// lowering. This is essentially a standard CFG of basic blocks, 51a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced 52a0318f36SChris Fallin /// by the machine-specific backend. 53a0318f36SChris Fallin /// 54a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not 55a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register 56a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output` 57a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not 58a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the 59a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or 60a0318f36SChris Fallin /// metadata as requested. 61d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 62d8357426SChris Fallin /// VReg IR-level types. 63d8357426SChris Fallin vreg_types: Vec<Type>, 64d8357426SChris Fallin 65d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 6648cf2c2fSChris Fallin insts: Vec<I>, 67d8357426SChris Fallin 68a0318f36SChris Fallin /// Operands: pre-regalloc references to virtual registers with 69a0318f36SChris Fallin /// constraints, in one flattened array. This allows the regalloc 70a0318f36SChris Fallin /// to efficiently access all operands without requiring expensive 71a0318f36SChris Fallin /// matches or method invocations on insts. 72a0318f36SChris Fallin operands: Vec<Operand>, 73a0318f36SChris Fallin 74a0318f36SChris Fallin /// Operand index ranges: for each instruction in `insts`, there 75a0318f36SChris Fallin /// is a tuple here providing the range in `operands` for that 76a0318f36SChris Fallin /// instruction's operands. 77a0318f36SChris Fallin operand_ranges: Vec<(u32, u32)>, 78a0318f36SChris Fallin 79b2e28b91SChris Fallin /// Clobbers: a sparse map from instruction indices to clobber masks. 80b2e28b91SChris Fallin clobbers: FxHashMap<InsnIndex, PRegSet>, 81a0318f36SChris Fallin 82b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 83b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 848a9b1a90SBenjamin Bouvier srclocs: Vec<RelSourceLoc>, 85b691770fSChris Fallin 86d8357426SChris Fallin /// Entry block. 87d8357426SChris Fallin entry: BlockIndex, 88d8357426SChris Fallin 89d8357426SChris Fallin /// Block instruction indices. 9048cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 91d8357426SChris Fallin 92a0318f36SChris Fallin /// Block successors: index range in the `block_succs_preds` list. 93a0318f36SChris Fallin block_succ_range: Vec<(u32, u32)>, 94d8357426SChris Fallin 95a0318f36SChris Fallin /// Block predecessors: index range in the `block_succs_preds` list. 96a0318f36SChris Fallin block_pred_range: Vec<(u32, u32)>, 97a0318f36SChris Fallin 98a0318f36SChris Fallin /// Block successor and predecessor lists, concatenated into one 99a0318f36SChris Fallin /// Vec. The `block_succ_range` and `block_pred_range` lists of 100a0318f36SChris Fallin /// tuples above give (start, end) ranges within this list that 101a0318f36SChris Fallin /// correspond to each basic block's successors or predecessors, 102a0318f36SChris Fallin /// respectively. 103a0318f36SChris Fallin block_succs_preds: Vec<regalloc2::Block>, 104a0318f36SChris Fallin 105a0318f36SChris Fallin /// Block parameters: index range in `block_params` below. 106a0318f36SChris Fallin block_params_range: Vec<(u32, u32)>, 107a0318f36SChris Fallin 108a0318f36SChris Fallin /// Block parameter lists, concatenated into one vec. The 109a0318f36SChris Fallin /// `block_params_range` list of tuples above gives (start, end) 110a0318f36SChris Fallin /// ranges within this list that correspond to each basic block's 111a0318f36SChris Fallin /// blockparam vregs. 112a0318f36SChris Fallin block_params: Vec<regalloc2::VReg>, 113a0318f36SChris Fallin 114a0318f36SChris Fallin /// Outgoing block arguments on branch instructions, concatenated 115a0318f36SChris Fallin /// into one list. 116a0318f36SChris Fallin /// 117a0318f36SChris Fallin /// Note that this is conceptually a 3D array: we have a VReg list 118a0318f36SChris Fallin /// per block, per successor. We flatten those three dimensions 119a0318f36SChris Fallin /// into this 1D vec, then store index ranges in two levels of 120a0318f36SChris Fallin /// indirection. 121a0318f36SChris Fallin /// 122a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 123a0318f36SChris Fallin branch_block_args: Vec<regalloc2::VReg>, 124a0318f36SChris Fallin 125a0318f36SChris Fallin /// Array of sequences of (start, end) tuples in 126a0318f36SChris Fallin /// `branch_block_args`, one for each successor; these sequences 127a0318f36SChris Fallin /// for each block are concatenated. 128a0318f36SChris Fallin /// 129a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 130a0318f36SChris Fallin branch_block_arg_range: Vec<(u32, u32)>, 131a0318f36SChris Fallin 132a0318f36SChris Fallin /// For a given block, indices in `branch_block_arg_range` 133a0318f36SChris Fallin /// corresponding to all of its successors. 134a0318f36SChris Fallin branch_block_arg_succ_range: Vec<(u32, u32)>, 135a0318f36SChris Fallin 136a0318f36SChris Fallin /// VReg aliases. Each key in this table is translated to its 137a0318f36SChris Fallin /// value when gathering Operands from instructions. Aliases are 138a0318f36SChris Fallin /// not chased transitively (we do not further look up the 139a0318f36SChris Fallin /// translated reg to see if it is another alias). 140a0318f36SChris Fallin /// 141a0318f36SChris Fallin /// We use these aliases to rename an instruction's expected 142a0318f36SChris Fallin /// result vregs to the returned vregs from lowering, which are 143a0318f36SChris Fallin /// usually freshly-allocated temps. 144a0318f36SChris Fallin /// 145a0318f36SChris Fallin /// Operands and branch arguments will already have been 146a0318f36SChris Fallin /// translated through this alias table; but it helps to make 147a0318f36SChris Fallin /// sense of instructions when pretty-printed, for example. 148a0318f36SChris Fallin vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>, 149d8357426SChris Fallin 15072e6be93SChris Fallin /// Block-order information. 15172e6be93SChris Fallin block_order: BlockLoweringOrder, 152d8357426SChris Fallin 153d8357426SChris Fallin /// ABI object. 1542986f6b0SChris Fallin pub(crate) abi: Callee<I::ABIMachineSpec>, 15508353fccSChris Fallin 156c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 157c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 158c5bbc874SBenjamin Bouvier emit_info: I::Info, 159c5bbc874SBenjamin Bouvier 160a0318f36SChris Fallin /// Reference-typed `regalloc2::VReg`s. The regalloc requires 161a0318f36SChris Fallin /// these in a dense slice (as opposed to querying the 162a0318f36SChris Fallin /// reftype-status of each vreg) for efficient iteration. 163a0318f36SChris Fallin reftyped_vregs: Vec<VReg>, 16408353fccSChris Fallin 16583f182b3SAndrew Brown /// Constants. 1664513d9caSChris Fallin pub(crate) constants: VCodeConstants, 167997fab55SChris Fallin 168a0318f36SChris Fallin /// Value labels for debuginfo attached to vregs. 169a0318f36SChris Fallin debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, 170f18a1f14SNick Fitzgerald 1712986f6b0SChris Fallin pub(crate) sigs: SigSet, 172f466aa26SChris Fallin 173f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code verification. 174f466aa26SChris Fallin facts: Vec<Option<Fact>>, 175d8357426SChris Fallin } 176d8357426SChris Fallin 177a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed 178a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly, 179a0318f36SChris Fallin /// and optionally metadata about the code layout. 18049dd8fd7SAlex Crichton pub struct EmitResult { 181a0318f36SChris Fallin /// The MachBuffer containing the machine code. 18249dd8fd7SAlex Crichton pub buffer: MachBufferFinalized<Stencil>, 183a0318f36SChris Fallin 184a0318f36SChris Fallin /// Offset of each basic block, recorded during emission. Computed 185a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 186a0318f36SChris Fallin pub bb_offsets: Vec<CodeOffset>, 187a0318f36SChris Fallin 188a0318f36SChris Fallin /// Final basic-block edges, in terms of code offsets of 189a0318f36SChris Fallin /// bb-starts. Computed only if `debug_value_labels` is non-empty. 190a0318f36SChris Fallin pub bb_edges: Vec<(CodeOffset, CodeOffset)>, 191a0318f36SChris Fallin 192a0318f36SChris Fallin /// Final length of function body. 193a0318f36SChris Fallin pub func_body_len: CodeOffset, 194a0318f36SChris Fallin 195a0318f36SChris Fallin /// The pretty-printed disassembly, if any. This uses the same 196a0318f36SChris Fallin /// pretty-printing for MachInsts as the pre-regalloc VCode Debug 197a0318f36SChris Fallin /// implementation, but additionally includes the prologue and 198a0318f36SChris Fallin /// epilogue(s), and makes use of the regalloc results. 199a0318f36SChris Fallin pub disasm: Option<String>, 200a0318f36SChris Fallin 2019c43749dSSam Parker /// Offsets of sized stackslots. 2029c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 2039c43749dSSam Parker 2049c43749dSSam Parker /// Offsets of dynamic stackslots. 2059c43749dSSam Parker pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>, 206a0318f36SChris Fallin 207a0318f36SChris Fallin /// Value-labels information (debug metadata). 208a0318f36SChris Fallin pub value_labels_ranges: ValueLabelsRanges, 209a0318f36SChris Fallin 210a0318f36SChris Fallin /// Stack frame size. 211a0318f36SChris Fallin pub frame_size: u32, 212d9d64694SChris Fallin } 213d9d64694SChris Fallin 214a0318f36SChris Fallin /// A builder for a VCode function body. 215d8357426SChris Fallin /// 216a0318f36SChris Fallin /// This builder has the ability to accept instructions in either 217a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that 218a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst> 219a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions 220a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will 221a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine 222a0318f36SChris Fallin /// order. 223a0318f36SChris Fallin /// 224a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the 225a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the 226a0318f36SChris Fallin /// order of construction. Note that this means we do not know the 227a0318f36SChris Fallin /// final block or instruction indices when building, so we do not 228a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending 229a0318f36SChris Fallin /// terminator instructions with successor blocks.) 230d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 231d8357426SChris Fallin /// In-progress VCode. 2322986f6b0SChris Fallin pub(crate) vcode: VCode<I>, 233d8357426SChris Fallin 234a0318f36SChris Fallin /// In what direction is the build occuring? 235a0318f36SChris Fallin direction: VCodeBuildDirection, 23608353fccSChris Fallin 23772e6be93SChris Fallin /// Index of the last block-start in the vcode. 238a0318f36SChris Fallin block_start: usize, 239d8357426SChris Fallin 240d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 241d8357426SChris Fallin succ_start: usize, 242b691770fSChris Fallin 243a0318f36SChris Fallin /// Start of blockparams for the current block in the concatenated 244a0318f36SChris Fallin /// blockparams list. 245a0318f36SChris Fallin block_params_start: usize, 246a0318f36SChris Fallin 247a0318f36SChris Fallin /// Start of successor blockparam arg list entries in 248a0318f36SChris Fallin /// the concatenated branch_block_arg_range list. 249a0318f36SChris Fallin branch_block_arg_succ_start: usize, 250a0318f36SChris Fallin 251a0318f36SChris Fallin /// Debug-value label in-progress map, keyed by label. For each 252a0318f36SChris Fallin /// label, we keep disjoint ranges mapping to vregs. We'll flatten 253a0318f36SChris Fallin /// this into (vreg, range, label) tuples when done. 254a0318f36SChris Fallin debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>, 255a0318f36SChris Fallin } 256a0318f36SChris Fallin 257a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode. 258a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)] 259a0318f36SChris Fallin pub enum VCodeBuildDirection { 260a0318f36SChris Fallin // TODO: add `Forward` once we need it and can test it adequately. 261a0318f36SChris Fallin /// Backward-build pass: we expect the producer to call `emit()` 262a0318f36SChris Fallin /// with instructions in reverse program order within each block. 263a0318f36SChris Fallin Backward, 264d8357426SChris Fallin } 265d8357426SChris Fallin 266d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 267d8357426SChris Fallin /// Create a new VCodeBuilder. 268c5bbc874SBenjamin Bouvier pub fn new( 269f18a1f14SNick Fitzgerald sigs: SigSet, 270f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 271c5bbc874SBenjamin Bouvier emit_info: I::Info, 272c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 27383f182b3SAndrew Brown constants: VCodeConstants, 274a0318f36SChris Fallin direction: VCodeBuildDirection, 275c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 276f18a1f14SNick Fitzgerald let vcode = VCode::new(sigs, abi, emit_info, block_order, constants); 27708353fccSChris Fallin 278d8357426SChris Fallin VCodeBuilder { 279d8357426SChris Fallin vcode, 280a0318f36SChris Fallin direction, 28172e6be93SChris Fallin block_start: 0, 282d8357426SChris Fallin succ_start: 0, 283a0318f36SChris Fallin block_params_start: 0, 284a0318f36SChris Fallin branch_block_arg_succ_start: 0, 285a0318f36SChris Fallin debug_info: FxHashMap::default(), 286d8357426SChris Fallin } 287d8357426SChris Fallin } 288d8357426SChris Fallin 289b6e7cc38SJamey Sharp pub fn init_retval_area(&mut self, vregs: &mut VRegAllocator<I>) -> CodegenResult<()> { 290b6e7cc38SJamey Sharp self.vcode.abi.init_retval_area(&self.vcode.sigs, vregs) 291f18a1f14SNick Fitzgerald } 292f18a1f14SNick Fitzgerald 293d8357426SChris Fallin /// Access the ABI object. 294f18a1f14SNick Fitzgerald pub fn abi(&self) -> &Callee<I::ABIMachineSpec> { 295f18a1f14SNick Fitzgerald &self.vcode.abi 296f18a1f14SNick Fitzgerald } 297f18a1f14SNick Fitzgerald 298f18a1f14SNick Fitzgerald /// Access the ABI object. 299f18a1f14SNick Fitzgerald pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> { 300f0c60f46SNick Fitzgerald &mut self.vcode.abi 301d8357426SChris Fallin } 302d8357426SChris Fallin 303f18a1f14SNick Fitzgerald pub fn sigs(&self) -> &SigSet { 304f18a1f14SNick Fitzgerald &self.vcode.sigs 305f18a1f14SNick Fitzgerald } 306f18a1f14SNick Fitzgerald 307f18a1f14SNick Fitzgerald pub fn sigs_mut(&mut self) -> &mut SigSet { 308f18a1f14SNick Fitzgerald &mut self.vcode.sigs 309f18a1f14SNick Fitzgerald } 310f18a1f14SNick Fitzgerald 31172e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 31272e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 31372e6be93SChris Fallin &self.vcode.block_order 3141d90751bSBenjamin Bouvier } 3151d90751bSBenjamin Bouvier 316d8357426SChris Fallin /// Set the current block as the entry block. 317d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 318d8357426SChris Fallin self.vcode.entry = block; 319d8357426SChris Fallin } 320d8357426SChris Fallin 321d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 322d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 32372e6be93SChris Fallin pub fn end_bb(&mut self) { 32472e6be93SChris Fallin let start_idx = self.block_start; 325a0318f36SChris Fallin let end_idx = self.vcode.insts.len(); 32672e6be93SChris Fallin self.block_start = end_idx; 327d8357426SChris Fallin // Add the instruction index range to the list of blocks. 328a0318f36SChris Fallin self.vcode 329a0318f36SChris Fallin .block_ranges 330a0318f36SChris Fallin .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx))); 331d8357426SChris Fallin // End the successors list. 332a0318f36SChris Fallin let succ_end = self.vcode.block_succs_preds.len(); 333d8357426SChris Fallin self.vcode 334d8357426SChris Fallin .block_succ_range 335a0318f36SChris Fallin .push((self.succ_start as u32, succ_end as u32)); 336d8357426SChris Fallin self.succ_start = succ_end; 337a0318f36SChris Fallin // End the blockparams list. 338a0318f36SChris Fallin let block_params_end = self.vcode.block_params.len(); 339a0318f36SChris Fallin self.vcode 340a0318f36SChris Fallin .block_params_range 341a0318f36SChris Fallin .push((self.block_params_start as u32, block_params_end as u32)); 342a0318f36SChris Fallin self.block_params_start = block_params_end; 343a0318f36SChris Fallin // End the branch blockparam args list. 344a0318f36SChris Fallin let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); 345a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.push(( 346a0318f36SChris Fallin self.branch_block_arg_succ_start as u32, 347a0318f36SChris Fallin branch_block_arg_succ_end as u32, 348a0318f36SChris Fallin )); 349a0318f36SChris Fallin self.branch_block_arg_succ_start = branch_block_arg_succ_end; 350d8357426SChris Fallin } 351d8357426SChris Fallin 352d94173eaSTrevor Elliott pub fn add_block_param(&mut self, param: VirtualReg) { 353a0318f36SChris Fallin self.vcode.block_params.push(param.into()); 354a0318f36SChris Fallin } 355a0318f36SChris Fallin 3565774e068SChris Fallin fn add_branch_args_for_succ(&mut self, args: &[Reg]) { 357a0318f36SChris Fallin let start = self.vcode.branch_block_args.len(); 358a0318f36SChris Fallin self.vcode 359a0318f36SChris Fallin .branch_block_args 360a0318f36SChris Fallin .extend(args.iter().map(|&arg| VReg::from(arg))); 361a0318f36SChris Fallin let end = self.vcode.branch_block_args.len(); 362a0318f36SChris Fallin self.vcode 363a0318f36SChris Fallin .branch_block_arg_range 364a0318f36SChris Fallin .push((start as u32, end as u32)); 365a0318f36SChris Fallin } 366a0318f36SChris Fallin 367a0318f36SChris Fallin /// Push an instruction for the current BB and current IR inst 368a0318f36SChris Fallin /// within the BB. 3693e878837SJamey Sharp pub fn push(&mut self, insn: I, loc: RelSourceLoc) { 37072e6be93SChris Fallin self.vcode.insts.push(insn); 3713e878837SJamey Sharp self.vcode.srclocs.push(loc); 37272e6be93SChris Fallin } 37372e6be93SChris Fallin 3745774e068SChris Fallin /// Add a successor block with branch args. 3755774e068SChris Fallin pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { 3765774e068SChris Fallin self.vcode.block_succs_preds.push(block); 3775774e068SChris Fallin self.add_branch_args_for_succ(args); 3785774e068SChris Fallin } 3795774e068SChris Fallin 380a0318f36SChris Fallin /// Add a debug value label to a register. 381a0318f36SChris Fallin pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { 382a0318f36SChris Fallin // We'll fix up labels in reverse(). Because we're generating 383a0318f36SChris Fallin // code bottom-to-top, the liverange of the label goes *from* 384a0318f36SChris Fallin // the last index at which was defined (or 0, which is the end 385a0318f36SChris Fallin // of the eventual function) *to* just this instruction, and 386a0318f36SChris Fallin // no further. 387a0318f36SChris Fallin let inst = InsnIndex::new(self.vcode.insts.len()); 388a0318f36SChris Fallin let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); 389a0318f36SChris Fallin let last = labels 390a0318f36SChris Fallin .last() 391a0318f36SChris Fallin .map(|(_start, end, _vreg)| *end) 392a0318f36SChris Fallin .unwrap_or(InsnIndex::new(0)); 393a0318f36SChris Fallin labels.push((last, inst, reg.into())); 394a0318f36SChris Fallin } 395a0318f36SChris Fallin 396a0318f36SChris Fallin pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { 397a0318f36SChris Fallin let from = from.into(); 398fef8a90fSChris Fallin let resolved_to = self.vcode.resolve_vreg_alias(to.into()); 399a0318f36SChris Fallin // Disallow cycles (see below). 400a0318f36SChris Fallin assert_ne!(resolved_to, from); 401a0318f36SChris Fallin self.vcode.vreg_aliases.insert(from, resolved_to); 402a0318f36SChris Fallin } 403a0318f36SChris Fallin 40483f182b3SAndrew Brown /// Access the constants. 40583f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 40683f182b3SAndrew Brown &mut self.vcode.constants 40783f182b3SAndrew Brown } 40883f182b3SAndrew Brown 409a0318f36SChris Fallin fn compute_preds_from_succs(&mut self) { 410a0318f36SChris Fallin // Compute predecessors from successors. In order to gather 411a0318f36SChris Fallin // all preds for a block into a contiguous sequence, we build 412a0318f36SChris Fallin // a list of (succ, pred) tuples and then sort. 413a0318f36SChris Fallin let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> = 414a0318f36SChris Fallin Vec::with_capacity(self.vcode.block_succs_preds.len()); 415a0318f36SChris Fallin for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() { 416a0318f36SChris Fallin let pred = BlockIndex::new(pred); 417a0318f36SChris Fallin for i in start..end { 418a0318f36SChris Fallin let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index()); 419a0318f36SChris Fallin succ_pred_edges.push((succ, pred)); 420a0318f36SChris Fallin } 421a0318f36SChris Fallin } 422a0318f36SChris Fallin succ_pred_edges.sort_unstable(); 423a0318f36SChris Fallin 424a0318f36SChris Fallin let mut i = 0; 425a0318f36SChris Fallin for succ in 0..self.vcode.num_blocks() { 426a0318f36SChris Fallin let succ = BlockIndex::new(succ); 427a0318f36SChris Fallin let start = self.vcode.block_succs_preds.len(); 428a0318f36SChris Fallin while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ { 429a0318f36SChris Fallin let pred = succ_pred_edges[i].1; 430a0318f36SChris Fallin self.vcode.block_succs_preds.push(pred); 431a0318f36SChris Fallin i += 1; 432a0318f36SChris Fallin } 433a0318f36SChris Fallin let end = self.vcode.block_succs_preds.len(); 434a0318f36SChris Fallin self.vcode.block_pred_range.push((start as u32, end as u32)); 435d8357426SChris Fallin } 436d8357426SChris Fallin } 437d8357426SChris Fallin 438a0318f36SChris Fallin /// Called once, when a build in Backward order is complete, to 439a0318f36SChris Fallin /// perform the overall reversal (into final forward order) and 440a0318f36SChris Fallin /// finalize metadata accordingly. 441a0318f36SChris Fallin fn reverse_and_finalize(&mut self) { 442a0318f36SChris Fallin let n_insts = self.vcode.insts.len(); 443a0318f36SChris Fallin if n_insts == 0 { 444a0318f36SChris Fallin return; 445a0318f36SChris Fallin } 446a0318f36SChris Fallin 447a0318f36SChris Fallin // Reverse the per-block and per-inst sequences. 448a0318f36SChris Fallin self.vcode.block_ranges.reverse(); 449a0318f36SChris Fallin // block_params_range is indexed by block (and blocks were 450a0318f36SChris Fallin // traversed in reverse) so we reverse it; but block-param 451a0318f36SChris Fallin // sequences in the concatenated vec can remain in reverse 452a0318f36SChris Fallin // order (it is effectively an arena of arbitrarily-placed 453a0318f36SChris Fallin // referenced sequences). 454a0318f36SChris Fallin self.vcode.block_params_range.reverse(); 455a0318f36SChris Fallin // Likewise, we reverse block_succ_range, but the block_succ 456a0318f36SChris Fallin // concatenated array can remain as-is. 457a0318f36SChris Fallin self.vcode.block_succ_range.reverse(); 458a0318f36SChris Fallin self.vcode.insts.reverse(); 459a0318f36SChris Fallin self.vcode.srclocs.reverse(); 460a0318f36SChris Fallin // Likewise, branch_block_arg_succ_range is indexed by block 461a0318f36SChris Fallin // so must be reversed. 462a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.reverse(); 463a0318f36SChris Fallin 464a0318f36SChris Fallin // To translate an instruction index *endpoint* in reversed 465a0318f36SChris Fallin // order to forward order, compute `n_insts - i`. 466a0318f36SChris Fallin // 467a0318f36SChris Fallin // Why not `n_insts - 1 - i`? That would be correct to 468a0318f36SChris Fallin // translate an individual instruction index (for ten insts 0 469a0318f36SChris Fallin // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes 470a0318f36SChris Fallin // 0). But for the usual inclusive-start, exclusive-end range 471a0318f36SChris Fallin // idiom, inclusive starts become exclusive ends and 472a0318f36SChris Fallin // vice-versa, so e.g. an (inclusive) start of 0 becomes an 473a0318f36SChris Fallin // (exclusive) end of 10. 474a0318f36SChris Fallin let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); 475a0318f36SChris Fallin 476a0318f36SChris Fallin // Edit the block-range instruction indices. 477a0318f36SChris Fallin for tuple in &mut self.vcode.block_ranges { 478a0318f36SChris Fallin let (start, end) = *tuple; 479a0318f36SChris Fallin *tuple = (translate(end), translate(start)); // Note reversed order. 480a0318f36SChris Fallin } 481a0318f36SChris Fallin 482a0318f36SChris Fallin // Generate debug-value labels based on per-label maps. 483a0318f36SChris Fallin for (label, tuples) in &self.debug_info { 484a0318f36SChris Fallin for &(start, end, vreg) in tuples { 485fef8a90fSChris Fallin let vreg = self.vcode.resolve_vreg_alias(vreg); 486a0318f36SChris Fallin let fwd_start = translate(end); 487a0318f36SChris Fallin let fwd_end = translate(start); 488a0318f36SChris Fallin self.vcode 489a0318f36SChris Fallin .debug_value_labels 490a0318f36SChris Fallin .push((vreg, fwd_start, fwd_end, label.as_u32())); 491a0318f36SChris Fallin } 492a0318f36SChris Fallin } 493a0318f36SChris Fallin 494a0318f36SChris Fallin // Now sort debug value labels by VReg, as required 495a0318f36SChris Fallin // by regalloc2. 496a0318f36SChris Fallin self.vcode 497a0318f36SChris Fallin .debug_value_labels 498a0318f36SChris Fallin .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); 499a0318f36SChris Fallin } 500a0318f36SChris Fallin 5015c8a603aSUlrich Weigand fn collect_operands(&mut self) { 5024822904dSJamey Sharp let allocatable = PRegSet::from(self.vcode.machine_env()); 503d180b907SJamey Sharp for (i, insn) in self.vcode.insts.iter_mut().enumerate() { 504a0318f36SChris Fallin // Push operands from the instruction onto the operand list. 505a0318f36SChris Fallin // 506a0318f36SChris Fallin // We rename through the vreg alias table as we collect 507a0318f36SChris Fallin // the operands. This is better than a separate post-pass 508a0318f36SChris Fallin // over operands, because it has more cache locality: 509a0318f36SChris Fallin // operands only need to pass through L1 once. This is 510a0318f36SChris Fallin // also better than renaming instructions' 511a0318f36SChris Fallin // operands/registers while lowering, because here we only 512a0318f36SChris Fallin // need to do the `match` over the instruction to visit 513a0318f36SChris Fallin // its register fields (which is slow, branchy code) once. 514a0318f36SChris Fallin 515a0318f36SChris Fallin let vreg_aliases = &self.vcode.vreg_aliases; 516a007e02bSTrevor Elliott let mut op_collector = 517a007e02bSTrevor Elliott OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| { 518fef8a90fSChris Fallin VCode::<I>::resolve_vreg_alias_impl(vreg_aliases, vreg) 519a0318f36SChris Fallin }); 520a0318f36SChris Fallin insn.get_operands(&mut op_collector); 521a0318f36SChris Fallin let (ops, clobbers) = op_collector.finish(); 522a0318f36SChris Fallin self.vcode.operand_ranges.push(ops); 523a0318f36SChris Fallin 524b2e28b91SChris Fallin if clobbers != PRegSet::default() { 525b2e28b91SChris Fallin self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); 526a0318f36SChris Fallin } 527a0318f36SChris Fallin 528a0318f36SChris Fallin if let Some((dst, src)) = insn.is_move() { 529fac4a915STrevor Elliott // We should never see non-virtual registers present in move 530fac4a915STrevor Elliott // instructions. 531fac4a915STrevor Elliott assert!( 532fac4a915STrevor Elliott src.is_virtual(), 533fac4a915STrevor Elliott "the real register {:?} was used as the source of a move instruction", 534fac4a915STrevor Elliott src 535fac4a915STrevor Elliott ); 536fac4a915STrevor Elliott assert!( 537fac4a915STrevor Elliott dst.to_reg().is_virtual(), 538fac4a915STrevor Elliott "the real register {:?} was used as the destination of a move instruction", 539fac4a915STrevor Elliott dst.to_reg() 540fac4a915STrevor Elliott ); 541a0318f36SChris Fallin } 542a0318f36SChris Fallin } 543a0318f36SChris Fallin 544a0318f36SChris Fallin // Translate blockparam args via the vreg aliases table as well. 545a0318f36SChris Fallin for arg in &mut self.vcode.branch_block_args { 546fef8a90fSChris Fallin let new_arg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg); 5478d022434SBenjamin Bouvier trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); 548a0318f36SChris Fallin *arg = new_arg; 549a0318f36SChris Fallin } 550a0318f36SChris Fallin } 551a0318f36SChris Fallin 552a0318f36SChris Fallin /// Build the final VCode. 5535c8a603aSUlrich Weigand pub fn build(mut self, vregs: VRegAllocator<I>) -> VCode<I> { 554d94173eaSTrevor Elliott self.vcode.vreg_types = vregs.vreg_types; 555f466aa26SChris Fallin self.vcode.facts = vregs.facts; 556d94173eaSTrevor Elliott self.vcode.reftyped_vregs = vregs.reftyped_vregs; 557d94173eaSTrevor Elliott 558a0318f36SChris Fallin if self.direction == VCodeBuildDirection::Backward { 559a0318f36SChris Fallin self.reverse_and_finalize(); 560a0318f36SChris Fallin } 5615c8a603aSUlrich Weigand self.collect_operands(); 5622154c63dSAlex Crichton 5632154c63dSAlex Crichton // Apply register aliases to the `reftyped_vregs` list since this list 5642154c63dSAlex Crichton // will be returned directly to `regalloc2` eventually and all 5652154c63dSAlex Crichton // operands/results of instructions will use the alias-resolved vregs 5662154c63dSAlex Crichton // from `regalloc2`'s perspective. 5672127c3a3SAlex Crichton // 5682127c3a3SAlex Crichton // Also note that `reftyped_vregs` can't have duplicates, so after the 5692127c3a3SAlex Crichton // aliases are applied duplicates are removed. 5702154c63dSAlex Crichton for reg in self.vcode.reftyped_vregs.iter_mut() { 571fef8a90fSChris Fallin *reg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg); 5722154c63dSAlex Crichton } 5732127c3a3SAlex Crichton self.vcode.reftyped_vregs.sort(); 5742127c3a3SAlex Crichton self.vcode.reftyped_vregs.dedup(); 5752154c63dSAlex Crichton 576a0318f36SChris Fallin self.compute_preds_from_succs(); 577a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 578d180b907SJamey Sharp 579d180b907SJamey Sharp // All aliases are resolved now, so remove them from the map. 580d180b907SJamey Sharp self.vcode.vreg_aliases.clear(); 581a0318f36SChris Fallin self.vcode 582d8357426SChris Fallin } 583d8357426SChris Fallin } 584d8357426SChris Fallin 58508353fccSChris Fallin /// Is this type a reference type? 58608353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 58726529006SChris Fallin ty == types::R64 || ty == types::R32 58808353fccSChris Fallin } 58908353fccSChris Fallin 590d4a4d4f9SSingleAccretion const NO_INST_OFFSET: CodeOffset = u32::MAX; 591d4a4d4f9SSingleAccretion 592d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 593d8357426SChris Fallin /// New empty VCode. 594c5bbc874SBenjamin Bouvier fn new( 595f18a1f14SNick Fitzgerald sigs: SigSet, 596f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 597c5bbc874SBenjamin Bouvier emit_info: I::Info, 598c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 59983f182b3SAndrew Brown constants: VCodeConstants, 600c5bbc874SBenjamin Bouvier ) -> VCode<I> { 601a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 602d8357426SChris Fallin VCode { 603f18a1f14SNick Fitzgerald sigs, 604d8357426SChris Fallin vreg_types: vec![], 605a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 606a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 607a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 608b2e28b91SChris Fallin clobbers: FxHashMap::default(), 609a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 610a0318f36SChris Fallin entry: BlockIndex::new(0), 611a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 612a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 613a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 614a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 615a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 616a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 617a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 618a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 619a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 62072e6be93SChris Fallin block_order, 621d8357426SChris Fallin abi, 622c5bbc874SBenjamin Bouvier emit_info, 623a0318f36SChris Fallin reftyped_vregs: vec![], 62483f182b3SAndrew Brown constants, 625a0318f36SChris Fallin debug_value_labels: vec![], 626a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 627f466aa26SChris Fallin facts: vec![], 628d8357426SChris Fallin } 629d8357426SChris Fallin } 630d8357426SChris Fallin 6315c8a603aSUlrich Weigand /// Get the ABI-dependent MachineEnv for managing register allocation. 6325c8a603aSUlrich Weigand pub fn machine_env(&self) -> &MachineEnv { 6335c8a603aSUlrich Weigand self.abi.machine_env(&self.sigs) 6345c8a603aSUlrich Weigand } 6355c8a603aSUlrich Weigand 636d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 637d8357426SChris Fallin /// (self.num_blocks() - 1)`. 638d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 639d8357426SChris Fallin self.block_ranges.len() 640d8357426SChris Fallin } 641d8357426SChris Fallin 6426fe69d00SNick Fitzgerald /// The number of lowered instructions. 6436fe69d00SNick Fitzgerald pub fn num_insts(&self) -> usize { 6446fe69d00SNick Fitzgerald self.insts.len() 6456fe69d00SNick Fitzgerald } 6466fe69d00SNick Fitzgerald 647d8357426SChris Fallin /// Get the successors for a block. 648a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 649a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 650a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 651d8357426SChris Fallin } 652d8357426SChris Fallin 653a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 6541a17dfb5SJamey Sharp let mut clobbered = PRegSet::default(); 655d8357426SChris Fallin 656a0318f36SChris Fallin // All moves are included in clobbers. 6571a17dfb5SJamey Sharp for (_, Edit::Move { to, .. }) in ®alloc.edits { 658a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 6591a17dfb5SJamey Sharp clobbered.add(preg); 660a0318f36SChris Fallin } 661d8357426SChris Fallin } 662d8357426SChris Fallin 663a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 664a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 665a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 666a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 667a0318f36SChris Fallin // the current function from clobbers, because by 668a0318f36SChris Fallin // definition everything clobbered by the call can be 669a0318f36SChris Fallin // clobbered by this function without saving as well.) 670a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 671d8357426SChris Fallin continue; 672d8357426SChris Fallin } 673d8357426SChris Fallin 674a0318f36SChris Fallin let start = *start as usize; 675a0318f36SChris Fallin let end = *end as usize; 676a0318f36SChris Fallin let operands = &self.operands[start..end]; 677a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 678a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 6791a17dfb5SJamey Sharp if operand.kind() == OperandKind::Def { 680a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 6811a17dfb5SJamey Sharp clobbered.add(preg); 682a0318f36SChris Fallin } 68308353fccSChris Fallin } 684d8357426SChris Fallin } 685d8357426SChris Fallin 686a0318f36SChris Fallin // Also add explicitly-clobbered registers. 6871a17dfb5SJamey Sharp if let Some(&inst_clobbered) = self.clobbers.get(&InsnIndex::new(i)) { 6881a17dfb5SJamey Sharp clobbered.union_from(inst_clobbered); 689a0318f36SChris Fallin } 690a0318f36SChris Fallin } 691d8357426SChris Fallin 692a0318f36SChris Fallin clobbered 6931a17dfb5SJamey Sharp .into_iter() 6941a17dfb5SJamey Sharp .map(|preg| Writable::from_reg(RealReg::from(preg))) 6951a17dfb5SJamey Sharp .collect() 696d8357426SChris Fallin } 697d8357426SChris Fallin 698a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 699a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 700a0318f36SChris Fallin /// the regalloc results as well. 701a0318f36SChris Fallin /// 702a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 703a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 704a0318f36SChris Fallin /// is consumed by the emission process. 70511a2ef01SChris Fallin pub fn emit( 706a0318f36SChris Fallin mut self, 707a0318f36SChris Fallin regalloc: ®alloc2::Output, 708a0318f36SChris Fallin want_disasm: bool, 70949dd8fd7SAlex Crichton flags: &settings::Flags, 7107eb89140SRemo Senekowitsch ctrl_plane: &mut ControlPlane, 71149dd8fd7SAlex Crichton ) -> EmitResult 712d8357426SChris Fallin where 713f18a1f14SNick Fitzgerald I: VCodeInst, 714d8357426SChris Fallin { 715a0318f36SChris Fallin // To write into disasm string. 716a0318f36SChris Fallin use core::fmt::Write; 717a0318f36SChris Fallin 7182b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 71972e6be93SChris Fallin let mut buffer = MachBuffer::new(); 72011a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 721d8357426SChris Fallin 72249dd8fd7SAlex Crichton // The first M MachLabels are reserved for block indices. 723a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 72449dd8fd7SAlex Crichton 72549dd8fd7SAlex Crichton // Register all allocated constants with the `MachBuffer` to ensure that 72649dd8fd7SAlex Crichton // any references to the constants during instructions can be handled 72749dd8fd7SAlex Crichton // correctly. 72849dd8fd7SAlex Crichton buffer.register_constants(&self.constants); 729d8357426SChris Fallin 730ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 731ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 732ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 733ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 734a0318f36SChris Fallin let block = BlockIndex::new(block); 735ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 736ef1b2d2fSChris Fallin cold_blocks.push(block); 737ef1b2d2fSChris Fallin } else { 738ef1b2d2fSChris Fallin final_order.push(block); 739ef1b2d2fSChris Fallin } 740ef1b2d2fSChris Fallin } 741d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 742ef1b2d2fSChris Fallin 743a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 744a0318f36SChris Fallin // number of spillslots. 745a0318f36SChris Fallin // 746a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 747a0318f36SChris Fallin // generate the prologue and set other info, but we can't 748a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 749a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 750a0318f36SChris Fallin // relatively cheap. 751a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 7525d4e319cSJamey Sharp self.abi 7535d4e319cSJamey Sharp .compute_frame_layout(&self.sigs, regalloc.num_spillslots, clobbers); 754a0318f36SChris Fallin 755ef1b2d2fSChris Fallin // Emit blocks. 756964c6087SChris Fallin let mut cur_srcloc = None; 75711a2ef01SChris Fallin let mut last_offset = None; 758a0318f36SChris Fallin let mut inst_offsets = vec![]; 7597eb89140SRemo Senekowitsch let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane)); 760a0318f36SChris Fallin 761a0318f36SChris Fallin let mut disasm = String::new(); 762a0318f36SChris Fallin 763a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 764d4a4d4f9SSingleAccretion inst_offsets.resize(self.insts.len(), NO_INST_OFFSET); 765a0318f36SChris Fallin } 766a0318f36SChris Fallin 767863659e0SChris Fallin // Count edits per block ahead of time; this is needed for 768863659e0SChris Fallin // lookahead island emission. (We could derive it per-block 769863659e0SChris Fallin // with binary search in the edit list, but it's more 770863659e0SChris Fallin // efficient to do it in one pass here.) 771863659e0SChris Fallin let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; 772863659e0SChris Fallin let mut edit_idx = 0; 773863659e0SChris Fallin for block in 0..self.num_blocks() { 774863659e0SChris Fallin let end_inst = self.block_ranges[block].1; 775863659e0SChris Fallin let start_edit_idx = edit_idx; 776863659e0SChris Fallin while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { 777863659e0SChris Fallin edit_idx += 1; 778863659e0SChris Fallin } 779863659e0SChris Fallin let end_edit_idx = edit_idx; 780863659e0SChris Fallin ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); 781863659e0SChris Fallin } 782863659e0SChris Fallin 783d8b29089SAnton Kirilov let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); 784475d1ba5SAlex Crichton let mut bb_padding = match flags.bb_padding_log2_minus_one() { 78549dd8fd7SAlex Crichton 0 => Vec::new(), 78649dd8fd7SAlex Crichton n => vec![0; 1 << (n - 1)], 78749dd8fd7SAlex Crichton }; 788475d1ba5SAlex Crichton let mut total_bb_padding = 0; 789d8b29089SAnton Kirilov 790863659e0SChris Fallin for (block_order_idx, &block) in final_order.iter().enumerate() { 7918d022434SBenjamin Bouvier trace!("emitting block {:?}", block); 79260e4a004SAfonso Bordado 79360e4a004SAfonso Bordado // Call the new block hook for state 79460e4a004SAfonso Bordado state.on_new_block(); 79560e4a004SAfonso Bordado 79660e4a004SAfonso Bordado // Emit NOPs to align the block. 79772e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 79872e6be93SChris Fallin while new_offset > buffer.cur_offset() { 799d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 80072e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 801a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 802d8357426SChris Fallin } 80372e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 804d8357426SChris Fallin 805a0318f36SChris Fallin let do_emit = |inst: &I, 806a0318f36SChris Fallin allocs: &[Allocation], 807a0318f36SChris Fallin disasm: &mut String, 808a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 809a0318f36SChris Fallin state: &mut I::State| { 8102986f6b0SChris Fallin if want_disasm && !inst.is_args() { 811a0318f36SChris Fallin let mut s = state.clone(); 812a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 813a0318f36SChris Fallin } 814a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 815a0318f36SChris Fallin }; 816a0318f36SChris Fallin 817a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 818a0318f36SChris Fallin if block == self.entry { 8198d022434SBenjamin Bouvier trace!(" -> entry block"); 8208a9b1a90SBenjamin Bouvier buffer.start_srcloc(Default::default()); 82186652959SUlrich Weigand for inst in &self.abi.gen_prologue() { 822a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 823a0318f36SChris Fallin } 824a0318f36SChris Fallin buffer.end_srcloc(); 825d9d64694SChris Fallin } 826d9d64694SChris Fallin 827a0318f36SChris Fallin // Now emit the regular block body. 82811a2ef01SChris Fallin 8297eb89140SRemo Senekowitsch buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut()); 830a0318f36SChris Fallin 831a0318f36SChris Fallin if want_disasm { 832a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 833a0318f36SChris Fallin } 834a0318f36SChris Fallin 83549dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 83611a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 83711a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 83811a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 83911a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 84011a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 84111a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 84211a2ef01SChris Fallin break; 84311a2ef01SChris Fallin } 84411a2ef01SChris Fallin bb_starts[i] = None; 84511a2ef01SChris Fallin } 84611a2ef01SChris Fallin } 84711a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 84811a2ef01SChris Fallin last_offset = Some(cur_offset); 849800cf25bSChris Fallin } 85011a2ef01SChris Fallin 851d8b29089SAnton Kirilov if let Some(block_start) = I::gen_block_start( 852d8b29089SAnton Kirilov self.block_order.is_indirect_branch_target(block), 853d8b29089SAnton Kirilov is_forward_edge_cfi_enabled, 854d8b29089SAnton Kirilov ) { 855d8b29089SAnton Kirilov do_emit(&block_start, &[], &mut disasm, &mut buffer, &mut state); 856d8b29089SAnton Kirilov } 857d8b29089SAnton Kirilov 858a0318f36SChris Fallin for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { 859a0318f36SChris Fallin match inst_or_edit { 860a0318f36SChris Fallin InstOrEdit::Inst(iix) => { 861a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 862a0318f36SChris Fallin // If we need to produce debug info, 863a0318f36SChris Fallin // record the offset of each instruction 864a0318f36SChris Fallin // so that we can translate value-label 865a0318f36SChris Fallin // ranges to machine-code offsets. 866a0318f36SChris Fallin 867a0318f36SChris Fallin // Cold blocks violate monotonicity 868a0318f36SChris Fallin // assumptions elsewhere (that 869a0318f36SChris Fallin // instructions in inst-index order are in 870a0318f36SChris Fallin // order in machine code), so we omit 871a0318f36SChris Fallin // their offsets here. Value-label range 872a0318f36SChris Fallin // generation below will skip empty ranges 873a0318f36SChris Fallin // and ranges with to-offsets of zero. 874a0318f36SChris Fallin if !self.block_order.is_cold(block) { 875a0318f36SChris Fallin inst_offsets[iix.index()] = buffer.cur_offset(); 876a0318f36SChris Fallin } 877a0318f36SChris Fallin } 878a0318f36SChris Fallin 879a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 880a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 881964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 882964c6087SChris Fallin if cur_srcloc.is_some() { 88372e6be93SChris Fallin buffer.end_srcloc(); 884b691770fSChris Fallin } 88572e6be93SChris Fallin buffer.start_srcloc(srcloc); 886964c6087SChris Fallin cur_srcloc = Some(srcloc); 887b691770fSChris Fallin } 888b691770fSChris Fallin 889a0318f36SChris Fallin // If this is a safepoint, compute a stack map 890a0318f36SChris Fallin // and pass it to the emit state. 891a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 892a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 893a0318f36SChris Fallin // Find the contiguous range of 894a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 895a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 896a0318f36SChris Fallin // for this instruction index. 897a0318f36SChris Fallin let safepoint_slots_start = regalloc 898a0318f36SChris Fallin .safepoint_slots 899a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 900a0318f36SChris Fallin if progpoint.inst() >= iix { 901a0318f36SChris Fallin std::cmp::Ordering::Greater 902a0318f36SChris Fallin } else { 903a0318f36SChris Fallin std::cmp::Ordering::Less 904a0318f36SChris Fallin } 905a0318f36SChris Fallin }) 906a0318f36SChris Fallin .unwrap_err(); 907a0318f36SChris Fallin 908a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 909a0318f36SChris Fallin .iter() 910a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 911a0318f36SChris Fallin { 912a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 913a0318f36SChris Fallin safepoint_slots.push(slot); 914a0318f36SChris Fallin } 915a0318f36SChris Fallin if !safepoint_slots.is_empty() { 916666c2554SChris Fallin let stack_map = self 917666c2554SChris Fallin .abi 918a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 91905bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 92008353fccSChris Fallin } 921a0318f36SChris Fallin } 92208353fccSChris Fallin 923a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 924a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 925de4af90aSYury Delendik 926a0318f36SChris Fallin // If the instruction we are about to emit is 927a0318f36SChris Fallin // a return, place an epilogue at this point 928a0318f36SChris Fallin // (and don't emit the return; the actual 929a0318f36SChris Fallin // epilogue will contain it). 930a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 93186652959SUlrich Weigand for inst in self.abi.gen_epilogue() { 932a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 933a0318f36SChris Fallin } 934c84d6be6SChris Fallin } else { 935a0318f36SChris Fallin // Emit the instruction! 936a0318f36SChris Fallin do_emit( 937a0318f36SChris Fallin &self.insts[iix.index()], 938a0318f36SChris Fallin allocs, 939a0318f36SChris Fallin &mut disasm, 940a0318f36SChris Fallin &mut buffer, 941a0318f36SChris Fallin &mut state, 942a0318f36SChris Fallin ); 943c84d6be6SChris Fallin } 944c84d6be6SChris Fallin } 945a0318f36SChris Fallin 946a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 947a0318f36SChris Fallin // Create a move/spill/reload instruction and 948a0318f36SChris Fallin // immediately emit it. 949a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 950a0318f36SChris Fallin (Some(from), Some(to)) => { 951a0318f36SChris Fallin // Reg-to-reg move. 952a0318f36SChris Fallin let from_rreg = Reg::from(from); 953a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 954a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 955a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 956a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 957a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 958a0318f36SChris Fallin } 959a0318f36SChris Fallin (Some(from), None) => { 960a0318f36SChris Fallin // Spill from register to spillslot. 961a0318f36SChris Fallin let to = to.as_stack().unwrap(); 962a0318f36SChris Fallin let from_rreg = RealReg::from(from); 963a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 964a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 965a0318f36SChris Fallin } 966a0318f36SChris Fallin (None, Some(to)) => { 967a0318f36SChris Fallin // Load from spillslot to register. 968a0318f36SChris Fallin let from = from.as_stack().unwrap(); 969a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 970a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 971a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 972a0318f36SChris Fallin } 973a0318f36SChris Fallin (None, None) => { 974a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 975a0318f36SChris Fallin } 976a0318f36SChris Fallin } 977a0318f36SChris Fallin } 978c84d6be6SChris Fallin } 979d8357426SChris Fallin } 980b691770fSChris Fallin 981964c6087SChris Fallin if cur_srcloc.is_some() { 98272e6be93SChris Fallin buffer.end_srcloc(); 983964c6087SChris Fallin cur_srcloc = None; 984b691770fSChris Fallin } 98572e6be93SChris Fallin 98649dd8fd7SAlex Crichton // Do we need an island? Get the worst-case size of the next BB, add 98749dd8fd7SAlex Crichton // it to the optional padding behind the block, and pass this to the 98849dd8fd7SAlex Crichton // `MachBuffer` to determine if an island is necessary. 98949dd8fd7SAlex Crichton let worst_case_next_bb = if block_order_idx < final_order.len() - 1 { 990863659e0SChris Fallin let next_block = final_order[block_order_idx + 1]; 991863659e0SChris Fallin let next_block_range = self.block_ranges[next_block.index()]; 992863659e0SChris Fallin let next_block_size = 993863659e0SChris Fallin (next_block_range.1.index() - next_block_range.0.index()) as u32; 994863659e0SChris Fallin let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; 99549dd8fd7SAlex Crichton I::worst_case_size() * (next_block_size + next_block_ra_insertions) 99649dd8fd7SAlex Crichton } else { 99749dd8fd7SAlex Crichton 0 99849dd8fd7SAlex Crichton }; 99949dd8fd7SAlex Crichton let padding = if bb_padding.is_empty() { 100049dd8fd7SAlex Crichton 0 100149dd8fd7SAlex Crichton } else { 100249dd8fd7SAlex Crichton bb_padding.len() as u32 + I::LabelUse::ALIGN - 1 100349dd8fd7SAlex Crichton }; 100449dd8fd7SAlex Crichton if buffer.island_needed(padding + worst_case_next_bb) { 1005f8c03d5aSAlex Crichton buffer.emit_island(padding + worst_case_next_bb, ctrl_plane); 100672e6be93SChris Fallin } 100749dd8fd7SAlex Crichton 100849dd8fd7SAlex Crichton // Insert padding, if configured, to stress the `MachBuffer`'s 100949dd8fd7SAlex Crichton // relocation and island calculations. 1010475d1ba5SAlex Crichton // 1011475d1ba5SAlex Crichton // Padding can get quite large during fuzzing though so place a 1012475d1ba5SAlex Crichton // total cap on it where when a per-function threshold is exceeded 1013475d1ba5SAlex Crichton // the padding is turned back down to zero. This avoids a small-ish 1014475d1ba5SAlex Crichton // test case generating a GB+ memory footprint in Cranelift for 1015475d1ba5SAlex Crichton // example. 101649dd8fd7SAlex Crichton if !bb_padding.is_empty() { 101749dd8fd7SAlex Crichton buffer.put_data(&bb_padding); 101849dd8fd7SAlex Crichton buffer.align_to(I::LabelUse::ALIGN); 1019475d1ba5SAlex Crichton total_bb_padding += bb_padding.len(); 1020475d1ba5SAlex Crichton if total_bb_padding > (150 << 20) { 1021475d1ba5SAlex Crichton bb_padding = Vec::new(); 1022475d1ba5SAlex Crichton } 102372e6be93SChris Fallin } 1024d8357426SChris Fallin } 1025d8357426SChris Fallin 1026d4a4d4f9SSingleAccretion // Do any optimizations on branches at tail of buffer, as if we had 1027d4a4d4f9SSingleAccretion // bound one last label. 1028d4a4d4f9SSingleAccretion buffer.optimize_branches(ctrl_plane); 1029d4a4d4f9SSingleAccretion 10307eb89140SRemo Senekowitsch // emission state is not needed anymore, move control plane back out 10317eb89140SRemo Senekowitsch *ctrl_plane = state.take_ctrl_plane(); 10327eb89140SRemo Senekowitsch 1033a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1034de4af90aSYury Delendik 103511a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 103611a2ef01SChris Fallin let mut bb_edges = vec![]; 1037a0318f36SChris Fallin let mut bb_offsets = vec![]; 103849dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 103911a2ef01SChris Fallin for block in 0..self.num_blocks() { 104011a2ef01SChris Fallin if bb_starts[block].is_none() { 104111a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 104211a2ef01SChris Fallin continue; 104311a2ef01SChris Fallin } 104411a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 104511a2ef01SChris Fallin 1046a0318f36SChris Fallin bb_offsets.push(from); 104711a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1048a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1049a0318f36SChris Fallin for &succ in succs.iter() { 1050a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 105111a2ef01SChris Fallin bb_edges.push((from, to)); 105211a2ef01SChris Fallin } 105311a2ef01SChris Fallin } 1054800cf25bSChris Fallin } 105511a2ef01SChris Fallin 1056d4a4d4f9SSingleAccretion self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len); 1057a0318f36SChris Fallin let value_labels_ranges = 1058a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1059a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1060a0318f36SChris Fallin 1061a0318f36SChris Fallin EmitResult { 106249dd8fd7SAlex Crichton buffer: buffer.finish(&self.constants, ctrl_plane), 1063a0318f36SChris Fallin bb_offsets, 1064a0318f36SChris Fallin bb_edges, 1065a0318f36SChris Fallin func_body_len, 1066a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10679c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10689c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1069a0318f36SChris Fallin value_labels_ranges, 1070a0318f36SChris Fallin frame_size, 1071a0318f36SChris Fallin } 1072d8357426SChris Fallin } 1073d8357426SChris Fallin 1074d4a4d4f9SSingleAccretion fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) { 1075d4a4d4f9SSingleAccretion if self.debug_value_labels.is_empty() { 1076d4a4d4f9SSingleAccretion return; 1077d4a4d4f9SSingleAccretion } 1078d4a4d4f9SSingleAccretion 1079d4a4d4f9SSingleAccretion // During emission, branch removal can make offsets of instructions incorrect. 1080d4a4d4f9SSingleAccretion // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj] 1081d4a4d4f9SSingleAccretion // It will be recorded as (say): [30] [34] [38] [42] [<would be 46>] 1082d4a4d4f9SSingleAccretion // When the jumps get removed we are left with (in "inst_offsets"): 1083d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1084d4a4d4f9SSingleAccretion // [30] [34] [38] [42] [34] 1085d4a4d4f9SSingleAccretion // Which violates the monotonicity invariant. This method sets offsets of these 1086d4a4d4f9SSingleAccretion // removed instructions such as to make them appear zero-sized: 1087d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1088d4a4d4f9SSingleAccretion // [30] [34] [34] [34] [34] 1089d4a4d4f9SSingleAccretion // 1090d4a4d4f9SSingleAccretion let mut next_offset = func_body_len; 1091d4a4d4f9SSingleAccretion for inst_index in (0..(inst_offsets.len() - 1)).rev() { 1092d4a4d4f9SSingleAccretion let inst_offset = inst_offsets[inst_index]; 1093d4a4d4f9SSingleAccretion 1094d4a4d4f9SSingleAccretion // Not all instructions get their offsets recorded. 1095d4a4d4f9SSingleAccretion if inst_offset == NO_INST_OFFSET { 1096d4a4d4f9SSingleAccretion continue; 1097d4a4d4f9SSingleAccretion } 1098d4a4d4f9SSingleAccretion 1099d4a4d4f9SSingleAccretion if inst_offset > next_offset { 1100d4a4d4f9SSingleAccretion trace!( 1101d4a4d4f9SSingleAccretion "Fixing code offset of the removed Inst {}: {} -> {}", 1102d4a4d4f9SSingleAccretion inst_index, 1103d4a4d4f9SSingleAccretion inst_offset, 1104d4a4d4f9SSingleAccretion next_offset 1105d4a4d4f9SSingleAccretion ); 1106d4a4d4f9SSingleAccretion inst_offsets[inst_index] = next_offset; 1107d4a4d4f9SSingleAccretion continue; 1108d4a4d4f9SSingleAccretion } 1109d4a4d4f9SSingleAccretion 1110d4a4d4f9SSingleAccretion next_offset = inst_offset; 1111d4a4d4f9SSingleAccretion } 1112d4a4d4f9SSingleAccretion } 1113d4a4d4f9SSingleAccretion 1114a0318f36SChris Fallin fn compute_value_labels_ranges( 1115a0318f36SChris Fallin &self, 1116a0318f36SChris Fallin regalloc: ®alloc2::Output, 1117a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1118a0318f36SChris Fallin func_body_len: u32, 1119a0318f36SChris Fallin ) -> ValueLabelsRanges { 1120a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1121602006ffSbjorn3 return ValueLabelsRanges::default(); 1122997fab55SChris Fallin } 1123997fab55SChris Fallin 1124a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1125a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1126a0318f36SChris Fallin let ranges = value_labels_ranges 1127a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1128a0318f36SChris Fallin .or_insert_with(|| vec![]); 1129a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1130a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1131a0318f36SChris Fallin func_body_len 1132a0318f36SChris Fallin } else { 1133a0318f36SChris Fallin inst_offsets[to.inst().index()] 1134a0318f36SChris Fallin }; 1135a0318f36SChris Fallin 1136d4a4d4f9SSingleAccretion // Empty ranges or unavailable offsets can happen 1137d4a4d4f9SSingleAccretion // due to cold blocks and branch removal (see above). 1138d4a4d4f9SSingleAccretion if from_offset == NO_INST_OFFSET 1139d4a4d4f9SSingleAccretion || to_offset == NO_INST_OFFSET 1140d4a4d4f9SSingleAccretion || from_offset == to_offset 1141d4a4d4f9SSingleAccretion { 1142a0318f36SChris Fallin continue; 114376d61504Sbjorn3 } 114476d61504Sbjorn3 1145a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1146a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1147a0318f36SChris Fallin } else { 11487b16eccdSSingleAccretion let slot = alloc.as_stack().unwrap(); 11497b16eccdSSingleAccretion let sp_offset = self.abi.get_spillslot_offset(slot); 11507b16eccdSSingleAccretion let sp_to_caller_sp_offset = self.abi.nominal_sp_to_caller_sp_offset(); 11517b16eccdSSingleAccretion let caller_sp_to_cfa_offset = 11527b16eccdSSingleAccretion crate::isa::unwind::systemv::caller_sp_to_cfa_offset(); 11537b16eccdSSingleAccretion let cfa_to_sp_offset = -((sp_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64); 11547b16eccdSSingleAccretion LabelValueLoc::CFAOffset(cfa_to_sp_offset + sp_offset) 1155a0318f36SChris Fallin }; 1156a0318f36SChris Fallin 1157a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1158a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1159a0318f36SChris Fallin // instruction; that is the same as the end of another 1160a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1161a0318f36SChris Fallin // we are past the previous instruction's end. 1162d4a4d4f9SSingleAccretion let start = from_offset + 1; 1163d4a4d4f9SSingleAccretion 1164a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1165a0318f36SChris Fallin // *include* the end of the last 1166a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1167a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1168a0318f36SChris Fallin // the first instruction not covered. That 1169a0318f36SChris Fallin // instruction's start is the same as the end of the 1170a0318f36SChris Fallin // last instruction that is included, so we go one 1171a0318f36SChris Fallin // byte further to be sure to include it. 1172d4a4d4f9SSingleAccretion let end = to_offset + 1; 1173d4a4d4f9SSingleAccretion 11747b16eccdSSingleAccretion // Coalesce adjacent ranges that for the same location 11757b16eccdSSingleAccretion // to minimize output size here and for the consumers. 11767b16eccdSSingleAccretion if let Some(last_loc_range) = ranges.last_mut() { 11777b16eccdSSingleAccretion if last_loc_range.loc == loc && last_loc_range.end == start { 11787b16eccdSSingleAccretion trace!( 11797b16eccdSSingleAccretion "Extending debug range for VL{} in {:?} to {}", 11807b16eccdSSingleAccretion label, 11817b16eccdSSingleAccretion loc, 11827b16eccdSSingleAccretion end 11837b16eccdSSingleAccretion ); 11847b16eccdSSingleAccretion last_loc_range.end = end; 11857b16eccdSSingleAccretion continue; 11867b16eccdSSingleAccretion } 11877b16eccdSSingleAccretion } 11887b16eccdSSingleAccretion 1189d4a4d4f9SSingleAccretion trace!( 1190d4a4d4f9SSingleAccretion "Recording debug range for VL{} in {:?}: [Inst {}..Inst {}) [{}..{})", 1191d4a4d4f9SSingleAccretion label, 1192d4a4d4f9SSingleAccretion loc, 1193d4a4d4f9SSingleAccretion from.inst().index(), 1194d4a4d4f9SSingleAccretion to.inst().index(), 1195d4a4d4f9SSingleAccretion start, 1196d4a4d4f9SSingleAccretion end 1197d4a4d4f9SSingleAccretion ); 1198d4a4d4f9SSingleAccretion 1199d4a4d4f9SSingleAccretion ranges.push(ValueLocRange { loc, start, end }); 1200a0318f36SChris Fallin } 1201a0318f36SChris Fallin 1202a0318f36SChris Fallin value_labels_ranges 1203c84d6be6SChris Fallin } 1204c84d6be6SChris Fallin 1205d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1206d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1207a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1208d8357426SChris Fallin } 12092154c63dSAlex Crichton 12106397f388SJamey Sharp fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 1211fef8a90fSChris Fallin Self::resolve_vreg_alias_impl(&self.vreg_aliases, from) 1212fef8a90fSChris Fallin } 1213fef8a90fSChris Fallin 1214fef8a90fSChris Fallin /// Implementation of alias resolution. Separate helper that does 1215fef8a90fSChris Fallin /// not borrow `self` in order to allow working around borrowing 1216fef8a90fSChris Fallin /// restrictions. 1217fef8a90fSChris Fallin fn resolve_vreg_alias_impl( 1218fef8a90fSChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 1219fef8a90fSChris Fallin from: regalloc2::VReg, 1220fef8a90fSChris Fallin ) -> regalloc2::VReg { 1221fef8a90fSChris Fallin // We prevent cycles from existing by resolving targets of 1222fef8a90fSChris Fallin // aliases eagerly before setting them. If the target resolves 1223fef8a90fSChris Fallin // to the origin of the alias, then a cycle would be created 1224fef8a90fSChris Fallin // and the alias is disallowed. Because of the structure of 1225fef8a90fSChris Fallin // SSA code (one instruction can refer to another's defs but 1226fef8a90fSChris Fallin // not vice-versa, except indirectly through 1227fef8a90fSChris Fallin // phis/blockparams), cycles should not occur as we use 1228fef8a90fSChris Fallin // aliases to redirect vregs to the temps that actually define 1229fef8a90fSChris Fallin // them. 1230fef8a90fSChris Fallin 1231fef8a90fSChris Fallin let mut vreg = from; 1232fef8a90fSChris Fallin while let Some(to) = aliases.get(&vreg) { 1233fef8a90fSChris Fallin vreg = *to; 1234fef8a90fSChris Fallin } 1235fef8a90fSChris Fallin vreg 1236fef8a90fSChris Fallin } 1237fef8a90fSChris Fallin 12382154c63dSAlex Crichton #[inline] 123970d2a26eSJamey Sharp fn debug_assert_no_vreg_aliases(&self, mut list: impl Iterator<Item = VReg>) { 124070d2a26eSJamey Sharp debug_assert!(list.all(|vreg| !self.vreg_aliases.contains_key(&vreg))); 12412154c63dSAlex Crichton } 1242f466aa26SChris Fallin 12439e4d4462SChris Fallin /// Get the type of a VReg. 12449e4d4462SChris Fallin pub fn vreg_type(&self, vreg: VReg) -> Type { 12459e4d4462SChris Fallin self.vreg_types[vreg.vreg()] 12469e4d4462SChris Fallin } 12479e4d4462SChris Fallin 1248f466aa26SChris Fallin /// Get the fact, if any, for a given VReg. 1249f466aa26SChris Fallin pub fn vreg_fact(&self, vreg: VReg) -> Option<&Fact> { 1250d180b907SJamey Sharp self.debug_assert_no_vreg_aliases(core::iter::once(vreg)); 12519e4d4462SChris Fallin self.facts[vreg.vreg()].as_ref() 1252f466aa26SChris Fallin } 1253f466aa26SChris Fallin 12548d19280aSChris Fallin /// Set the fact for a given VReg. 12558d19280aSChris Fallin pub fn set_vreg_fact(&mut self, vreg: VReg, fact: Fact) { 1256d180b907SJamey Sharp self.debug_assert_no_vreg_aliases(core::iter::once(vreg)); 1257f262c311SChris Fallin trace!("set fact on {}: {:?}", vreg, fact); 12588d19280aSChris Fallin self.facts[vreg.vreg()] = Some(fact); 12598d19280aSChris Fallin } 12608d19280aSChris Fallin 1261f466aa26SChris Fallin /// Does a given instruction define any facts? 1262f466aa26SChris Fallin pub fn inst_defines_facts(&self, inst: InsnIndex) -> bool { 1263f466aa26SChris Fallin self.inst_operands(inst) 1264f466aa26SChris Fallin .iter() 1265f466aa26SChris Fallin .filter(|o| o.kind() == OperandKind::Def) 1266f466aa26SChris Fallin .map(|o| o.vreg()) 12672e7f9414SChris Fallin .any(|vreg| self.facts[vreg.vreg()].is_some()) 1268f466aa26SChris Fallin } 1269f466aa26SChris Fallin } 1270f466aa26SChris Fallin 1271f466aa26SChris Fallin impl<I: VCodeInst> std::ops::Index<InsnIndex> for VCode<I> { 1272f466aa26SChris Fallin type Output = I; 1273f466aa26SChris Fallin fn index(&self, idx: InsnIndex) -> &Self::Output { 1274f466aa26SChris Fallin &self.insts[idx.index()] 1275f466aa26SChris Fallin } 1276d8357426SChris Fallin } 1277d8357426SChris Fallin 1278d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1279a0318f36SChris Fallin fn num_insts(&self) -> usize { 1280a0318f36SChris Fallin self.insts.len() 1281d8357426SChris Fallin } 1282d8357426SChris Fallin 1283a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1284a0318f36SChris Fallin self.block_ranges.len() 1285d8357426SChris Fallin } 1286d8357426SChris Fallin 1287a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1288a0318f36SChris Fallin self.entry 1289d8357426SChris Fallin } 1290d8357426SChris Fallin 1291a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1292a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1293a0318f36SChris Fallin InstRange::forward(start, end) 1294d8357426SChris Fallin } 1295d8357426SChris Fallin 1296a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1297a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1298a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1299d8357426SChris Fallin } 1300d8357426SChris Fallin 1301a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1302a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1303a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1304d8357426SChris Fallin } 1305d8357426SChris Fallin 1306a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1307c5379051STrevor Elliott // As a special case we don't return block params for the entry block, as all the arguments 1308c5379051STrevor Elliott // will be defined by the `Inst::Args` instruction. 1309c5379051STrevor Elliott if block == self.entry { 1310c5379051STrevor Elliott return &[]; 1311c5379051STrevor Elliott } 1312c5379051STrevor Elliott 1313a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 13142154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 13152154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 13162154c63dSAlex Crichton // double-check just to be sure. 131770d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 131870d2a26eSJamey Sharp ret 1319d8357426SChris Fallin } 1320d8357426SChris Fallin 1321a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1322a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1323a0318f36SChris Fallin let succ_ranges = 1324a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1325a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 13262154c63dSAlex Crichton let ret = &self.branch_block_args 13272154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 132870d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 132970d2a26eSJamey Sharp ret 1330d8357426SChris Fallin } 1331d8357426SChris Fallin 1332a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1333a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1334c5379051STrevor Elliott // We treat blocks terminated by an unconditional trap like a return for regalloc. 1335c5379051STrevor Elliott MachTerminator::None => self.insts[insn.index()].is_trap(), 13364154fa47SNick Fitzgerald MachTerminator::Ret | MachTerminator::RetCall => true, 13374154fa47SNick Fitzgerald MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false, 1338d8357426SChris Fallin } 1339d8357426SChris Fallin } 1340d8357426SChris Fallin 1341a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1342a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 13435774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1344a0318f36SChris Fallin _ => false, 1345a0318f36SChris Fallin } 134671768bb6SChris Fallin } 134771768bb6SChris Fallin 1348a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1349a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1350d8357426SChris Fallin } 1351d8357426SChris Fallin 1352a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1353a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 13542154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 135570d2a26eSJamey Sharp // It should be true by construction that `Operand`s do not contain any 135670d2a26eSJamey Sharp // aliased vregs since they're all collected and mapped when the VCode 135770d2a26eSJamey Sharp // is itself constructed. 135870d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|op| op.vreg())); 13592154c63dSAlex Crichton ret 1360d8357426SChris Fallin } 1361d8357426SChris Fallin 1362b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1363b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1364be6f060aSChris Fallin } 1365be6f060aSChris Fallin 1366a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1367b1307638SJamey Sharp self.vreg_types.len() 1368d8357426SChris Fallin } 1369d8357426SChris Fallin 1370a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 137170d2a26eSJamey Sharp let ret = &self.reftyped_vregs; 137270d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().copied()); 137370d2a26eSJamey Sharp ret 1374d8357426SChris Fallin } 1375d8357426SChris Fallin 1376a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 13772154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 137870d2a26eSJamey Sharp // generated and aliases are fully defined, so double-check that 13792154c63dSAlex Crichton // aliases are not lingering. 138070d2a26eSJamey Sharp let ret = &self.debug_value_labels; 138170d2a26eSJamey Sharp self.debug_assert_no_vreg_aliases(ret.iter().map(|&(vreg, ..)| vreg)); 138270d2a26eSJamey Sharp ret 1383d8357426SChris Fallin } 1384d8357426SChris Fallin 1385a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1386a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1387d8357426SChris Fallin } 1388d8357426SChris Fallin 1389a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1390a0318f36SChris Fallin // At least the s390x backend requires this, because the 1391a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1392a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1393a0318f36SChris Fallin true 1394d8357426SChris Fallin } 1395d8357426SChris Fallin } 1396d8357426SChris Fallin 1397d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1398d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1399a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1400a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1401a0318f36SChris Fallin 1402a0318f36SChris Fallin let mut state = Default::default(); 1403a0318f36SChris Fallin 1404a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1405a0318f36SChris Fallin alias_keys.sort_unstable(); 1406a0318f36SChris Fallin for key in alias_keys { 1407a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1408a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1409a0318f36SChris Fallin } 1410d8357426SChris Fallin 1411d8357426SChris Fallin for block in 0..self.num_blocks() { 1412a0318f36SChris Fallin let block = BlockIndex::new(block); 1413a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1414a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1415a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1416d8357426SChris Fallin } 1417a0318f36SChris Fallin for succ in self.succs(block) { 1418a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1419a0318f36SChris Fallin } 1420a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1421a0318f36SChris Fallin writeln!( 1422a0318f36SChris Fallin f, 1423a0318f36SChris Fallin " (instruction range: {} .. {})", 1424a0318f36SChris Fallin start.index(), 1425a0318f36SChris Fallin end.index() 1426a0318f36SChris Fallin )?; 1427a0318f36SChris Fallin for inst in start.index()..end.index() { 1428a0318f36SChris Fallin writeln!( 1429a0318f36SChris Fallin f, 1430a0318f36SChris Fallin " Inst {}: {}", 1431a0318f36SChris Fallin inst, 1432a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1433a0318f36SChris Fallin )?; 1434f466aa26SChris Fallin for operand in self.inst_operands(InsnIndex::new(inst)) { 1435f466aa26SChris Fallin if operand.kind() == OperandKind::Def { 1436f466aa26SChris Fallin if let Some(fact) = &self.facts[operand.vreg().vreg()] { 1437fef8a90fSChris Fallin writeln!(f, " v{} ! {}", operand.vreg().vreg(), fact)?; 1438f466aa26SChris Fallin } 1439f466aa26SChris Fallin } 1440f466aa26SChris Fallin } 1441d8357426SChris Fallin } 1442d8357426SChris Fallin } 1443d8357426SChris Fallin 1444d8357426SChris Fallin writeln!(f, "}}")?; 1445d8357426SChris Fallin Ok(()) 1446d8357426SChris Fallin } 1447d8357426SChris Fallin } 1448d8357426SChris Fallin 1449d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder. 1450d94173eaSTrevor Elliott pub struct VRegAllocator<I> { 1451d94173eaSTrevor Elliott /// VReg IR-level types. 1452d94173eaSTrevor Elliott vreg_types: Vec<Type>, 1453d94173eaSTrevor Elliott 1454d94173eaSTrevor Elliott /// Reference-typed `regalloc2::VReg`s. The regalloc requires 1455d94173eaSTrevor Elliott /// these in a dense slice (as opposed to querying the 1456d94173eaSTrevor Elliott /// reftype-status of each vreg) for efficient iteration. 1457d94173eaSTrevor Elliott reftyped_vregs: Vec<VReg>, 1458d94173eaSTrevor Elliott 145917eeba0eSChris Fallin /// A deferred error, to be bubbled up to the top level of the 146017eeba0eSChris Fallin /// lowering algorithm. We take this approach because we cannot 146117eeba0eSChris Fallin /// currently propagate a `Result` upward through ISLE code (the 146217eeba0eSChris Fallin /// lowering rules) or some ABI code. 146317eeba0eSChris Fallin deferred_error: Option<CodegenError>, 146417eeba0eSChris Fallin 1465f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code. 1466f466aa26SChris Fallin facts: Vec<Option<Fact>>, 1467f466aa26SChris Fallin 1468d94173eaSTrevor Elliott /// The type of instruction that this allocator makes registers for. 1469d94173eaSTrevor Elliott _inst: core::marker::PhantomData<I>, 1470d94173eaSTrevor Elliott } 1471d94173eaSTrevor Elliott 1472d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> { 1473d94173eaSTrevor Elliott /// Make a new VRegAllocator. 1474d94173eaSTrevor Elliott pub fn new() -> Self { 1475d94173eaSTrevor Elliott Self { 1476b1307638SJamey Sharp vreg_types: vec![types::INVALID; first_user_vreg_index()], 1477f466aa26SChris Fallin facts: vec![], 1478d94173eaSTrevor Elliott reftyped_vregs: vec![], 147917eeba0eSChris Fallin deferred_error: None, 1480d94173eaSTrevor Elliott _inst: core::marker::PhantomData::default(), 1481d94173eaSTrevor Elliott } 1482d94173eaSTrevor Elliott } 1483d94173eaSTrevor Elliott 1484d94173eaSTrevor Elliott /// Allocate a fresh ValueRegs. 1485d94173eaSTrevor Elliott pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> { 148617eeba0eSChris Fallin if self.deferred_error.is_some() { 148717eeba0eSChris Fallin return Err(CodegenError::CodeTooLarge); 148817eeba0eSChris Fallin } 1489b1307638SJamey Sharp let v = self.vreg_types.len(); 1490d94173eaSTrevor Elliott let (regclasses, tys) = I::rc_for_type(ty)?; 1491b1307638SJamey Sharp if v + regclasses.len() >= VReg::MAX { 1492d94173eaSTrevor Elliott return Err(CodegenError::CodeTooLarge); 1493d94173eaSTrevor Elliott } 1494d94173eaSTrevor Elliott 1495d94173eaSTrevor Elliott let regs: ValueRegs<Reg> = match regclasses { 1496d94173eaSTrevor Elliott &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), 1497d94173eaSTrevor Elliott &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), 1498d94173eaSTrevor Elliott // We can extend this if/when we support 32-bit targets; e.g., 1499d94173eaSTrevor Elliott // an i128 on a 32-bit machine will need up to four machine regs 1500d94173eaSTrevor Elliott // for a `Value`. 1501d94173eaSTrevor Elliott _ => panic!("Value must reside in 1 or 2 registers"), 1502d94173eaSTrevor Elliott }; 1503d94173eaSTrevor Elliott for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { 1504b1307638SJamey Sharp let vreg = reg.to_virtual_reg().unwrap(); 1505b1307638SJamey Sharp debug_assert_eq!(self.vreg_types.len(), vreg.index()); 1506b1307638SJamey Sharp self.vreg_types.push(reg_ty); 1507b1307638SJamey Sharp if is_reftype(reg_ty) { 1508b1307638SJamey Sharp self.reftyped_vregs.push(vreg.into()); 1509b1307638SJamey Sharp } 1510d94173eaSTrevor Elliott } 1511f466aa26SChris Fallin 1512f466aa26SChris Fallin // Create empty facts for each allocated vreg. 1513b1307638SJamey Sharp self.facts.resize(self.vreg_types.len(), None); 1514f466aa26SChris Fallin 1515d94173eaSTrevor Elliott Ok(regs) 1516d94173eaSTrevor Elliott } 1517d94173eaSTrevor Elliott 151817eeba0eSChris Fallin /// Allocate a fresh ValueRegs, deferring any out-of-vregs 151917eeba0eSChris Fallin /// errors. This is useful in places where we cannot bubble a 152017eeba0eSChris Fallin /// `CodegenResult` upward easily, and which are known to be 152117eeba0eSChris Fallin /// invoked from within the lowering loop that checks the deferred 152217eeba0eSChris Fallin /// error status below. 152317eeba0eSChris Fallin pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg> { 152417eeba0eSChris Fallin match self.alloc(ty) { 152517eeba0eSChris Fallin Ok(x) => x, 152617eeba0eSChris Fallin Err(e) => { 152717eeba0eSChris Fallin self.deferred_error = Some(e); 152817eeba0eSChris Fallin self.bogus_for_deferred_error(ty) 152917eeba0eSChris Fallin } 153017eeba0eSChris Fallin } 153117eeba0eSChris Fallin } 153217eeba0eSChris Fallin 153317eeba0eSChris Fallin /// Take any deferred error that was accumulated by `alloc_with_deferred_error`. 153417eeba0eSChris Fallin pub fn take_deferred_error(&mut self) -> Option<CodegenError> { 153517eeba0eSChris Fallin self.deferred_error.take() 153617eeba0eSChris Fallin } 153717eeba0eSChris Fallin 153817eeba0eSChris Fallin /// Produce an bogus VReg placeholder with the proper number of 153917eeba0eSChris Fallin /// registers for the given type. This is meant to be used with 154017eeba0eSChris Fallin /// deferred allocation errors (see `Lower::alloc_tmp()`). 154117eeba0eSChris Fallin fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg> { 154217eeba0eSChris Fallin let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type"); 154317eeba0eSChris Fallin match regclasses { 154417eeba0eSChris Fallin &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()), 154517eeba0eSChris Fallin &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()), 154617eeba0eSChris Fallin _ => panic!("Value must reside in 1 or 2 registers"), 154717eeba0eSChris Fallin } 154817eeba0eSChris Fallin } 154917eeba0eSChris Fallin 1550f466aa26SChris Fallin /// Set the proof-carrying code fact on a given virtual register. 1551f466aa26SChris Fallin /// 1552f466aa26SChris Fallin /// Returns the old fact, if any (only one fact can be stored). 1553f466aa26SChris Fallin pub fn set_fact(&mut self, vreg: VirtualReg, fact: Fact) -> Option<Fact> { 1554fef8a90fSChris Fallin trace!("vreg {:?} has fact: {:?}", vreg, fact); 1555f466aa26SChris Fallin self.facts[vreg.index()].replace(fact) 1556f466aa26SChris Fallin } 1557f466aa26SChris Fallin 1558fef8a90fSChris Fallin /// Take (and remove) a fact about a VReg. Used when setting up 1559fef8a90fSChris Fallin /// aliases: we want to move a fact from the alias vreg to the 1560fef8a90fSChris Fallin /// aliased vreg, to preserve facts about a value that were stated 1561fef8a90fSChris Fallin /// before we lowered its producer. 1562fef8a90fSChris Fallin pub fn take_fact(&mut self, vreg: VirtualReg) -> Option<Fact> { 1563fef8a90fSChris Fallin self.facts[vreg.index()].take() 1564fef8a90fSChris Fallin } 1565fef8a90fSChris Fallin 1566f262c311SChris Fallin /// Set a fact only if one doesn't already exist. 1567f262c311SChris Fallin pub fn set_fact_if_missing(&mut self, vreg: VirtualReg, fact: Fact) { 1568f262c311SChris Fallin if self.facts[vreg.index()].is_none() { 1569f262c311SChris Fallin self.set_fact(vreg, fact); 1570f262c311SChris Fallin } 1571f262c311SChris Fallin } 1572f262c311SChris Fallin 1573f466aa26SChris Fallin /// Allocate a fresh ValueRegs, with a given fact to apply if 1574f466aa26SChris Fallin /// the value fits in one VReg. 1575f466aa26SChris Fallin pub fn alloc_with_maybe_fact( 1576f466aa26SChris Fallin &mut self, 1577f466aa26SChris Fallin ty: Type, 1578f466aa26SChris Fallin fact: Option<Fact>, 1579f466aa26SChris Fallin ) -> CodegenResult<ValueRegs<Reg>> { 1580f466aa26SChris Fallin let result = self.alloc(ty)?; 1581f466aa26SChris Fallin 1582f466aa26SChris Fallin // Ensure that we don't lose a fact on a value that splits 1583f466aa26SChris Fallin // into multiple VRegs. 1584f466aa26SChris Fallin assert!(result.len() == 1 || fact.is_none()); 1585f466aa26SChris Fallin if let Some(fact) = fact { 1586f466aa26SChris Fallin self.set_fact(result.regs()[0].to_virtual_reg().unwrap(), fact); 1587f466aa26SChris Fallin } 1588f466aa26SChris Fallin 1589f466aa26SChris Fallin Ok(result) 1590f466aa26SChris Fallin } 1591d94173eaSTrevor Elliott } 1592d94173eaSTrevor Elliott 159383f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 159483f182b3SAndrew Brown /// [MachBuffer]. 159583f182b3SAndrew Brown /// 159683f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 1597d38d387aSAlex Crichton /// [VCodeConstants.insert]; an intermediate handle, `VCodeConstant`, tracks what constants are 159883f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 159983f182b3SAndrew Brown /// values are inserted. 160083f182b3SAndrew Brown /// 160183f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 160283f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 160383f182b3SAndrew Brown /// then writes the constant values to the buffer. 160483f182b3SAndrew Brown #[derive(Default)] 160583f182b3SAndrew Brown pub struct VCodeConstants { 160683f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 160783f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 160883f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1609eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 161083f182b3SAndrew Brown } 161183f182b3SAndrew Brown impl VCodeConstants { 161283f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 161383f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 161483f182b3SAndrew Brown Self { 161583f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 161683f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 161783f182b3SAndrew Brown well_known_uses: HashMap::new(), 1618eb435f30SChris Fallin u64s: HashMap::new(), 161983f182b3SAndrew Brown } 162083f182b3SAndrew Brown } 162183f182b3SAndrew Brown 162283f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 162383f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 162483f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 162583f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 162683f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 162783f182b3SAndrew Brown match data { 162883f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 162983f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 163083f182b3SAndrew Brown None => { 163183f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 163283f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 163383f182b3SAndrew Brown vcode_constant 163483f182b3SAndrew Brown } 163583f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 163683f182b3SAndrew Brown }, 163783f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1638eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1639eb435f30SChris Fallin Entry::Vacant(v) => { 164083f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1641eb435f30SChris Fallin v.insert(vcode_constant); 164283f182b3SAndrew Brown vcode_constant 164383f182b3SAndrew Brown } 1644eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 164583f182b3SAndrew Brown } 164683f182b3SAndrew Brown } 1647eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1648eb435f30SChris Fallin Entry::Vacant(v) => { 1649eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1650eb435f30SChris Fallin v.insert(vcode_constant); 1651eb435f30SChris Fallin vcode_constant 1652eb435f30SChris Fallin } 1653eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1654eb435f30SChris Fallin }, 165583f182b3SAndrew Brown } 165683f182b3SAndrew Brown } 165783f182b3SAndrew Brown 165883f182b3SAndrew Brown /// Return the number of constants inserted. 165983f182b3SAndrew Brown pub fn len(&self) -> usize { 166083f182b3SAndrew Brown self.constants.len() 166183f182b3SAndrew Brown } 166283f182b3SAndrew Brown 1663d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys inserted in this structure. 166483f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 166583f182b3SAndrew Brown self.constants.keys() 166683f182b3SAndrew Brown } 166783f182b3SAndrew Brown 1668d38d387aSAlex Crichton /// Iterate over the `VCodeConstant` keys and the data (as a byte slice) inserted in this 166983f182b3SAndrew Brown /// structure. 167083f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 167183f182b3SAndrew Brown self.constants.iter() 167283f182b3SAndrew Brown } 167349dd8fd7SAlex Crichton 167449dd8fd7SAlex Crichton /// Returns the data associated with the specified constant. 167549dd8fd7SAlex Crichton pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData { 167649dd8fd7SAlex Crichton &self.constants[c] 167749dd8fd7SAlex Crichton } 167897f6a8b3SSaúl Cabrera 167997f6a8b3SSaúl Cabrera /// Checks if the given [VCodeConstantData] is registered as 168097f6a8b3SSaúl Cabrera /// used by the pool. 168197f6a8b3SSaúl Cabrera pub fn pool_uses(&self, constant: &VCodeConstantData) -> bool { 168297f6a8b3SSaúl Cabrera match constant { 168397f6a8b3SSaúl Cabrera VCodeConstantData::Pool(c, _) => self.pool_uses.contains_key(c), 168497f6a8b3SSaúl Cabrera _ => false, 168597f6a8b3SSaúl Cabrera } 168697f6a8b3SSaúl Cabrera } 168783f182b3SAndrew Brown } 168883f182b3SAndrew Brown 168983f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 169083f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 169183f182b3SAndrew Brown pub struct VCodeConstant(u32); 169283f182b3SAndrew Brown entity_impl!(VCodeConstant); 169383f182b3SAndrew Brown 169483f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 169583f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 169683f182b3SAndrew Brown pub enum VCodeConstantData { 169783f182b3SAndrew Brown /// A constant already present in the Cranelift IR 169883f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 169983f182b3SAndrew Brown Pool(Constant, ConstantData), 170083f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 170183f182b3SAndrew Brown WellKnown(&'static [u8]), 170283f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 170383f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 170483f182b3SAndrew Brown Generated(ConstantData), 1705eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1706eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1707eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1708eb435f30SChris Fallin U64([u8; 8]), 170983f182b3SAndrew Brown } 171083f182b3SAndrew Brown impl VCodeConstantData { 171183f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 171283f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 171383f182b3SAndrew Brown match self { 171483f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 171583f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1716eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 171783f182b3SAndrew Brown } 171883f182b3SAndrew Brown } 171983f182b3SAndrew Brown 172083f182b3SAndrew Brown /// Calculate the alignment of the constant data. 172183f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 172283f182b3SAndrew Brown if self.as_slice().len() <= 8 { 172383f182b3SAndrew Brown 8 172483f182b3SAndrew Brown } else { 172583f182b3SAndrew Brown 16 172683f182b3SAndrew Brown } 172783f182b3SAndrew Brown } 172883f182b3SAndrew Brown } 172983f182b3SAndrew Brown 173083f182b3SAndrew Brown #[cfg(test)] 173183f182b3SAndrew Brown mod test { 173283f182b3SAndrew Brown use super::*; 17335e5e5206SChris Fallin use std::mem::size_of; 173483f182b3SAndrew Brown 173583f182b3SAndrew Brown #[test] 173683f182b3SAndrew Brown fn size_of_constant_structs() { 173783f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 173883f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 173983f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 174083f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 174183f182b3SAndrew Brown assert_eq!( 174283f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 174383f182b3SAndrew Brown 24 174483f182b3SAndrew Brown ); 17455e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 17465e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 17475e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 174883f182b3SAndrew Brown } 174983f182b3SAndrew Brown } 1750