1d8357426SChris Fallin //! This implements the VCode container: a CFG of Insts that have been lowered. 2d8357426SChris Fallin //! 3d8357426SChris Fallin //! VCode is virtual-register code. An instruction in VCode is almost a machine 4d8357426SChris Fallin //! instruction; however, its register slots can refer to virtual registers in 5d8357426SChris Fallin //! addition to real machine registers. 6d8357426SChris Fallin //! 7d8357426SChris Fallin //! VCode is structured with traditional basic blocks, and 8d8357426SChris Fallin //! each block must be terminated by an unconditional branch (one target), a 9d8357426SChris Fallin //! conditional branch (two targets), or a return (no targets). Note that this 10d8357426SChris Fallin //! slightly differs from the machine code of most ISAs: in most ISAs, a 11d8357426SChris Fallin //! conditional branch has one target (and the not-taken case falls through). 12d8357426SChris Fallin //! However, we expect that machine backends will elide branches to the following 13d8357426SChris Fallin //! block (i.e., zero-offset jumps), and will be able to codegen a branch-cond / 14d8357426SChris Fallin //! branch-uncond pair if *both* targets are not fallthrough. This allows us to 15d8357426SChris Fallin //! play with layout prior to final binary emission, as well, if we want. 16d8357426SChris Fallin //! 17d8357426SChris Fallin //! See the main module comment in `mod.rs` for more details on the VCode-based 18d8357426SChris Fallin //! backend pipeline. 19d8357426SChris Fallin 20666c2554SChris Fallin use crate::fx::FxHashMap; 21a0318f36SChris Fallin use crate::fx::FxHashSet; 22f466aa26SChris Fallin use crate::ir::pcc::*; 238a9b1a90SBenjamin Bouvier use crate::ir::RelSourceLoc; 24729e2640Sbjorn3 use crate::ir::{self, types, Constant, ConstantData, DynamicStackSlot, ValueLabel}; 25d8357426SChris Fallin use crate::machinst::*; 262b9fefe8SChris Fallin use crate::timing; 278d022434SBenjamin Bouvier use crate::trace; 28d94173eaSTrevor Elliott use crate::CodegenError; 29729e2640Sbjorn3 use crate::{LabelValueLoc, ValueLocRange}; 307eb89140SRemo Senekowitsch use cranelift_control::ControlPlane; 31a0318f36SChris Fallin use regalloc2::{ 325c8a603aSUlrich Weigand Edit, Function as RegallocFunction, InstOrEdit, InstRange, MachineEnv, Operand, OperandKind, 335c8a603aSUlrich Weigand PRegSet, RegClass, VReg, 34be6f060aSChris Fallin }; 35d8357426SChris Fallin 36a0318f36SChris Fallin use alloc::vec::Vec; 3783f182b3SAndrew Brown use cranelift_entity::{entity_impl, Keys, PrimaryMap}; 38eb435f30SChris Fallin use std::collections::hash_map::Entry; 3983f182b3SAndrew Brown use std::collections::HashMap; 40d8357426SChris Fallin use std::fmt; 41d8357426SChris Fallin 42d8357426SChris Fallin /// Index referring to an instruction in VCode. 43a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst; 44a0318f36SChris Fallin 45d8357426SChris Fallin /// Index referring to a basic block in VCode. 46a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block; 47d8357426SChris Fallin 48d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be 49d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. 5072e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 5172e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {} 52d8357426SChris Fallin 53a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after 54a0318f36SChris Fallin /// lowering. This is essentially a standard CFG of basic blocks, 55a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced 56a0318f36SChris Fallin /// by the machine-specific backend. 57a0318f36SChris Fallin /// 58a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not 59a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register 60a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output` 61a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not 62a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the 63a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or 64a0318f36SChris Fallin /// metadata as requested. 65d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 66d8357426SChris Fallin /// VReg IR-level types. 67d8357426SChris Fallin vreg_types: Vec<Type>, 68d8357426SChris Fallin 69d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 7048cf2c2fSChris Fallin insts: Vec<I>, 71d8357426SChris Fallin 72a0318f36SChris Fallin /// Operands: pre-regalloc references to virtual registers with 73a0318f36SChris Fallin /// constraints, in one flattened array. This allows the regalloc 74a0318f36SChris Fallin /// to efficiently access all operands without requiring expensive 75a0318f36SChris Fallin /// matches or method invocations on insts. 76a0318f36SChris Fallin operands: Vec<Operand>, 77a0318f36SChris Fallin 78a0318f36SChris Fallin /// Operand index ranges: for each instruction in `insts`, there 79a0318f36SChris Fallin /// is a tuple here providing the range in `operands` for that 80a0318f36SChris Fallin /// instruction's operands. 81a0318f36SChris Fallin operand_ranges: Vec<(u32, u32)>, 82a0318f36SChris Fallin 83b2e28b91SChris Fallin /// Clobbers: a sparse map from instruction indices to clobber masks. 84b2e28b91SChris Fallin clobbers: FxHashMap<InsnIndex, PRegSet>, 85a0318f36SChris Fallin 86b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 87b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 888a9b1a90SBenjamin Bouvier srclocs: Vec<RelSourceLoc>, 89b691770fSChris Fallin 90d8357426SChris Fallin /// Entry block. 91d8357426SChris Fallin entry: BlockIndex, 92d8357426SChris Fallin 93d8357426SChris Fallin /// Block instruction indices. 9448cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 95d8357426SChris Fallin 96a0318f36SChris Fallin /// Block successors: index range in the `block_succs_preds` list. 97a0318f36SChris Fallin block_succ_range: Vec<(u32, u32)>, 98d8357426SChris Fallin 99a0318f36SChris Fallin /// Block predecessors: index range in the `block_succs_preds` list. 100a0318f36SChris Fallin block_pred_range: Vec<(u32, u32)>, 101a0318f36SChris Fallin 102a0318f36SChris Fallin /// Block successor and predecessor lists, concatenated into one 103a0318f36SChris Fallin /// Vec. The `block_succ_range` and `block_pred_range` lists of 104a0318f36SChris Fallin /// tuples above give (start, end) ranges within this list that 105a0318f36SChris Fallin /// correspond to each basic block's successors or predecessors, 106a0318f36SChris Fallin /// respectively. 107a0318f36SChris Fallin block_succs_preds: Vec<regalloc2::Block>, 108a0318f36SChris Fallin 109a0318f36SChris Fallin /// Block parameters: index range in `block_params` below. 110a0318f36SChris Fallin block_params_range: Vec<(u32, u32)>, 111a0318f36SChris Fallin 112a0318f36SChris Fallin /// Block parameter lists, concatenated into one vec. The 113a0318f36SChris Fallin /// `block_params_range` list of tuples above gives (start, end) 114a0318f36SChris Fallin /// ranges within this list that correspond to each basic block's 115a0318f36SChris Fallin /// blockparam vregs. 116a0318f36SChris Fallin block_params: Vec<regalloc2::VReg>, 117a0318f36SChris Fallin 118a0318f36SChris Fallin /// Outgoing block arguments on branch instructions, concatenated 119a0318f36SChris Fallin /// into one list. 120a0318f36SChris Fallin /// 121a0318f36SChris Fallin /// Note that this is conceptually a 3D array: we have a VReg list 122a0318f36SChris Fallin /// per block, per successor. We flatten those three dimensions 123a0318f36SChris Fallin /// into this 1D vec, then store index ranges in two levels of 124a0318f36SChris Fallin /// indirection. 125a0318f36SChris Fallin /// 126a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 127a0318f36SChris Fallin branch_block_args: Vec<regalloc2::VReg>, 128a0318f36SChris Fallin 129a0318f36SChris Fallin /// Array of sequences of (start, end) tuples in 130a0318f36SChris Fallin /// `branch_block_args`, one for each successor; these sequences 131a0318f36SChris Fallin /// for each block are concatenated. 132a0318f36SChris Fallin /// 133a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 134a0318f36SChris Fallin branch_block_arg_range: Vec<(u32, u32)>, 135a0318f36SChris Fallin 136a0318f36SChris Fallin /// For a given block, indices in `branch_block_arg_range` 137a0318f36SChris Fallin /// corresponding to all of its successors. 138a0318f36SChris Fallin branch_block_arg_succ_range: Vec<(u32, u32)>, 139a0318f36SChris Fallin 140a0318f36SChris Fallin /// VReg aliases. Each key in this table is translated to its 141a0318f36SChris Fallin /// value when gathering Operands from instructions. Aliases are 142a0318f36SChris Fallin /// not chased transitively (we do not further look up the 143a0318f36SChris Fallin /// translated reg to see if it is another alias). 144a0318f36SChris Fallin /// 145a0318f36SChris Fallin /// We use these aliases to rename an instruction's expected 146a0318f36SChris Fallin /// result vregs to the returned vregs from lowering, which are 147a0318f36SChris Fallin /// usually freshly-allocated temps. 148a0318f36SChris Fallin /// 149a0318f36SChris Fallin /// Operands and branch arguments will already have been 150a0318f36SChris Fallin /// translated through this alias table; but it helps to make 151a0318f36SChris Fallin /// sense of instructions when pretty-printed, for example. 152a0318f36SChris Fallin vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>, 153d8357426SChris Fallin 15472e6be93SChris Fallin /// Block-order information. 15572e6be93SChris Fallin block_order: BlockLoweringOrder, 156d8357426SChris Fallin 157d8357426SChris Fallin /// ABI object. 1582986f6b0SChris Fallin pub(crate) abi: Callee<I::ABIMachineSpec>, 15908353fccSChris Fallin 160c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 161c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 162c5bbc874SBenjamin Bouvier emit_info: I::Info, 163c5bbc874SBenjamin Bouvier 164a0318f36SChris Fallin /// Reference-typed `regalloc2::VReg`s. The regalloc requires 165a0318f36SChris Fallin /// these in a dense slice (as opposed to querying the 166a0318f36SChris Fallin /// reftype-status of each vreg) for efficient iteration. 167a0318f36SChris Fallin reftyped_vregs: Vec<VReg>, 16808353fccSChris Fallin 16983f182b3SAndrew Brown /// Constants. 17083f182b3SAndrew Brown constants: VCodeConstants, 171997fab55SChris Fallin 172a0318f36SChris Fallin /// Value labels for debuginfo attached to vregs. 173a0318f36SChris Fallin debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, 174f18a1f14SNick Fitzgerald 1752986f6b0SChris Fallin pub(crate) sigs: SigSet, 176f466aa26SChris Fallin 177f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code verification. 178f466aa26SChris Fallin facts: Vec<Option<Fact>>, 179d8357426SChris Fallin } 180d8357426SChris Fallin 181a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed 182a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly, 183a0318f36SChris Fallin /// and optionally metadata about the code layout. 18449dd8fd7SAlex Crichton pub struct EmitResult { 185a0318f36SChris Fallin /// The MachBuffer containing the machine code. 18649dd8fd7SAlex Crichton pub buffer: MachBufferFinalized<Stencil>, 187a0318f36SChris Fallin 188a0318f36SChris Fallin /// Offset of each basic block, recorded during emission. Computed 189a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 190a0318f36SChris Fallin pub bb_offsets: Vec<CodeOffset>, 191a0318f36SChris Fallin 192a0318f36SChris Fallin /// Final basic-block edges, in terms of code offsets of 193a0318f36SChris Fallin /// bb-starts. Computed only if `debug_value_labels` is non-empty. 194a0318f36SChris Fallin pub bb_edges: Vec<(CodeOffset, CodeOffset)>, 195a0318f36SChris Fallin 196a0318f36SChris Fallin /// Final length of function body. 197a0318f36SChris Fallin pub func_body_len: CodeOffset, 198a0318f36SChris Fallin 199a0318f36SChris Fallin /// The pretty-printed disassembly, if any. This uses the same 200a0318f36SChris Fallin /// pretty-printing for MachInsts as the pre-regalloc VCode Debug 201a0318f36SChris Fallin /// implementation, but additionally includes the prologue and 202a0318f36SChris Fallin /// epilogue(s), and makes use of the regalloc results. 203a0318f36SChris Fallin pub disasm: Option<String>, 204a0318f36SChris Fallin 2059c43749dSSam Parker /// Offsets of sized stackslots. 2069c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 2079c43749dSSam Parker 2089c43749dSSam Parker /// Offsets of dynamic stackslots. 2099c43749dSSam Parker pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>, 210a0318f36SChris Fallin 211a0318f36SChris Fallin /// Value-labels information (debug metadata). 212a0318f36SChris Fallin pub value_labels_ranges: ValueLabelsRanges, 213a0318f36SChris Fallin 214a0318f36SChris Fallin /// Stack frame size. 215a0318f36SChris Fallin pub frame_size: u32, 216d9d64694SChris Fallin } 217d9d64694SChris Fallin 218a0318f36SChris Fallin /// A builder for a VCode function body. 219d8357426SChris Fallin /// 220a0318f36SChris Fallin /// This builder has the ability to accept instructions in either 221a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that 222a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst> 223a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions 224a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will 225a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine 226a0318f36SChris Fallin /// order. 227a0318f36SChris Fallin /// 228a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the 229a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the 230a0318f36SChris Fallin /// order of construction. Note that this means we do not know the 231a0318f36SChris Fallin /// final block or instruction indices when building, so we do not 232a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending 233a0318f36SChris Fallin /// terminator instructions with successor blocks.) 234d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 235d8357426SChris Fallin /// In-progress VCode. 2362986f6b0SChris Fallin pub(crate) vcode: VCode<I>, 237d8357426SChris Fallin 238a0318f36SChris Fallin /// In what direction is the build occuring? 239a0318f36SChris Fallin direction: VCodeBuildDirection, 24008353fccSChris Fallin 24172e6be93SChris Fallin /// Index of the last block-start in the vcode. 242a0318f36SChris Fallin block_start: usize, 243d8357426SChris Fallin 244d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 245d8357426SChris Fallin succ_start: usize, 246b691770fSChris Fallin 247a0318f36SChris Fallin /// Start of blockparams for the current block in the concatenated 248a0318f36SChris Fallin /// blockparams list. 249a0318f36SChris Fallin block_params_start: usize, 250a0318f36SChris Fallin 251a0318f36SChris Fallin /// Start of successor blockparam arg list entries in 252a0318f36SChris Fallin /// the concatenated branch_block_arg_range list. 253a0318f36SChris Fallin branch_block_arg_succ_start: usize, 254a0318f36SChris Fallin 255b691770fSChris Fallin /// Current source location. 2568a9b1a90SBenjamin Bouvier cur_srcloc: RelSourceLoc, 257a0318f36SChris Fallin 258a0318f36SChris Fallin /// Debug-value label in-progress map, keyed by label. For each 259a0318f36SChris Fallin /// label, we keep disjoint ranges mapping to vregs. We'll flatten 260a0318f36SChris Fallin /// this into (vreg, range, label) tuples when done. 261a0318f36SChris Fallin debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>, 262a0318f36SChris Fallin } 263a0318f36SChris Fallin 264a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode. 265a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)] 266a0318f36SChris Fallin pub enum VCodeBuildDirection { 267a0318f36SChris Fallin // TODO: add `Forward` once we need it and can test it adequately. 268a0318f36SChris Fallin /// Backward-build pass: we expect the producer to call `emit()` 269a0318f36SChris Fallin /// with instructions in reverse program order within each block. 270a0318f36SChris Fallin Backward, 271d8357426SChris Fallin } 272d8357426SChris Fallin 273d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 274d8357426SChris Fallin /// Create a new VCodeBuilder. 275c5bbc874SBenjamin Bouvier pub fn new( 276f18a1f14SNick Fitzgerald sigs: SigSet, 277f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 278c5bbc874SBenjamin Bouvier emit_info: I::Info, 279c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 28083f182b3SAndrew Brown constants: VCodeConstants, 281a0318f36SChris Fallin direction: VCodeBuildDirection, 282c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 283f18a1f14SNick Fitzgerald let vcode = VCode::new(sigs, abi, emit_info, block_order, constants); 28408353fccSChris Fallin 285d8357426SChris Fallin VCodeBuilder { 286d8357426SChris Fallin vcode, 287a0318f36SChris Fallin direction, 28872e6be93SChris Fallin block_start: 0, 289d8357426SChris Fallin succ_start: 0, 290a0318f36SChris Fallin block_params_start: 0, 291a0318f36SChris Fallin branch_block_arg_succ_start: 0, 2928a9b1a90SBenjamin Bouvier cur_srcloc: Default::default(), 293a0318f36SChris Fallin debug_info: FxHashMap::default(), 294d8357426SChris Fallin } 295d8357426SChris Fallin } 296d8357426SChris Fallin 297f18a1f14SNick Fitzgerald pub fn init_abi(&mut self, temps: Vec<Writable<Reg>>) { 298f18a1f14SNick Fitzgerald self.vcode.abi.init(&self.vcode.sigs, temps); 299f18a1f14SNick Fitzgerald } 300f18a1f14SNick Fitzgerald 301d8357426SChris Fallin /// Access the ABI object. 302f18a1f14SNick Fitzgerald pub fn abi(&self) -> &Callee<I::ABIMachineSpec> { 303f18a1f14SNick Fitzgerald &self.vcode.abi 304f18a1f14SNick Fitzgerald } 305f18a1f14SNick Fitzgerald 306f18a1f14SNick Fitzgerald /// Access the ABI object. 307f18a1f14SNick Fitzgerald pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> { 308f0c60f46SNick Fitzgerald &mut self.vcode.abi 309d8357426SChris Fallin } 310d8357426SChris Fallin 311f18a1f14SNick Fitzgerald pub fn sigs(&self) -> &SigSet { 312f18a1f14SNick Fitzgerald &self.vcode.sigs 313f18a1f14SNick Fitzgerald } 314f18a1f14SNick Fitzgerald 315f18a1f14SNick Fitzgerald pub fn sigs_mut(&mut self) -> &mut SigSet { 316f18a1f14SNick Fitzgerald &mut self.vcode.sigs 317f18a1f14SNick Fitzgerald } 318f18a1f14SNick Fitzgerald 31972e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 32072e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 32172e6be93SChris Fallin &self.vcode.block_order 3221d90751bSBenjamin Bouvier } 3231d90751bSBenjamin Bouvier 324d8357426SChris Fallin /// Set the current block as the entry block. 325d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 326d8357426SChris Fallin self.vcode.entry = block; 327d8357426SChris Fallin } 328d8357426SChris Fallin 329d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 330d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 33172e6be93SChris Fallin pub fn end_bb(&mut self) { 33272e6be93SChris Fallin let start_idx = self.block_start; 333a0318f36SChris Fallin let end_idx = self.vcode.insts.len(); 33472e6be93SChris Fallin self.block_start = end_idx; 335d8357426SChris Fallin // Add the instruction index range to the list of blocks. 336a0318f36SChris Fallin self.vcode 337a0318f36SChris Fallin .block_ranges 338a0318f36SChris Fallin .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx))); 339d8357426SChris Fallin // End the successors list. 340a0318f36SChris Fallin let succ_end = self.vcode.block_succs_preds.len(); 341d8357426SChris Fallin self.vcode 342d8357426SChris Fallin .block_succ_range 343a0318f36SChris Fallin .push((self.succ_start as u32, succ_end as u32)); 344d8357426SChris Fallin self.succ_start = succ_end; 345a0318f36SChris Fallin // End the blockparams list. 346a0318f36SChris Fallin let block_params_end = self.vcode.block_params.len(); 347a0318f36SChris Fallin self.vcode 348a0318f36SChris Fallin .block_params_range 349a0318f36SChris Fallin .push((self.block_params_start as u32, block_params_end as u32)); 350a0318f36SChris Fallin self.block_params_start = block_params_end; 351a0318f36SChris Fallin // End the branch blockparam args list. 352a0318f36SChris Fallin let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); 353a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.push(( 354a0318f36SChris Fallin self.branch_block_arg_succ_start as u32, 355a0318f36SChris Fallin branch_block_arg_succ_end as u32, 356a0318f36SChris Fallin )); 357a0318f36SChris Fallin self.branch_block_arg_succ_start = branch_block_arg_succ_end; 358d8357426SChris Fallin } 359d8357426SChris Fallin 360d94173eaSTrevor Elliott pub fn add_block_param(&mut self, param: VirtualReg) { 361a0318f36SChris Fallin self.vcode.block_params.push(param.into()); 362a0318f36SChris Fallin } 363a0318f36SChris Fallin 3645774e068SChris Fallin fn add_branch_args_for_succ(&mut self, args: &[Reg]) { 365a0318f36SChris Fallin let start = self.vcode.branch_block_args.len(); 366a0318f36SChris Fallin self.vcode 367a0318f36SChris Fallin .branch_block_args 368a0318f36SChris Fallin .extend(args.iter().map(|&arg| VReg::from(arg))); 369a0318f36SChris Fallin let end = self.vcode.branch_block_args.len(); 370a0318f36SChris Fallin self.vcode 371a0318f36SChris Fallin .branch_block_arg_range 372a0318f36SChris Fallin .push((start as u32, end as u32)); 373a0318f36SChris Fallin } 374a0318f36SChris Fallin 375a0318f36SChris Fallin /// Push an instruction for the current BB and current IR inst 376a0318f36SChris Fallin /// within the BB. 377a0318f36SChris Fallin pub fn push(&mut self, insn: I) { 37872e6be93SChris Fallin self.vcode.insts.push(insn); 37972e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 38072e6be93SChris Fallin } 38172e6be93SChris Fallin 3825774e068SChris Fallin /// Add a successor block with branch args. 3835774e068SChris Fallin pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { 3845774e068SChris Fallin self.vcode.block_succs_preds.push(block); 3855774e068SChris Fallin self.add_branch_args_for_succ(args); 3865774e068SChris Fallin } 3875774e068SChris Fallin 388b691770fSChris Fallin /// Set the current source location. 3898a9b1a90SBenjamin Bouvier pub fn set_srcloc(&mut self, srcloc: RelSourceLoc) { 390b691770fSChris Fallin self.cur_srcloc = srcloc; 391d8357426SChris Fallin } 392d8357426SChris Fallin 393a0318f36SChris Fallin /// Add a debug value label to a register. 394a0318f36SChris Fallin pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { 395a0318f36SChris Fallin // We'll fix up labels in reverse(). Because we're generating 396a0318f36SChris Fallin // code bottom-to-top, the liverange of the label goes *from* 397a0318f36SChris Fallin // the last index at which was defined (or 0, which is the end 398a0318f36SChris Fallin // of the eventual function) *to* just this instruction, and 399a0318f36SChris Fallin // no further. 400a0318f36SChris Fallin let inst = InsnIndex::new(self.vcode.insts.len()); 401a0318f36SChris Fallin let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); 402a0318f36SChris Fallin let last = labels 403a0318f36SChris Fallin .last() 404a0318f36SChris Fallin .map(|(_start, end, _vreg)| *end) 405a0318f36SChris Fallin .unwrap_or(InsnIndex::new(0)); 406a0318f36SChris Fallin labels.push((last, inst, reg.into())); 407a0318f36SChris Fallin } 408a0318f36SChris Fallin 409a0318f36SChris Fallin pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { 410a0318f36SChris Fallin let from = from.into(); 411fef8a90fSChris Fallin let resolved_to = self.vcode.resolve_vreg_alias(to.into()); 412a0318f36SChris Fallin // Disallow cycles (see below). 413a0318f36SChris Fallin assert_ne!(resolved_to, from); 414a0318f36SChris Fallin self.vcode.vreg_aliases.insert(from, resolved_to); 415a0318f36SChris Fallin } 416a0318f36SChris Fallin 41783f182b3SAndrew Brown /// Access the constants. 41883f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 41983f182b3SAndrew Brown &mut self.vcode.constants 42083f182b3SAndrew Brown } 42183f182b3SAndrew Brown 422a0318f36SChris Fallin fn compute_preds_from_succs(&mut self) { 423a0318f36SChris Fallin // Compute predecessors from successors. In order to gather 424a0318f36SChris Fallin // all preds for a block into a contiguous sequence, we build 425a0318f36SChris Fallin // a list of (succ, pred) tuples and then sort. 426a0318f36SChris Fallin let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> = 427a0318f36SChris Fallin Vec::with_capacity(self.vcode.block_succs_preds.len()); 428a0318f36SChris Fallin for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() { 429a0318f36SChris Fallin let pred = BlockIndex::new(pred); 430a0318f36SChris Fallin for i in start..end { 431a0318f36SChris Fallin let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index()); 432a0318f36SChris Fallin succ_pred_edges.push((succ, pred)); 433a0318f36SChris Fallin } 434a0318f36SChris Fallin } 435a0318f36SChris Fallin succ_pred_edges.sort_unstable(); 436a0318f36SChris Fallin 437a0318f36SChris Fallin let mut i = 0; 438a0318f36SChris Fallin for succ in 0..self.vcode.num_blocks() { 439a0318f36SChris Fallin let succ = BlockIndex::new(succ); 440a0318f36SChris Fallin let start = self.vcode.block_succs_preds.len(); 441a0318f36SChris Fallin while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ { 442a0318f36SChris Fallin let pred = succ_pred_edges[i].1; 443a0318f36SChris Fallin self.vcode.block_succs_preds.push(pred); 444a0318f36SChris Fallin i += 1; 445a0318f36SChris Fallin } 446a0318f36SChris Fallin let end = self.vcode.block_succs_preds.len(); 447a0318f36SChris Fallin self.vcode.block_pred_range.push((start as u32, end as u32)); 448d8357426SChris Fallin } 449d8357426SChris Fallin } 450d8357426SChris Fallin 451a0318f36SChris Fallin /// Called once, when a build in Backward order is complete, to 452a0318f36SChris Fallin /// perform the overall reversal (into final forward order) and 453a0318f36SChris Fallin /// finalize metadata accordingly. 454a0318f36SChris Fallin fn reverse_and_finalize(&mut self) { 455a0318f36SChris Fallin let n_insts = self.vcode.insts.len(); 456a0318f36SChris Fallin if n_insts == 0 { 457a0318f36SChris Fallin return; 458a0318f36SChris Fallin } 459a0318f36SChris Fallin 460a0318f36SChris Fallin // Reverse the per-block and per-inst sequences. 461a0318f36SChris Fallin self.vcode.block_ranges.reverse(); 462a0318f36SChris Fallin // block_params_range is indexed by block (and blocks were 463a0318f36SChris Fallin // traversed in reverse) so we reverse it; but block-param 464a0318f36SChris Fallin // sequences in the concatenated vec can remain in reverse 465a0318f36SChris Fallin // order (it is effectively an arena of arbitrarily-placed 466a0318f36SChris Fallin // referenced sequences). 467a0318f36SChris Fallin self.vcode.block_params_range.reverse(); 468a0318f36SChris Fallin // Likewise, we reverse block_succ_range, but the block_succ 469a0318f36SChris Fallin // concatenated array can remain as-is. 470a0318f36SChris Fallin self.vcode.block_succ_range.reverse(); 471a0318f36SChris Fallin self.vcode.insts.reverse(); 472a0318f36SChris Fallin self.vcode.srclocs.reverse(); 473a0318f36SChris Fallin // Likewise, branch_block_arg_succ_range is indexed by block 474a0318f36SChris Fallin // so must be reversed. 475a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.reverse(); 476a0318f36SChris Fallin 477a0318f36SChris Fallin // To translate an instruction index *endpoint* in reversed 478a0318f36SChris Fallin // order to forward order, compute `n_insts - i`. 479a0318f36SChris Fallin // 480a0318f36SChris Fallin // Why not `n_insts - 1 - i`? That would be correct to 481a0318f36SChris Fallin // translate an individual instruction index (for ten insts 0 482a0318f36SChris Fallin // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes 483a0318f36SChris Fallin // 0). But for the usual inclusive-start, exclusive-end range 484a0318f36SChris Fallin // idiom, inclusive starts become exclusive ends and 485a0318f36SChris Fallin // vice-versa, so e.g. an (inclusive) start of 0 becomes an 486a0318f36SChris Fallin // (exclusive) end of 10. 487a0318f36SChris Fallin let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); 488a0318f36SChris Fallin 489a0318f36SChris Fallin // Edit the block-range instruction indices. 490a0318f36SChris Fallin for tuple in &mut self.vcode.block_ranges { 491a0318f36SChris Fallin let (start, end) = *tuple; 492a0318f36SChris Fallin *tuple = (translate(end), translate(start)); // Note reversed order. 493a0318f36SChris Fallin } 494a0318f36SChris Fallin 495a0318f36SChris Fallin // Generate debug-value labels based on per-label maps. 496a0318f36SChris Fallin for (label, tuples) in &self.debug_info { 497a0318f36SChris Fallin for &(start, end, vreg) in tuples { 498fef8a90fSChris Fallin let vreg = self.vcode.resolve_vreg_alias(vreg); 499a0318f36SChris Fallin let fwd_start = translate(end); 500a0318f36SChris Fallin let fwd_end = translate(start); 501a0318f36SChris Fallin self.vcode 502a0318f36SChris Fallin .debug_value_labels 503a0318f36SChris Fallin .push((vreg, fwd_start, fwd_end, label.as_u32())); 504a0318f36SChris Fallin } 505a0318f36SChris Fallin } 506a0318f36SChris Fallin 507a0318f36SChris Fallin // Now sort debug value labels by VReg, as required 508a0318f36SChris Fallin // by regalloc2. 509a0318f36SChris Fallin self.vcode 510a0318f36SChris Fallin .debug_value_labels 511a0318f36SChris Fallin .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); 512a0318f36SChris Fallin } 513a0318f36SChris Fallin 5145c8a603aSUlrich Weigand fn collect_operands(&mut self) { 515a0318f36SChris Fallin for (i, insn) in self.vcode.insts.iter().enumerate() { 516a0318f36SChris Fallin // Push operands from the instruction onto the operand list. 517a0318f36SChris Fallin // 518a0318f36SChris Fallin // We rename through the vreg alias table as we collect 519a0318f36SChris Fallin // the operands. This is better than a separate post-pass 520a0318f36SChris Fallin // over operands, because it has more cache locality: 521a0318f36SChris Fallin // operands only need to pass through L1 once. This is 522a0318f36SChris Fallin // also better than renaming instructions' 523a0318f36SChris Fallin // operands/registers while lowering, because here we only 524a0318f36SChris Fallin // need to do the `match` over the instruction to visit 525a0318f36SChris Fallin // its register fields (which is slow, branchy code) once. 526a0318f36SChris Fallin 527a0318f36SChris Fallin let vreg_aliases = &self.vcode.vreg_aliases; 5285c8a603aSUlrich Weigand let allocatable = PRegSet::from(self.vcode.machine_env()); 529a007e02bSTrevor Elliott let mut op_collector = 530a007e02bSTrevor Elliott OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| { 531fef8a90fSChris Fallin VCode::<I>::resolve_vreg_alias_impl(vreg_aliases, vreg) 532a0318f36SChris Fallin }); 533a0318f36SChris Fallin insn.get_operands(&mut op_collector); 534a0318f36SChris Fallin let (ops, clobbers) = op_collector.finish(); 535a0318f36SChris Fallin self.vcode.operand_ranges.push(ops); 536a0318f36SChris Fallin 537b2e28b91SChris Fallin if clobbers != PRegSet::default() { 538b2e28b91SChris Fallin self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); 539a0318f36SChris Fallin } 540a0318f36SChris Fallin 541a0318f36SChris Fallin if let Some((dst, src)) = insn.is_move() { 542fac4a915STrevor Elliott // We should never see non-virtual registers present in move 543fac4a915STrevor Elliott // instructions. 544fac4a915STrevor Elliott assert!( 545fac4a915STrevor Elliott src.is_virtual(), 546fac4a915STrevor Elliott "the real register {:?} was used as the source of a move instruction", 547fac4a915STrevor Elliott src 548fac4a915STrevor Elliott ); 549fac4a915STrevor Elliott assert!( 550fac4a915STrevor Elliott dst.to_reg().is_virtual(), 551fac4a915STrevor Elliott "the real register {:?} was used as the destination of a move instruction", 552fac4a915STrevor Elliott dst.to_reg() 553fac4a915STrevor Elliott ); 554a0318f36SChris Fallin } 555a0318f36SChris Fallin } 556a0318f36SChris Fallin 557a0318f36SChris Fallin // Translate blockparam args via the vreg aliases table as well. 558a0318f36SChris Fallin for arg in &mut self.vcode.branch_block_args { 559fef8a90fSChris Fallin let new_arg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg); 5608d022434SBenjamin Bouvier trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); 561a0318f36SChris Fallin *arg = new_arg; 562a0318f36SChris Fallin } 563a0318f36SChris Fallin } 564a0318f36SChris Fallin 565a0318f36SChris Fallin /// Build the final VCode. 5665c8a603aSUlrich Weigand pub fn build(mut self, vregs: VRegAllocator<I>) -> VCode<I> { 567d94173eaSTrevor Elliott self.vcode.vreg_types = vregs.vreg_types; 568f466aa26SChris Fallin self.vcode.facts = vregs.facts; 569d94173eaSTrevor Elliott self.vcode.reftyped_vregs = vregs.reftyped_vregs; 570d94173eaSTrevor Elliott 571a0318f36SChris Fallin if self.direction == VCodeBuildDirection::Backward { 572a0318f36SChris Fallin self.reverse_and_finalize(); 573a0318f36SChris Fallin } 5745c8a603aSUlrich Weigand self.collect_operands(); 5752154c63dSAlex Crichton 5762154c63dSAlex Crichton // Apply register aliases to the `reftyped_vregs` list since this list 5772154c63dSAlex Crichton // will be returned directly to `regalloc2` eventually and all 5782154c63dSAlex Crichton // operands/results of instructions will use the alias-resolved vregs 5792154c63dSAlex Crichton // from `regalloc2`'s perspective. 5802127c3a3SAlex Crichton // 5812127c3a3SAlex Crichton // Also note that `reftyped_vregs` can't have duplicates, so after the 5822127c3a3SAlex Crichton // aliases are applied duplicates are removed. 5832154c63dSAlex Crichton for reg in self.vcode.reftyped_vregs.iter_mut() { 584fef8a90fSChris Fallin *reg = VCode::<I>::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg); 5852154c63dSAlex Crichton } 5862127c3a3SAlex Crichton self.vcode.reftyped_vregs.sort(); 5872127c3a3SAlex Crichton self.vcode.reftyped_vregs.dedup(); 5882154c63dSAlex Crichton 589a0318f36SChris Fallin self.compute_preds_from_succs(); 590a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 591a0318f36SChris Fallin self.vcode 592d8357426SChris Fallin } 593d8357426SChris Fallin } 594d8357426SChris Fallin 59508353fccSChris Fallin /// Is this type a reference type? 59608353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 59726529006SChris Fallin ty == types::R64 || ty == types::R32 59808353fccSChris Fallin } 59908353fccSChris Fallin 600d4a4d4f9SSingleAccretion const NO_INST_OFFSET: CodeOffset = u32::MAX; 601d4a4d4f9SSingleAccretion 602d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 603d8357426SChris Fallin /// New empty VCode. 604c5bbc874SBenjamin Bouvier fn new( 605f18a1f14SNick Fitzgerald sigs: SigSet, 606f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 607c5bbc874SBenjamin Bouvier emit_info: I::Info, 608c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 60983f182b3SAndrew Brown constants: VCodeConstants, 610c5bbc874SBenjamin Bouvier ) -> VCode<I> { 611a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 612d8357426SChris Fallin VCode { 613f18a1f14SNick Fitzgerald sigs, 614d8357426SChris Fallin vreg_types: vec![], 615a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 616a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 617a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 618b2e28b91SChris Fallin clobbers: FxHashMap::default(), 619a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 620a0318f36SChris Fallin entry: BlockIndex::new(0), 621a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 622a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 623a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 624a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 625a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 626a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 627a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 628a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 629a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 63072e6be93SChris Fallin block_order, 631d8357426SChris Fallin abi, 632c5bbc874SBenjamin Bouvier emit_info, 633a0318f36SChris Fallin reftyped_vregs: vec![], 63483f182b3SAndrew Brown constants, 635a0318f36SChris Fallin debug_value_labels: vec![], 636a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 637f466aa26SChris Fallin facts: vec![], 638d8357426SChris Fallin } 639d8357426SChris Fallin } 640d8357426SChris Fallin 6415c8a603aSUlrich Weigand /// Get the ABI-dependent MachineEnv for managing register allocation. 6425c8a603aSUlrich Weigand pub fn machine_env(&self) -> &MachineEnv { 6435c8a603aSUlrich Weigand self.abi.machine_env(&self.sigs) 6445c8a603aSUlrich Weigand } 6455c8a603aSUlrich Weigand 646d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 647d8357426SChris Fallin /// (self.num_blocks() - 1)`. 648d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 649d8357426SChris Fallin self.block_ranges.len() 650d8357426SChris Fallin } 651d8357426SChris Fallin 6526fe69d00SNick Fitzgerald /// The number of lowered instructions. 6536fe69d00SNick Fitzgerald pub fn num_insts(&self) -> usize { 6546fe69d00SNick Fitzgerald self.insts.len() 6556fe69d00SNick Fitzgerald } 6566fe69d00SNick Fitzgerald 657d8357426SChris Fallin /// Get the successors for a block. 658a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 659a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 660a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 661d8357426SChris Fallin } 662d8357426SChris Fallin 663a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 664a0318f36SChris Fallin // Compute clobbered registers. 665a0318f36SChris Fallin let mut clobbered = vec![]; 666a0318f36SChris Fallin let mut clobbered_set = FxHashSet::default(); 667d8357426SChris Fallin 668a0318f36SChris Fallin // All moves are included in clobbers. 669a0318f36SChris Fallin for edit in ®alloc.edits { 670a0318f36SChris Fallin let Edit::Move { to, .. } = edit.1; 671a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 672a0318f36SChris Fallin let reg = RealReg::from(preg); 673a0318f36SChris Fallin if clobbered_set.insert(reg) { 674a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 675a0318f36SChris Fallin } 676a0318f36SChris Fallin } 677d8357426SChris Fallin } 678d8357426SChris Fallin 679a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 680a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 681a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 682a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 683a0318f36SChris Fallin // the current function from clobbers, because by 684a0318f36SChris Fallin // definition everything clobbered by the call can be 685a0318f36SChris Fallin // clobbered by this function without saving as well.) 686a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 687d8357426SChris Fallin continue; 688d8357426SChris Fallin } 689d8357426SChris Fallin 690a0318f36SChris Fallin let start = *start as usize; 691a0318f36SChris Fallin let end = *end as usize; 692a0318f36SChris Fallin let operands = &self.operands[start..end]; 693a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 694a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 695a0318f36SChris Fallin // We're interested only in writes (Mods or Defs). 696a0318f36SChris Fallin if operand.kind() == OperandKind::Use { 697a0318f36SChris Fallin continue; 698d8357426SChris Fallin } 699a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 700a0318f36SChris Fallin let reg = RealReg::from(preg); 701a0318f36SChris Fallin if clobbered_set.insert(reg) { 702a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 703a0318f36SChris Fallin } 70408353fccSChris Fallin } 705d8357426SChris Fallin } 706d8357426SChris Fallin 707a0318f36SChris Fallin // Also add explicitly-clobbered registers. 708b2e28b91SChris Fallin for preg in self 709b2e28b91SChris Fallin .clobbers 710b2e28b91SChris Fallin .get(&InsnIndex::new(i)) 711b2e28b91SChris Fallin .cloned() 712b2e28b91SChris Fallin .unwrap_or_default() 713b2e28b91SChris Fallin { 714a0318f36SChris Fallin let reg = RealReg::from(preg); 715a0318f36SChris Fallin if clobbered_set.insert(reg) { 716a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 717a0318f36SChris Fallin } 718a0318f36SChris Fallin } 719a0318f36SChris Fallin } 720d8357426SChris Fallin 721a0318f36SChris Fallin clobbered 722d8357426SChris Fallin } 723d8357426SChris Fallin 724a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 725a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 726a0318f36SChris Fallin /// the regalloc results as well. 727a0318f36SChris Fallin /// 728a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 729a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 730a0318f36SChris Fallin /// is consumed by the emission process. 73111a2ef01SChris Fallin pub fn emit( 732a0318f36SChris Fallin mut self, 733a0318f36SChris Fallin regalloc: ®alloc2::Output, 734a0318f36SChris Fallin want_disasm: bool, 73549dd8fd7SAlex Crichton flags: &settings::Flags, 7367eb89140SRemo Senekowitsch ctrl_plane: &mut ControlPlane, 73749dd8fd7SAlex Crichton ) -> EmitResult 738d8357426SChris Fallin where 739f18a1f14SNick Fitzgerald I: VCodeInst, 740d8357426SChris Fallin { 741a0318f36SChris Fallin // To write into disasm string. 742a0318f36SChris Fallin use core::fmt::Write; 743a0318f36SChris Fallin 7442b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 74572e6be93SChris Fallin let mut buffer = MachBuffer::new(); 74611a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 747d8357426SChris Fallin 74849dd8fd7SAlex Crichton // The first M MachLabels are reserved for block indices. 749a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 75049dd8fd7SAlex Crichton 75149dd8fd7SAlex Crichton // Register all allocated constants with the `MachBuffer` to ensure that 75249dd8fd7SAlex Crichton // any references to the constants during instructions can be handled 75349dd8fd7SAlex Crichton // correctly. 75449dd8fd7SAlex Crichton buffer.register_constants(&self.constants); 755d8357426SChris Fallin 756ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 757ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 758ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 759ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 760a0318f36SChris Fallin let block = BlockIndex::new(block); 761ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 762ef1b2d2fSChris Fallin cold_blocks.push(block); 763ef1b2d2fSChris Fallin } else { 764ef1b2d2fSChris Fallin final_order.push(block); 765ef1b2d2fSChris Fallin } 766ef1b2d2fSChris Fallin } 767d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 768ef1b2d2fSChris Fallin 769a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 770a0318f36SChris Fallin // number of spillslots. 771a0318f36SChris Fallin // 772a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 773a0318f36SChris Fallin // generate the prologue and set other info, but we can't 774a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 775a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 776a0318f36SChris Fallin // relatively cheap. 777a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 778a0318f36SChris Fallin self.abi.set_num_spillslots(regalloc.num_spillslots); 779a0318f36SChris Fallin self.abi.set_clobbered(clobbers); 78086652959SUlrich Weigand self.abi.compute_frame_layout(&self.sigs); 781a0318f36SChris Fallin 782ef1b2d2fSChris Fallin // Emit blocks. 783964c6087SChris Fallin let mut cur_srcloc = None; 78411a2ef01SChris Fallin let mut last_offset = None; 785a0318f36SChris Fallin let mut inst_offsets = vec![]; 7867eb89140SRemo Senekowitsch let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane)); 787a0318f36SChris Fallin 788a0318f36SChris Fallin let mut disasm = String::new(); 789a0318f36SChris Fallin 790a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 791d4a4d4f9SSingleAccretion inst_offsets.resize(self.insts.len(), NO_INST_OFFSET); 792a0318f36SChris Fallin } 793a0318f36SChris Fallin 794863659e0SChris Fallin // Count edits per block ahead of time; this is needed for 795863659e0SChris Fallin // lookahead island emission. (We could derive it per-block 796863659e0SChris Fallin // with binary search in the edit list, but it's more 797863659e0SChris Fallin // efficient to do it in one pass here.) 798863659e0SChris Fallin let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; 799863659e0SChris Fallin let mut edit_idx = 0; 800863659e0SChris Fallin for block in 0..self.num_blocks() { 801863659e0SChris Fallin let end_inst = self.block_ranges[block].1; 802863659e0SChris Fallin let start_edit_idx = edit_idx; 803863659e0SChris Fallin while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { 804863659e0SChris Fallin edit_idx += 1; 805863659e0SChris Fallin } 806863659e0SChris Fallin let end_edit_idx = edit_idx; 807863659e0SChris Fallin ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); 808863659e0SChris Fallin } 809863659e0SChris Fallin 810d8b29089SAnton Kirilov let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); 811475d1ba5SAlex Crichton let mut bb_padding = match flags.bb_padding_log2_minus_one() { 81249dd8fd7SAlex Crichton 0 => Vec::new(), 81349dd8fd7SAlex Crichton n => vec![0; 1 << (n - 1)], 81449dd8fd7SAlex Crichton }; 815475d1ba5SAlex Crichton let mut total_bb_padding = 0; 816d8b29089SAnton Kirilov 817863659e0SChris Fallin for (block_order_idx, &block) in final_order.iter().enumerate() { 8188d022434SBenjamin Bouvier trace!("emitting block {:?}", block); 81960e4a004SAfonso Bordado 82060e4a004SAfonso Bordado // Call the new block hook for state 82160e4a004SAfonso Bordado state.on_new_block(); 82260e4a004SAfonso Bordado 82360e4a004SAfonso Bordado // Emit NOPs to align the block. 82472e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 82572e6be93SChris Fallin while new_offset > buffer.cur_offset() { 826d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 82772e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 828a0318f36SChris Fallin nop.emit(&[], &mut buffer, &self.emit_info, &mut Default::default()); 829d8357426SChris Fallin } 83072e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 831d8357426SChris Fallin 832a0318f36SChris Fallin let do_emit = |inst: &I, 833a0318f36SChris Fallin allocs: &[Allocation], 834a0318f36SChris Fallin disasm: &mut String, 835a0318f36SChris Fallin buffer: &mut MachBuffer<I>, 836a0318f36SChris Fallin state: &mut I::State| { 8372986f6b0SChris Fallin if want_disasm && !inst.is_args() { 838a0318f36SChris Fallin let mut s = state.clone(); 839a0318f36SChris Fallin writeln!(disasm, " {}", inst.pretty_print_inst(allocs, &mut s)).unwrap(); 840a0318f36SChris Fallin } 841a0318f36SChris Fallin inst.emit(allocs, buffer, &self.emit_info, state); 842a0318f36SChris Fallin }; 843a0318f36SChris Fallin 844a0318f36SChris Fallin // Is this the first block? Emit the prologue directly if so. 845a0318f36SChris Fallin if block == self.entry { 8468d022434SBenjamin Bouvier trace!(" -> entry block"); 8478a9b1a90SBenjamin Bouvier buffer.start_srcloc(Default::default()); 8488a9b1a90SBenjamin Bouvier state.pre_sourceloc(Default::default()); 84986652959SUlrich Weigand for inst in &self.abi.gen_prologue() { 850a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 851a0318f36SChris Fallin } 852a0318f36SChris Fallin buffer.end_srcloc(); 853d9d64694SChris Fallin } 854d9d64694SChris Fallin 855a0318f36SChris Fallin // Now emit the regular block body. 85611a2ef01SChris Fallin 8577eb89140SRemo Senekowitsch buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut()); 858a0318f36SChris Fallin 859a0318f36SChris Fallin if want_disasm { 860a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 861a0318f36SChris Fallin } 862a0318f36SChris Fallin 86349dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 86411a2ef01SChris Fallin // Track BB starts. If we have backed up due to MachBuffer 86511a2ef01SChris Fallin // branch opts, note that the removed blocks were removed. 86611a2ef01SChris Fallin let cur_offset = buffer.cur_offset(); 86711a2ef01SChris Fallin if last_offset.is_some() && cur_offset <= last_offset.unwrap() { 86811a2ef01SChris Fallin for i in (0..bb_starts.len()).rev() { 86911a2ef01SChris Fallin if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { 87011a2ef01SChris Fallin break; 87111a2ef01SChris Fallin } 87211a2ef01SChris Fallin bb_starts[i] = None; 87311a2ef01SChris Fallin } 87411a2ef01SChris Fallin } 87511a2ef01SChris Fallin bb_starts.push(Some(cur_offset)); 87611a2ef01SChris Fallin last_offset = Some(cur_offset); 877800cf25bSChris Fallin } 87811a2ef01SChris Fallin 879d8b29089SAnton Kirilov if let Some(block_start) = I::gen_block_start( 880d8b29089SAnton Kirilov self.block_order.is_indirect_branch_target(block), 881d8b29089SAnton Kirilov is_forward_edge_cfi_enabled, 882d8b29089SAnton Kirilov ) { 883d8b29089SAnton Kirilov do_emit(&block_start, &[], &mut disasm, &mut buffer, &mut state); 884d8b29089SAnton Kirilov } 885d8b29089SAnton Kirilov 886a0318f36SChris Fallin for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { 887a0318f36SChris Fallin match inst_or_edit { 888a0318f36SChris Fallin InstOrEdit::Inst(iix) => { 889a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 890a0318f36SChris Fallin // If we need to produce debug info, 891a0318f36SChris Fallin // record the offset of each instruction 892a0318f36SChris Fallin // so that we can translate value-label 893a0318f36SChris Fallin // ranges to machine-code offsets. 894a0318f36SChris Fallin 895a0318f36SChris Fallin // Cold blocks violate monotonicity 896a0318f36SChris Fallin // assumptions elsewhere (that 897a0318f36SChris Fallin // instructions in inst-index order are in 898a0318f36SChris Fallin // order in machine code), so we omit 899a0318f36SChris Fallin // their offsets here. Value-label range 900a0318f36SChris Fallin // generation below will skip empty ranges 901a0318f36SChris Fallin // and ranges with to-offsets of zero. 902a0318f36SChris Fallin if !self.block_order.is_cold(block) { 903a0318f36SChris Fallin inst_offsets[iix.index()] = buffer.cur_offset(); 904a0318f36SChris Fallin } 905a0318f36SChris Fallin } 906a0318f36SChris Fallin 907a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 908a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 909964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 910964c6087SChris Fallin if cur_srcloc.is_some() { 91172e6be93SChris Fallin buffer.end_srcloc(); 912b691770fSChris Fallin } 91372e6be93SChris Fallin buffer.start_srcloc(srcloc); 914964c6087SChris Fallin cur_srcloc = Some(srcloc); 915b691770fSChris Fallin } 9168a9b1a90SBenjamin Bouvier state.pre_sourceloc(cur_srcloc.unwrap_or_default()); 917b691770fSChris Fallin 918a0318f36SChris Fallin // If this is a safepoint, compute a stack map 919a0318f36SChris Fallin // and pass it to the emit state. 920a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 921a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 922a0318f36SChris Fallin // Find the contiguous range of 923a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 924a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 925a0318f36SChris Fallin // for this instruction index. 926a0318f36SChris Fallin let safepoint_slots_start = regalloc 927a0318f36SChris Fallin .safepoint_slots 928a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 929a0318f36SChris Fallin if progpoint.inst() >= iix { 930a0318f36SChris Fallin std::cmp::Ordering::Greater 931a0318f36SChris Fallin } else { 932a0318f36SChris Fallin std::cmp::Ordering::Less 933a0318f36SChris Fallin } 934a0318f36SChris Fallin }) 935a0318f36SChris Fallin .unwrap_err(); 936a0318f36SChris Fallin 937a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 938a0318f36SChris Fallin .iter() 939a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 940a0318f36SChris Fallin { 941a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 942a0318f36SChris Fallin safepoint_slots.push(slot); 943a0318f36SChris Fallin } 944a0318f36SChris Fallin if !safepoint_slots.is_empty() { 945666c2554SChris Fallin let stack_map = self 946666c2554SChris Fallin .abi 947a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 94805bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 94908353fccSChris Fallin } 950a0318f36SChris Fallin } 95108353fccSChris Fallin 952a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 953a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 954de4af90aSYury Delendik 955a0318f36SChris Fallin // If the instruction we are about to emit is 956a0318f36SChris Fallin // a return, place an epilogue at this point 957a0318f36SChris Fallin // (and don't emit the return; the actual 958a0318f36SChris Fallin // epilogue will contain it). 959a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 96086652959SUlrich Weigand for inst in self.abi.gen_epilogue() { 961a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 962a0318f36SChris Fallin } 963c84d6be6SChris Fallin } else { 964a0318f36SChris Fallin // Emit the instruction! 965a0318f36SChris Fallin do_emit( 966a0318f36SChris Fallin &self.insts[iix.index()], 967a0318f36SChris Fallin allocs, 968a0318f36SChris Fallin &mut disasm, 969a0318f36SChris Fallin &mut buffer, 970a0318f36SChris Fallin &mut state, 971a0318f36SChris Fallin ); 972c84d6be6SChris Fallin } 973c84d6be6SChris Fallin } 974a0318f36SChris Fallin 975a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 976a0318f36SChris Fallin // Create a move/spill/reload instruction and 977a0318f36SChris Fallin // immediately emit it. 978a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 979a0318f36SChris Fallin (Some(from), Some(to)) => { 980a0318f36SChris Fallin // Reg-to-reg move. 981a0318f36SChris Fallin let from_rreg = Reg::from(from); 982a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 983a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 984a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 985a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 986a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 987a0318f36SChris Fallin } 988a0318f36SChris Fallin (Some(from), None) => { 989a0318f36SChris Fallin // Spill from register to spillslot. 990a0318f36SChris Fallin let to = to.as_stack().unwrap(); 991a0318f36SChris Fallin let from_rreg = RealReg::from(from); 992a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 993a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 994a0318f36SChris Fallin } 995a0318f36SChris Fallin (None, Some(to)) => { 996a0318f36SChris Fallin // Load from spillslot to register. 997a0318f36SChris Fallin let from = from.as_stack().unwrap(); 998a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 999a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 1000a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 1001a0318f36SChris Fallin } 1002a0318f36SChris Fallin (None, None) => { 1003a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 1004a0318f36SChris Fallin } 1005a0318f36SChris Fallin } 1006a0318f36SChris Fallin } 1007c84d6be6SChris Fallin } 1008d8357426SChris Fallin } 1009b691770fSChris Fallin 1010964c6087SChris Fallin if cur_srcloc.is_some() { 101172e6be93SChris Fallin buffer.end_srcloc(); 1012964c6087SChris Fallin cur_srcloc = None; 1013b691770fSChris Fallin } 101472e6be93SChris Fallin 101549dd8fd7SAlex Crichton // Do we need an island? Get the worst-case size of the next BB, add 101649dd8fd7SAlex Crichton // it to the optional padding behind the block, and pass this to the 101749dd8fd7SAlex Crichton // `MachBuffer` to determine if an island is necessary. 101849dd8fd7SAlex Crichton let worst_case_next_bb = if block_order_idx < final_order.len() - 1 { 1019863659e0SChris Fallin let next_block = final_order[block_order_idx + 1]; 1020863659e0SChris Fallin let next_block_range = self.block_ranges[next_block.index()]; 1021863659e0SChris Fallin let next_block_size = 1022863659e0SChris Fallin (next_block_range.1.index() - next_block_range.0.index()) as u32; 1023863659e0SChris Fallin let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; 102449dd8fd7SAlex Crichton I::worst_case_size() * (next_block_size + next_block_ra_insertions) 102549dd8fd7SAlex Crichton } else { 102649dd8fd7SAlex Crichton 0 102749dd8fd7SAlex Crichton }; 102849dd8fd7SAlex Crichton let padding = if bb_padding.is_empty() { 102949dd8fd7SAlex Crichton 0 103049dd8fd7SAlex Crichton } else { 103149dd8fd7SAlex Crichton bb_padding.len() as u32 + I::LabelUse::ALIGN - 1 103249dd8fd7SAlex Crichton }; 103349dd8fd7SAlex Crichton if buffer.island_needed(padding + worst_case_next_bb) { 1034f8c03d5aSAlex Crichton buffer.emit_island(padding + worst_case_next_bb, ctrl_plane); 103572e6be93SChris Fallin } 103649dd8fd7SAlex Crichton 103749dd8fd7SAlex Crichton // Insert padding, if configured, to stress the `MachBuffer`'s 103849dd8fd7SAlex Crichton // relocation and island calculations. 1039475d1ba5SAlex Crichton // 1040475d1ba5SAlex Crichton // Padding can get quite large during fuzzing though so place a 1041475d1ba5SAlex Crichton // total cap on it where when a per-function threshold is exceeded 1042475d1ba5SAlex Crichton // the padding is turned back down to zero. This avoids a small-ish 1043475d1ba5SAlex Crichton // test case generating a GB+ memory footprint in Cranelift for 1044475d1ba5SAlex Crichton // example. 104549dd8fd7SAlex Crichton if !bb_padding.is_empty() { 104649dd8fd7SAlex Crichton buffer.put_data(&bb_padding); 104749dd8fd7SAlex Crichton buffer.align_to(I::LabelUse::ALIGN); 1048475d1ba5SAlex Crichton total_bb_padding += bb_padding.len(); 1049475d1ba5SAlex Crichton if total_bb_padding > (150 << 20) { 1050475d1ba5SAlex Crichton bb_padding = Vec::new(); 1051475d1ba5SAlex Crichton } 105272e6be93SChris Fallin } 1053d8357426SChris Fallin } 1054d8357426SChris Fallin 1055d4a4d4f9SSingleAccretion // Do any optimizations on branches at tail of buffer, as if we had 1056d4a4d4f9SSingleAccretion // bound one last label. 1057d4a4d4f9SSingleAccretion buffer.optimize_branches(ctrl_plane); 1058d4a4d4f9SSingleAccretion 10597eb89140SRemo Senekowitsch // emission state is not needed anymore, move control plane back out 10607eb89140SRemo Senekowitsch *ctrl_plane = state.take_ctrl_plane(); 10617eb89140SRemo Senekowitsch 1062a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1063de4af90aSYury Delendik 106411a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 106511a2ef01SChris Fallin let mut bb_edges = vec![]; 1066a0318f36SChris Fallin let mut bb_offsets = vec![]; 106749dd8fd7SAlex Crichton if flags.machine_code_cfg_info() { 106811a2ef01SChris Fallin for block in 0..self.num_blocks() { 106911a2ef01SChris Fallin if bb_starts[block].is_none() { 107011a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 107111a2ef01SChris Fallin continue; 107211a2ef01SChris Fallin } 107311a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 107411a2ef01SChris Fallin 1075a0318f36SChris Fallin bb_offsets.push(from); 107611a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1077a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1078a0318f36SChris Fallin for &succ in succs.iter() { 1079a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 108011a2ef01SChris Fallin bb_edges.push((from, to)); 108111a2ef01SChris Fallin } 108211a2ef01SChris Fallin } 1083800cf25bSChris Fallin } 108411a2ef01SChris Fallin 1085d4a4d4f9SSingleAccretion self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len); 1086a0318f36SChris Fallin let value_labels_ranges = 1087a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1088a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1089a0318f36SChris Fallin 1090a0318f36SChris Fallin EmitResult { 109149dd8fd7SAlex Crichton buffer: buffer.finish(&self.constants, ctrl_plane), 1092a0318f36SChris Fallin bb_offsets, 1093a0318f36SChris Fallin bb_edges, 1094a0318f36SChris Fallin func_body_len, 1095a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10969c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10979c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1098a0318f36SChris Fallin value_labels_ranges, 1099a0318f36SChris Fallin frame_size, 1100a0318f36SChris Fallin } 1101d8357426SChris Fallin } 1102d8357426SChris Fallin 1103d4a4d4f9SSingleAccretion fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) { 1104d4a4d4f9SSingleAccretion if self.debug_value_labels.is_empty() { 1105d4a4d4f9SSingleAccretion return; 1106d4a4d4f9SSingleAccretion } 1107d4a4d4f9SSingleAccretion 1108d4a4d4f9SSingleAccretion // During emission, branch removal can make offsets of instructions incorrect. 1109d4a4d4f9SSingleAccretion // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj] 1110d4a4d4f9SSingleAccretion // It will be recorded as (say): [30] [34] [38] [42] [<would be 46>] 1111d4a4d4f9SSingleAccretion // When the jumps get removed we are left with (in "inst_offsets"): 1112d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1113d4a4d4f9SSingleAccretion // [30] [34] [38] [42] [34] 1114d4a4d4f9SSingleAccretion // Which violates the monotonicity invariant. This method sets offsets of these 1115d4a4d4f9SSingleAccretion // removed instructions such as to make them appear zero-sized: 1116d4a4d4f9SSingleAccretion // [insi][jmp0][jmp1][jmp2][insj][...] 1117d4a4d4f9SSingleAccretion // [30] [34] [34] [34] [34] 1118d4a4d4f9SSingleAccretion // 1119d4a4d4f9SSingleAccretion let mut next_offset = func_body_len; 1120d4a4d4f9SSingleAccretion for inst_index in (0..(inst_offsets.len() - 1)).rev() { 1121d4a4d4f9SSingleAccretion let inst_offset = inst_offsets[inst_index]; 1122d4a4d4f9SSingleAccretion 1123d4a4d4f9SSingleAccretion // Not all instructions get their offsets recorded. 1124d4a4d4f9SSingleAccretion if inst_offset == NO_INST_OFFSET { 1125d4a4d4f9SSingleAccretion continue; 1126d4a4d4f9SSingleAccretion } 1127d4a4d4f9SSingleAccretion 1128d4a4d4f9SSingleAccretion if inst_offset > next_offset { 1129d4a4d4f9SSingleAccretion trace!( 1130d4a4d4f9SSingleAccretion "Fixing code offset of the removed Inst {}: {} -> {}", 1131d4a4d4f9SSingleAccretion inst_index, 1132d4a4d4f9SSingleAccretion inst_offset, 1133d4a4d4f9SSingleAccretion next_offset 1134d4a4d4f9SSingleAccretion ); 1135d4a4d4f9SSingleAccretion inst_offsets[inst_index] = next_offset; 1136d4a4d4f9SSingleAccretion continue; 1137d4a4d4f9SSingleAccretion } 1138d4a4d4f9SSingleAccretion 1139d4a4d4f9SSingleAccretion next_offset = inst_offset; 1140d4a4d4f9SSingleAccretion } 1141d4a4d4f9SSingleAccretion } 1142d4a4d4f9SSingleAccretion 1143a0318f36SChris Fallin fn compute_value_labels_ranges( 1144a0318f36SChris Fallin &self, 1145a0318f36SChris Fallin regalloc: ®alloc2::Output, 1146a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1147a0318f36SChris Fallin func_body_len: u32, 1148a0318f36SChris Fallin ) -> ValueLabelsRanges { 1149a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1150602006ffSbjorn3 return ValueLabelsRanges::default(); 1151997fab55SChris Fallin } 1152997fab55SChris Fallin 1153a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1154a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1155a0318f36SChris Fallin let ranges = value_labels_ranges 1156a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1157a0318f36SChris Fallin .or_insert_with(|| vec![]); 1158a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1159a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1160a0318f36SChris Fallin func_body_len 1161a0318f36SChris Fallin } else { 1162a0318f36SChris Fallin inst_offsets[to.inst().index()] 1163a0318f36SChris Fallin }; 1164a0318f36SChris Fallin 1165d4a4d4f9SSingleAccretion // Empty ranges or unavailable offsets can happen 1166d4a4d4f9SSingleAccretion // due to cold blocks and branch removal (see above). 1167d4a4d4f9SSingleAccretion if from_offset == NO_INST_OFFSET 1168d4a4d4f9SSingleAccretion || to_offset == NO_INST_OFFSET 1169d4a4d4f9SSingleAccretion || from_offset == to_offset 1170d4a4d4f9SSingleAccretion { 1171a0318f36SChris Fallin continue; 117276d61504Sbjorn3 } 117376d61504Sbjorn3 1174a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1175a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1176a0318f36SChris Fallin } else { 11777b16eccdSSingleAccretion let slot = alloc.as_stack().unwrap(); 11787b16eccdSSingleAccretion let sp_offset = self.abi.get_spillslot_offset(slot); 11797b16eccdSSingleAccretion let sp_to_caller_sp_offset = self.abi.nominal_sp_to_caller_sp_offset(); 11807b16eccdSSingleAccretion let caller_sp_to_cfa_offset = 11817b16eccdSSingleAccretion crate::isa::unwind::systemv::caller_sp_to_cfa_offset(); 11827b16eccdSSingleAccretion let cfa_to_sp_offset = -((sp_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64); 11837b16eccdSSingleAccretion LabelValueLoc::CFAOffset(cfa_to_sp_offset + sp_offset) 1184a0318f36SChris Fallin }; 1185a0318f36SChris Fallin 1186a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1187a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1188a0318f36SChris Fallin // instruction; that is the same as the end of another 1189a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1190a0318f36SChris Fallin // we are past the previous instruction's end. 1191d4a4d4f9SSingleAccretion let start = from_offset + 1; 1192d4a4d4f9SSingleAccretion 1193a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1194a0318f36SChris Fallin // *include* the end of the last 1195a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1196a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1197a0318f36SChris Fallin // the first instruction not covered. That 1198a0318f36SChris Fallin // instruction's start is the same as the end of the 1199a0318f36SChris Fallin // last instruction that is included, so we go one 1200a0318f36SChris Fallin // byte further to be sure to include it. 1201d4a4d4f9SSingleAccretion let end = to_offset + 1; 1202d4a4d4f9SSingleAccretion 12037b16eccdSSingleAccretion // Coalesce adjacent ranges that for the same location 12047b16eccdSSingleAccretion // to minimize output size here and for the consumers. 12057b16eccdSSingleAccretion if let Some(last_loc_range) = ranges.last_mut() { 12067b16eccdSSingleAccretion if last_loc_range.loc == loc && last_loc_range.end == start { 12077b16eccdSSingleAccretion trace!( 12087b16eccdSSingleAccretion "Extending debug range for VL{} in {:?} to {}", 12097b16eccdSSingleAccretion label, 12107b16eccdSSingleAccretion loc, 12117b16eccdSSingleAccretion end 12127b16eccdSSingleAccretion ); 12137b16eccdSSingleAccretion last_loc_range.end = end; 12147b16eccdSSingleAccretion continue; 12157b16eccdSSingleAccretion } 12167b16eccdSSingleAccretion } 12177b16eccdSSingleAccretion 1218d4a4d4f9SSingleAccretion trace!( 1219d4a4d4f9SSingleAccretion "Recording debug range for VL{} in {:?}: [Inst {}..Inst {}) [{}..{})", 1220d4a4d4f9SSingleAccretion label, 1221d4a4d4f9SSingleAccretion loc, 1222d4a4d4f9SSingleAccretion from.inst().index(), 1223d4a4d4f9SSingleAccretion to.inst().index(), 1224d4a4d4f9SSingleAccretion start, 1225d4a4d4f9SSingleAccretion end 1226d4a4d4f9SSingleAccretion ); 1227d4a4d4f9SSingleAccretion 1228d4a4d4f9SSingleAccretion ranges.push(ValueLocRange { loc, start, end }); 1229a0318f36SChris Fallin } 1230a0318f36SChris Fallin 1231a0318f36SChris Fallin value_labels_ranges 1232c84d6be6SChris Fallin } 1233c84d6be6SChris Fallin 1234d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1235d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1236a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1237d8357426SChris Fallin } 12382154c63dSAlex Crichton 1239fef8a90fSChris Fallin pub fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 1240fef8a90fSChris Fallin Self::resolve_vreg_alias_impl(&self.vreg_aliases, from) 1241fef8a90fSChris Fallin } 1242fef8a90fSChris Fallin 1243fef8a90fSChris Fallin /// Implementation of alias resolution. Separate helper that does 1244fef8a90fSChris Fallin /// not borrow `self` in order to allow working around borrowing 1245fef8a90fSChris Fallin /// restrictions. 1246fef8a90fSChris Fallin fn resolve_vreg_alias_impl( 1247fef8a90fSChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 1248fef8a90fSChris Fallin from: regalloc2::VReg, 1249fef8a90fSChris Fallin ) -> regalloc2::VReg { 1250fef8a90fSChris Fallin // We prevent cycles from existing by resolving targets of 1251fef8a90fSChris Fallin // aliases eagerly before setting them. If the target resolves 1252fef8a90fSChris Fallin // to the origin of the alias, then a cycle would be created 1253fef8a90fSChris Fallin // and the alias is disallowed. Because of the structure of 1254fef8a90fSChris Fallin // SSA code (one instruction can refer to another's defs but 1255fef8a90fSChris Fallin // not vice-versa, except indirectly through 1256fef8a90fSChris Fallin // phis/blockparams), cycles should not occur as we use 1257fef8a90fSChris Fallin // aliases to redirect vregs to the temps that actually define 1258fef8a90fSChris Fallin // them. 1259fef8a90fSChris Fallin 1260fef8a90fSChris Fallin let mut vreg = from; 1261fef8a90fSChris Fallin while let Some(to) = aliases.get(&vreg) { 1262fef8a90fSChris Fallin vreg = *to; 1263fef8a90fSChris Fallin } 1264fef8a90fSChris Fallin vreg 1265fef8a90fSChris Fallin } 1266fef8a90fSChris Fallin 12672154c63dSAlex Crichton #[inline] 12682154c63dSAlex Crichton fn assert_no_vreg_aliases<'a>(&self, list: &'a [VReg]) -> &'a [VReg] { 12692154c63dSAlex Crichton for vreg in list { 12702154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 12712154c63dSAlex Crichton } 12722154c63dSAlex Crichton list 12732154c63dSAlex Crichton } 12742154c63dSAlex Crichton 12752154c63dSAlex Crichton #[inline] 12762154c63dSAlex Crichton fn assert_not_vreg_alias(&self, vreg: VReg) -> VReg { 1277fef8a90fSChris Fallin debug_assert!(self.resolve_vreg_alias(vreg) == vreg); 12782154c63dSAlex Crichton vreg 12792154c63dSAlex Crichton } 12802154c63dSAlex Crichton 12812154c63dSAlex Crichton #[inline] 12822154c63dSAlex Crichton fn assert_operand_not_vreg_alias(&self, op: Operand) -> Operand { 12832154c63dSAlex Crichton // It should be true by construction that `Operand`s do not contain any 12842154c63dSAlex Crichton // aliased vregs since they're all collected and mapped when the VCode 12852154c63dSAlex Crichton // is itself constructed. 12862154c63dSAlex Crichton self.assert_not_vreg_alias(op.vreg()); 12872154c63dSAlex Crichton op 12882154c63dSAlex Crichton } 1289f466aa26SChris Fallin 1290*9e4d4462SChris Fallin /// Get the type of a VReg. 1291*9e4d4462SChris Fallin pub fn vreg_type(&self, vreg: VReg) -> Type { 1292*9e4d4462SChris Fallin self.vreg_types[vreg.vreg()] 1293*9e4d4462SChris Fallin } 1294*9e4d4462SChris Fallin 1295f466aa26SChris Fallin /// Get the fact, if any, for a given VReg. 1296f466aa26SChris Fallin pub fn vreg_fact(&self, vreg: VReg) -> Option<&Fact> { 1297fef8a90fSChris Fallin let vreg = self.resolve_vreg_alias(vreg); 1298*9e4d4462SChris Fallin self.facts[vreg.vreg()].as_ref() 1299f466aa26SChris Fallin } 1300f466aa26SChris Fallin 1301f466aa26SChris Fallin /// Does a given instruction define any facts? 1302f466aa26SChris Fallin pub fn inst_defines_facts(&self, inst: InsnIndex) -> bool { 1303f466aa26SChris Fallin self.inst_operands(inst) 1304f466aa26SChris Fallin .iter() 1305f466aa26SChris Fallin .filter(|o| o.kind() == OperandKind::Def) 1306f466aa26SChris Fallin .map(|o| o.vreg()) 13072e7f9414SChris Fallin .any(|vreg| self.facts[vreg.vreg()].is_some()) 1308f466aa26SChris Fallin } 1309f466aa26SChris Fallin } 1310f466aa26SChris Fallin 1311f466aa26SChris Fallin impl<I: VCodeInst> std::ops::Index<InsnIndex> for VCode<I> { 1312f466aa26SChris Fallin type Output = I; 1313f466aa26SChris Fallin fn index(&self, idx: InsnIndex) -> &Self::Output { 1314f466aa26SChris Fallin &self.insts[idx.index()] 1315f466aa26SChris Fallin } 1316d8357426SChris Fallin } 1317d8357426SChris Fallin 1318d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1319a0318f36SChris Fallin fn num_insts(&self) -> usize { 1320a0318f36SChris Fallin self.insts.len() 1321d8357426SChris Fallin } 1322d8357426SChris Fallin 1323a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1324a0318f36SChris Fallin self.block_ranges.len() 1325d8357426SChris Fallin } 1326d8357426SChris Fallin 1327a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1328a0318f36SChris Fallin self.entry 1329d8357426SChris Fallin } 1330d8357426SChris Fallin 1331a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1332a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1333a0318f36SChris Fallin InstRange::forward(start, end) 1334d8357426SChris Fallin } 1335d8357426SChris Fallin 1336a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1337a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1338a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1339d8357426SChris Fallin } 1340d8357426SChris Fallin 1341a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1342a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1343a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1344d8357426SChris Fallin } 1345d8357426SChris Fallin 1346a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1347c5379051STrevor Elliott // As a special case we don't return block params for the entry block, as all the arguments 1348c5379051STrevor Elliott // will be defined by the `Inst::Args` instruction. 1349c5379051STrevor Elliott if block == self.entry { 1350c5379051STrevor Elliott return &[]; 1351c5379051STrevor Elliott } 1352c5379051STrevor Elliott 1353a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 13542154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 13552154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 13562154c63dSAlex Crichton // double-check just to be sure. 13572154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1358d8357426SChris Fallin } 1359d8357426SChris Fallin 1360a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1361a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1362a0318f36SChris Fallin let succ_ranges = 1363a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1364a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 13652154c63dSAlex Crichton let ret = &self.branch_block_args 13662154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 13672154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1368d8357426SChris Fallin } 1369d8357426SChris Fallin 1370a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1371a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1372c5379051STrevor Elliott // We treat blocks terminated by an unconditional trap like a return for regalloc. 1373c5379051STrevor Elliott MachTerminator::None => self.insts[insn.index()].is_trap(), 13744154fa47SNick Fitzgerald MachTerminator::Ret | MachTerminator::RetCall => true, 13754154fa47SNick Fitzgerald MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false, 1376d8357426SChris Fallin } 1377d8357426SChris Fallin } 1378d8357426SChris Fallin 1379a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1380a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 13815774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1382a0318f36SChris Fallin _ => false, 1383a0318f36SChris Fallin } 138471768bb6SChris Fallin } 138571768bb6SChris Fallin 1386a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1387a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1388d8357426SChris Fallin } 1389d8357426SChris Fallin 1390a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1391a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 13922154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 13932154c63dSAlex Crichton for op in ret { 13942154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*op); 13952154c63dSAlex Crichton } 13962154c63dSAlex Crichton ret 1397d8357426SChris Fallin } 1398d8357426SChris Fallin 1399b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1400b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1401be6f060aSChris Fallin } 1402be6f060aSChris Fallin 1403a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1404a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1405d8357426SChris Fallin } 1406d8357426SChris Fallin 1407a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 14082154c63dSAlex Crichton self.assert_no_vreg_aliases(&self.reftyped_vregs[..]) 1409d8357426SChris Fallin } 1410d8357426SChris Fallin 1411a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 14122154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 14132154c63dSAlex Crichton // generated and aliases are fully defined, so no double-check that 14142154c63dSAlex Crichton // aliases are not lingering. 14152154c63dSAlex Crichton for (vreg, ..) in self.debug_value_labels.iter() { 14162154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 14172154c63dSAlex Crichton } 1418a0318f36SChris Fallin &self.debug_value_labels[..] 1419d8357426SChris Fallin } 1420d8357426SChris Fallin 1421a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1422a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1423d8357426SChris Fallin } 1424d8357426SChris Fallin 1425a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1426a0318f36SChris Fallin // At least the s390x backend requires this, because the 1427a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1428a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1429a0318f36SChris Fallin true 1430d8357426SChris Fallin } 1431d8357426SChris Fallin } 1432d8357426SChris Fallin 1433d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1434d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1435a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1436a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1437a0318f36SChris Fallin 1438a0318f36SChris Fallin let mut state = Default::default(); 1439a0318f36SChris Fallin 1440a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1441a0318f36SChris Fallin alias_keys.sort_unstable(); 1442a0318f36SChris Fallin for key in alias_keys { 1443a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1444a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1445a0318f36SChris Fallin } 1446d8357426SChris Fallin 1447d8357426SChris Fallin for block in 0..self.num_blocks() { 1448a0318f36SChris Fallin let block = BlockIndex::new(block); 1449a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1450a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1451a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1452d8357426SChris Fallin } 1453a0318f36SChris Fallin for succ in self.succs(block) { 1454a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1455a0318f36SChris Fallin } 1456a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1457a0318f36SChris Fallin writeln!( 1458a0318f36SChris Fallin f, 1459a0318f36SChris Fallin " (instruction range: {} .. {})", 1460a0318f36SChris Fallin start.index(), 1461a0318f36SChris Fallin end.index() 1462a0318f36SChris Fallin )?; 1463a0318f36SChris Fallin for inst in start.index()..end.index() { 1464a0318f36SChris Fallin writeln!( 1465a0318f36SChris Fallin f, 1466a0318f36SChris Fallin " Inst {}: {}", 1467a0318f36SChris Fallin inst, 1468a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1469a0318f36SChris Fallin )?; 1470f466aa26SChris Fallin for operand in self.inst_operands(InsnIndex::new(inst)) { 1471f466aa26SChris Fallin if operand.kind() == OperandKind::Def { 1472f466aa26SChris Fallin if let Some(fact) = &self.facts[operand.vreg().vreg()] { 1473fef8a90fSChris Fallin writeln!(f, " v{} ! {}", operand.vreg().vreg(), fact)?; 1474f466aa26SChris Fallin } 1475f466aa26SChris Fallin } 1476f466aa26SChris Fallin } 1477d8357426SChris Fallin } 1478d8357426SChris Fallin } 1479d8357426SChris Fallin 1480d8357426SChris Fallin writeln!(f, "}}")?; 1481d8357426SChris Fallin Ok(()) 1482d8357426SChris Fallin } 1483d8357426SChris Fallin } 1484d8357426SChris Fallin 1485d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder. 1486d94173eaSTrevor Elliott pub struct VRegAllocator<I> { 1487d94173eaSTrevor Elliott /// Next virtual register number to allocate. 1488d94173eaSTrevor Elliott next_vreg: usize, 1489d94173eaSTrevor Elliott 1490d94173eaSTrevor Elliott /// VReg IR-level types. 1491d94173eaSTrevor Elliott vreg_types: Vec<Type>, 1492d94173eaSTrevor Elliott 1493d94173eaSTrevor Elliott /// A set with the same contents as `reftyped_vregs`, in order to 1494d94173eaSTrevor Elliott /// avoid inserting more than once. 1495d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet<VReg>, 1496d94173eaSTrevor Elliott 1497d94173eaSTrevor Elliott /// Reference-typed `regalloc2::VReg`s. The regalloc requires 1498d94173eaSTrevor Elliott /// these in a dense slice (as opposed to querying the 1499d94173eaSTrevor Elliott /// reftype-status of each vreg) for efficient iteration. 1500d94173eaSTrevor Elliott reftyped_vregs: Vec<VReg>, 1501d94173eaSTrevor Elliott 150217eeba0eSChris Fallin /// A deferred error, to be bubbled up to the top level of the 150317eeba0eSChris Fallin /// lowering algorithm. We take this approach because we cannot 150417eeba0eSChris Fallin /// currently propagate a `Result` upward through ISLE code (the 150517eeba0eSChris Fallin /// lowering rules) or some ABI code. 150617eeba0eSChris Fallin deferred_error: Option<CodegenError>, 150717eeba0eSChris Fallin 1508f466aa26SChris Fallin /// Facts on VRegs, for proof-carrying code. 1509f466aa26SChris Fallin facts: Vec<Option<Fact>>, 1510f466aa26SChris Fallin 1511d94173eaSTrevor Elliott /// The type of instruction that this allocator makes registers for. 1512d94173eaSTrevor Elliott _inst: core::marker::PhantomData<I>, 1513d94173eaSTrevor Elliott } 1514d94173eaSTrevor Elliott 1515d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> { 1516d94173eaSTrevor Elliott /// Make a new VRegAllocator. 1517d94173eaSTrevor Elliott pub fn new() -> Self { 1518d94173eaSTrevor Elliott Self { 1519d94173eaSTrevor Elliott next_vreg: first_user_vreg_index(), 1520d94173eaSTrevor Elliott vreg_types: vec![], 1521f466aa26SChris Fallin facts: vec![], 1522d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet::default(), 1523d94173eaSTrevor Elliott reftyped_vregs: vec![], 152417eeba0eSChris Fallin deferred_error: None, 1525d94173eaSTrevor Elliott _inst: core::marker::PhantomData::default(), 1526d94173eaSTrevor Elliott } 1527d94173eaSTrevor Elliott } 1528d94173eaSTrevor Elliott 1529d94173eaSTrevor Elliott /// Allocate a fresh ValueRegs. 1530d94173eaSTrevor Elliott pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> { 153117eeba0eSChris Fallin if self.deferred_error.is_some() { 153217eeba0eSChris Fallin return Err(CodegenError::CodeTooLarge); 153317eeba0eSChris Fallin } 1534d94173eaSTrevor Elliott let v = self.next_vreg; 1535d94173eaSTrevor Elliott let (regclasses, tys) = I::rc_for_type(ty)?; 1536d94173eaSTrevor Elliott self.next_vreg += regclasses.len(); 1537d94173eaSTrevor Elliott if self.next_vreg >= VReg::MAX { 1538d94173eaSTrevor Elliott return Err(CodegenError::CodeTooLarge); 1539d94173eaSTrevor Elliott } 1540d94173eaSTrevor Elliott 1541d94173eaSTrevor Elliott let regs: ValueRegs<Reg> = match regclasses { 1542d94173eaSTrevor Elliott &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), 1543d94173eaSTrevor Elliott &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), 1544d94173eaSTrevor Elliott // We can extend this if/when we support 32-bit targets; e.g., 1545d94173eaSTrevor Elliott // an i128 on a 32-bit machine will need up to four machine regs 1546d94173eaSTrevor Elliott // for a `Value`. 1547d94173eaSTrevor Elliott _ => panic!("Value must reside in 1 or 2 registers"), 1548d94173eaSTrevor Elliott }; 1549d94173eaSTrevor Elliott for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { 1550d94173eaSTrevor Elliott self.set_vreg_type(reg.to_virtual_reg().unwrap(), reg_ty); 1551d94173eaSTrevor Elliott } 1552f466aa26SChris Fallin 1553f466aa26SChris Fallin // Create empty facts for each allocated vreg. 1554f466aa26SChris Fallin self.facts 1555f466aa26SChris Fallin .resize(usize::try_from(self.next_vreg).unwrap(), None); 1556f466aa26SChris Fallin 1557d94173eaSTrevor Elliott Ok(regs) 1558d94173eaSTrevor Elliott } 1559d94173eaSTrevor Elliott 156017eeba0eSChris Fallin /// Allocate a fresh ValueRegs, deferring any out-of-vregs 156117eeba0eSChris Fallin /// errors. This is useful in places where we cannot bubble a 156217eeba0eSChris Fallin /// `CodegenResult` upward easily, and which are known to be 156317eeba0eSChris Fallin /// invoked from within the lowering loop that checks the deferred 156417eeba0eSChris Fallin /// error status below. 156517eeba0eSChris Fallin pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg> { 156617eeba0eSChris Fallin match self.alloc(ty) { 156717eeba0eSChris Fallin Ok(x) => x, 156817eeba0eSChris Fallin Err(e) => { 156917eeba0eSChris Fallin self.deferred_error = Some(e); 157017eeba0eSChris Fallin self.bogus_for_deferred_error(ty) 157117eeba0eSChris Fallin } 157217eeba0eSChris Fallin } 157317eeba0eSChris Fallin } 157417eeba0eSChris Fallin 157517eeba0eSChris Fallin /// Take any deferred error that was accumulated by `alloc_with_deferred_error`. 157617eeba0eSChris Fallin pub fn take_deferred_error(&mut self) -> Option<CodegenError> { 157717eeba0eSChris Fallin self.deferred_error.take() 157817eeba0eSChris Fallin } 157917eeba0eSChris Fallin 158017eeba0eSChris Fallin /// Produce an bogus VReg placeholder with the proper number of 158117eeba0eSChris Fallin /// registers for the given type. This is meant to be used with 158217eeba0eSChris Fallin /// deferred allocation errors (see `Lower::alloc_tmp()`). 158317eeba0eSChris Fallin fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg> { 158417eeba0eSChris Fallin let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type"); 158517eeba0eSChris Fallin match regclasses { 158617eeba0eSChris Fallin &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()), 158717eeba0eSChris Fallin &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()), 158817eeba0eSChris Fallin _ => panic!("Value must reside in 1 or 2 registers"), 158917eeba0eSChris Fallin } 159017eeba0eSChris Fallin } 159117eeba0eSChris Fallin 1592d94173eaSTrevor Elliott /// Set the type of this virtual register. 1593d94173eaSTrevor Elliott pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 1594d94173eaSTrevor Elliott if self.vreg_types.len() <= vreg.index() { 159570bca801STrevor Elliott self.vreg_types.resize(vreg.index() + 1, ir::types::INVALID); 1596d94173eaSTrevor Elliott } 1597d94173eaSTrevor Elliott self.vreg_types[vreg.index()] = ty; 1598d94173eaSTrevor Elliott if is_reftype(ty) { 1599d94173eaSTrevor Elliott let vreg: VReg = vreg.into(); 1600d94173eaSTrevor Elliott if self.reftyped_vregs_set.insert(vreg) { 1601d94173eaSTrevor Elliott self.reftyped_vregs.push(vreg); 1602d94173eaSTrevor Elliott } 1603d94173eaSTrevor Elliott } 1604d94173eaSTrevor Elliott } 1605f466aa26SChris Fallin 1606f466aa26SChris Fallin /// Set the proof-carrying code fact on a given virtual register. 1607f466aa26SChris Fallin /// 1608f466aa26SChris Fallin /// Returns the old fact, if any (only one fact can be stored). 1609f466aa26SChris Fallin pub fn set_fact(&mut self, vreg: VirtualReg, fact: Fact) -> Option<Fact> { 1610fef8a90fSChris Fallin trace!("vreg {:?} has fact: {:?}", vreg, fact); 1611f466aa26SChris Fallin self.facts[vreg.index()].replace(fact) 1612f466aa26SChris Fallin } 1613f466aa26SChris Fallin 1614fef8a90fSChris Fallin /// Take (and remove) a fact about a VReg. Used when setting up 1615fef8a90fSChris Fallin /// aliases: we want to move a fact from the alias vreg to the 1616fef8a90fSChris Fallin /// aliased vreg, to preserve facts about a value that were stated 1617fef8a90fSChris Fallin /// before we lowered its producer. 1618fef8a90fSChris Fallin pub fn take_fact(&mut self, vreg: VirtualReg) -> Option<Fact> { 1619fef8a90fSChris Fallin self.facts[vreg.index()].take() 1620fef8a90fSChris Fallin } 1621fef8a90fSChris Fallin 1622f466aa26SChris Fallin /// Allocate a fresh ValueRegs, with a given fact to apply if 1623f466aa26SChris Fallin /// the value fits in one VReg. 1624f466aa26SChris Fallin pub fn alloc_with_maybe_fact( 1625f466aa26SChris Fallin &mut self, 1626f466aa26SChris Fallin ty: Type, 1627f466aa26SChris Fallin fact: Option<Fact>, 1628f466aa26SChris Fallin ) -> CodegenResult<ValueRegs<Reg>> { 1629f466aa26SChris Fallin let result = self.alloc(ty)?; 1630f466aa26SChris Fallin 1631f466aa26SChris Fallin // Ensure that we don't lose a fact on a value that splits 1632f466aa26SChris Fallin // into multiple VRegs. 1633f466aa26SChris Fallin assert!(result.len() == 1 || fact.is_none()); 1634f466aa26SChris Fallin if let Some(fact) = fact { 1635f466aa26SChris Fallin self.set_fact(result.regs()[0].to_virtual_reg().unwrap(), fact); 1636f466aa26SChris Fallin } 1637f466aa26SChris Fallin 1638f466aa26SChris Fallin Ok(result) 1639f466aa26SChris Fallin } 1640d94173eaSTrevor Elliott } 1641d94173eaSTrevor Elliott 164283f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 164383f182b3SAndrew Brown /// [MachBuffer]. 164483f182b3SAndrew Brown /// 164583f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 164683f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are 164783f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 164883f182b3SAndrew Brown /// values are inserted. 164983f182b3SAndrew Brown /// 165083f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 165183f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 165283f182b3SAndrew Brown /// then writes the constant values to the buffer. 165383f182b3SAndrew Brown #[derive(Default)] 165483f182b3SAndrew Brown pub struct VCodeConstants { 165583f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 165683f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 165783f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1658eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 165983f182b3SAndrew Brown } 166083f182b3SAndrew Brown impl VCodeConstants { 166183f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 166283f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 166383f182b3SAndrew Brown Self { 166483f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 166583f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 166683f182b3SAndrew Brown well_known_uses: HashMap::new(), 1667eb435f30SChris Fallin u64s: HashMap::new(), 166883f182b3SAndrew Brown } 166983f182b3SAndrew Brown } 167083f182b3SAndrew Brown 167183f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 167283f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 167383f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 167483f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 167583f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 167683f182b3SAndrew Brown match data { 167783f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 167883f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 167983f182b3SAndrew Brown None => { 168083f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 168183f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 168283f182b3SAndrew Brown vcode_constant 168383f182b3SAndrew Brown } 168483f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 168583f182b3SAndrew Brown }, 168683f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1687eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1688eb435f30SChris Fallin Entry::Vacant(v) => { 168983f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1690eb435f30SChris Fallin v.insert(vcode_constant); 169183f182b3SAndrew Brown vcode_constant 169283f182b3SAndrew Brown } 1693eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 169483f182b3SAndrew Brown } 169583f182b3SAndrew Brown } 1696eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1697eb435f30SChris Fallin Entry::Vacant(v) => { 1698eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1699eb435f30SChris Fallin v.insert(vcode_constant); 1700eb435f30SChris Fallin vcode_constant 1701eb435f30SChris Fallin } 1702eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1703eb435f30SChris Fallin }, 170483f182b3SAndrew Brown } 170583f182b3SAndrew Brown } 170683f182b3SAndrew Brown 170783f182b3SAndrew Brown /// Return the number of constants inserted. 170883f182b3SAndrew Brown pub fn len(&self) -> usize { 170983f182b3SAndrew Brown self.constants.len() 171083f182b3SAndrew Brown } 171183f182b3SAndrew Brown 171283f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys inserted in this structure. 171383f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 171483f182b3SAndrew Brown self.constants.keys() 171583f182b3SAndrew Brown } 171683f182b3SAndrew Brown 171783f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this 171883f182b3SAndrew Brown /// structure. 171983f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 172083f182b3SAndrew Brown self.constants.iter() 172183f182b3SAndrew Brown } 172249dd8fd7SAlex Crichton 172349dd8fd7SAlex Crichton /// Returns the data associated with the specified constant. 172449dd8fd7SAlex Crichton pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData { 172549dd8fd7SAlex Crichton &self.constants[c] 172649dd8fd7SAlex Crichton } 172783f182b3SAndrew Brown } 172883f182b3SAndrew Brown 172983f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 173083f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 173183f182b3SAndrew Brown pub struct VCodeConstant(u32); 173283f182b3SAndrew Brown entity_impl!(VCodeConstant); 173383f182b3SAndrew Brown 173483f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 173583f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 173683f182b3SAndrew Brown pub enum VCodeConstantData { 173783f182b3SAndrew Brown /// A constant already present in the Cranelift IR 173883f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 173983f182b3SAndrew Brown Pool(Constant, ConstantData), 174083f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 174183f182b3SAndrew Brown WellKnown(&'static [u8]), 174283f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 174383f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 174483f182b3SAndrew Brown Generated(ConstantData), 1745eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1746eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1747eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1748eb435f30SChris Fallin U64([u8; 8]), 174983f182b3SAndrew Brown } 175083f182b3SAndrew Brown impl VCodeConstantData { 175183f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 175283f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 175383f182b3SAndrew Brown match self { 175483f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 175583f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1756eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 175783f182b3SAndrew Brown } 175883f182b3SAndrew Brown } 175983f182b3SAndrew Brown 176083f182b3SAndrew Brown /// Calculate the alignment of the constant data. 176183f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 176283f182b3SAndrew Brown if self.as_slice().len() <= 8 { 176383f182b3SAndrew Brown 8 176483f182b3SAndrew Brown } else { 176583f182b3SAndrew Brown 16 176683f182b3SAndrew Brown } 176783f182b3SAndrew Brown } 176883f182b3SAndrew Brown } 176983f182b3SAndrew Brown 177083f182b3SAndrew Brown #[cfg(test)] 177183f182b3SAndrew Brown mod test { 177283f182b3SAndrew Brown use super::*; 17735e5e5206SChris Fallin use std::mem::size_of; 177483f182b3SAndrew Brown 177583f182b3SAndrew Brown #[test] 177683f182b3SAndrew Brown fn size_of_constant_structs() { 177783f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 177883f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 177983f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 178083f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 178183f182b3SAndrew Brown assert_eq!( 178283f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 178383f182b3SAndrew Brown 24 178483f182b3SAndrew Brown ); 17855e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 17865e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 17875e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 178883f182b3SAndrew Brown } 178983f182b3SAndrew Brown } 1790