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; 228a9b1a90SBenjamin Bouvier use crate::ir::RelSourceLoc; 238a9b1a90SBenjamin Bouvier use crate::ir::{self, types, Constant, ConstantData, DynamicStackSlot, LabelValueLoc, ValueLabel}; 24d8357426SChris Fallin use crate::machinst::*; 252b9fefe8SChris Fallin use crate::timing; 268d022434SBenjamin Bouvier use crate::trace; 27d94173eaSTrevor Elliott use crate::CodegenError; 28a0318f36SChris Fallin use crate::ValueLocRange; 29a0318f36SChris Fallin use regalloc2::{ 30b2e28b91SChris Fallin Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PReg, PRegSet, 31a0318f36SChris Fallin RegClass, VReg, 32be6f060aSChris Fallin }; 33d8357426SChris Fallin 34a0318f36SChris Fallin use alloc::vec::Vec; 3583f182b3SAndrew Brown use cranelift_entity::{entity_impl, Keys, PrimaryMap}; 36eb435f30SChris Fallin use std::collections::hash_map::Entry; 3783f182b3SAndrew Brown use std::collections::HashMap; 38d8357426SChris Fallin use std::fmt; 39d8357426SChris Fallin 40d8357426SChris Fallin /// Index referring to an instruction in VCode. 41a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst; 42a0318f36SChris Fallin 43d8357426SChris Fallin /// Index referring to a basic block in VCode. 44a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block; 45d8357426SChris Fallin 46d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be 47d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. 4872e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 4972e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {} 50d8357426SChris Fallin 51a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after 52a0318f36SChris Fallin /// lowering. This is essentially a standard CFG of basic blocks, 53a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced 54a0318f36SChris Fallin /// by the machine-specific backend. 55a0318f36SChris Fallin /// 56a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not 57a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register 58a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output` 59a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not 60a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the 61a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or 62a0318f36SChris Fallin /// metadata as requested. 63d8357426SChris Fallin pub struct VCode<I: VCodeInst> { 64d8357426SChris Fallin /// VReg IR-level types. 65d8357426SChris Fallin vreg_types: Vec<Type>, 66d8357426SChris Fallin 67d8357426SChris Fallin /// Lowered machine instructions in order corresponding to the original IR. 6848cf2c2fSChris Fallin insts: Vec<I>, 69d8357426SChris Fallin 70a0318f36SChris Fallin /// Operands: pre-regalloc references to virtual registers with 71a0318f36SChris Fallin /// constraints, in one flattened array. This allows the regalloc 72a0318f36SChris Fallin /// to efficiently access all operands without requiring expensive 73a0318f36SChris Fallin /// matches or method invocations on insts. 74a0318f36SChris Fallin operands: Vec<Operand>, 75a0318f36SChris Fallin 76a0318f36SChris Fallin /// Operand index ranges: for each instruction in `insts`, there 77a0318f36SChris Fallin /// is a tuple here providing the range in `operands` for that 78a0318f36SChris Fallin /// instruction's operands. 79a0318f36SChris Fallin operand_ranges: Vec<(u32, u32)>, 80a0318f36SChris Fallin 81b2e28b91SChris Fallin /// Clobbers: a sparse map from instruction indices to clobber masks. 82b2e28b91SChris Fallin clobbers: FxHashMap<InsnIndex, PRegSet>, 83a0318f36SChris Fallin 84a0318f36SChris Fallin /// Move information: for a given InsnIndex, (src, dst) operand pair. 85a0318f36SChris Fallin is_move: FxHashMap<InsnIndex, (Operand, Operand)>, 86a0318f36SChris Fallin 87b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 88b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 898a9b1a90SBenjamin Bouvier srclocs: Vec<RelSourceLoc>, 90b691770fSChris Fallin 91d8357426SChris Fallin /// Entry block. 92d8357426SChris Fallin entry: BlockIndex, 93d8357426SChris Fallin 94d8357426SChris Fallin /// Block instruction indices. 9548cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 96d8357426SChris Fallin 97a0318f36SChris Fallin /// Block successors: index range in the `block_succs_preds` list. 98a0318f36SChris Fallin block_succ_range: Vec<(u32, u32)>, 99d8357426SChris Fallin 100a0318f36SChris Fallin /// Block predecessors: index range in the `block_succs_preds` list. 101a0318f36SChris Fallin block_pred_range: Vec<(u32, u32)>, 102a0318f36SChris Fallin 103a0318f36SChris Fallin /// Block successor and predecessor lists, concatenated into one 104a0318f36SChris Fallin /// Vec. The `block_succ_range` and `block_pred_range` lists of 105a0318f36SChris Fallin /// tuples above give (start, end) ranges within this list that 106a0318f36SChris Fallin /// correspond to each basic block's successors or predecessors, 107a0318f36SChris Fallin /// respectively. 108a0318f36SChris Fallin block_succs_preds: Vec<regalloc2::Block>, 109a0318f36SChris Fallin 110a0318f36SChris Fallin /// Block parameters: index range in `block_params` below. 111a0318f36SChris Fallin block_params_range: Vec<(u32, u32)>, 112a0318f36SChris Fallin 113a0318f36SChris Fallin /// Block parameter lists, concatenated into one vec. The 114a0318f36SChris Fallin /// `block_params_range` list of tuples above gives (start, end) 115a0318f36SChris Fallin /// ranges within this list that correspond to each basic block's 116a0318f36SChris Fallin /// blockparam vregs. 117a0318f36SChris Fallin block_params: Vec<regalloc2::VReg>, 118a0318f36SChris Fallin 119a0318f36SChris Fallin /// Outgoing block arguments on branch instructions, concatenated 120a0318f36SChris Fallin /// into one list. 121a0318f36SChris Fallin /// 122a0318f36SChris Fallin /// Note that this is conceptually a 3D array: we have a VReg list 123a0318f36SChris Fallin /// per block, per successor. We flatten those three dimensions 124a0318f36SChris Fallin /// into this 1D vec, then store index ranges in two levels of 125a0318f36SChris Fallin /// indirection. 126a0318f36SChris Fallin /// 127a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 128a0318f36SChris Fallin branch_block_args: Vec<regalloc2::VReg>, 129a0318f36SChris Fallin 130a0318f36SChris Fallin /// Array of sequences of (start, end) tuples in 131a0318f36SChris Fallin /// `branch_block_args`, one for each successor; these sequences 132a0318f36SChris Fallin /// for each block are concatenated. 133a0318f36SChris Fallin /// 134a0318f36SChris Fallin /// Indexed by the indices in `branch_block_arg_succ_range`. 135a0318f36SChris Fallin branch_block_arg_range: Vec<(u32, u32)>, 136a0318f36SChris Fallin 137a0318f36SChris Fallin /// For a given block, indices in `branch_block_arg_range` 138a0318f36SChris Fallin /// corresponding to all of its successors. 139a0318f36SChris Fallin branch_block_arg_succ_range: Vec<(u32, u32)>, 140a0318f36SChris Fallin 141a0318f36SChris Fallin /// VReg aliases. Each key in this table is translated to its 142a0318f36SChris Fallin /// value when gathering Operands from instructions. Aliases are 143a0318f36SChris Fallin /// not chased transitively (we do not further look up the 144a0318f36SChris Fallin /// translated reg to see if it is another alias). 145a0318f36SChris Fallin /// 146a0318f36SChris Fallin /// We use these aliases to rename an instruction's expected 147a0318f36SChris Fallin /// result vregs to the returned vregs from lowering, which are 148a0318f36SChris Fallin /// usually freshly-allocated temps. 149a0318f36SChris Fallin /// 150a0318f36SChris Fallin /// Operands and branch arguments will already have been 151a0318f36SChris Fallin /// translated through this alias table; but it helps to make 152a0318f36SChris Fallin /// sense of instructions when pretty-printed, for example. 153a0318f36SChris Fallin vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>, 154d8357426SChris Fallin 15572e6be93SChris Fallin /// Block-order information. 15672e6be93SChris Fallin block_order: BlockLoweringOrder, 157d8357426SChris Fallin 158d8357426SChris Fallin /// ABI object. 1592986f6b0SChris Fallin pub(crate) abi: Callee<I::ABIMachineSpec>, 16008353fccSChris Fallin 161c5bbc874SBenjamin Bouvier /// Constant information used during code emission. This should be 162c5bbc874SBenjamin Bouvier /// immutable across function compilations within the same module. 163c5bbc874SBenjamin Bouvier emit_info: I::Info, 164c5bbc874SBenjamin Bouvier 165a0318f36SChris Fallin /// Reference-typed `regalloc2::VReg`s. The regalloc requires 166a0318f36SChris Fallin /// these in a dense slice (as opposed to querying the 167a0318f36SChris Fallin /// reftype-status of each vreg) for efficient iteration. 168a0318f36SChris Fallin reftyped_vregs: Vec<VReg>, 16908353fccSChris Fallin 17083f182b3SAndrew Brown /// Constants. 17183f182b3SAndrew Brown constants: VCodeConstants, 172997fab55SChris Fallin 173a0318f36SChris Fallin /// Value labels for debuginfo attached to vregs. 174a0318f36SChris Fallin debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, 175f18a1f14SNick Fitzgerald 1762986f6b0SChris Fallin pub(crate) sigs: SigSet, 177d8357426SChris Fallin } 178d8357426SChris Fallin 179a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed 180a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly, 181a0318f36SChris Fallin /// and optionally metadata about the code layout. 182a0318f36SChris Fallin pub struct EmitResult<I: VCodeInst> { 183a0318f36SChris Fallin /// The MachBuffer containing the machine code. 184a0318f36SChris Fallin pub buffer: MachBuffer<I>, 185a0318f36SChris Fallin 186a0318f36SChris Fallin /// Offset of each basic block, recorded during emission. Computed 187a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 188a0318f36SChris Fallin pub bb_offsets: Vec<CodeOffset>, 189a0318f36SChris Fallin 190a0318f36SChris Fallin /// Final basic-block edges, in terms of code offsets of 191a0318f36SChris Fallin /// bb-starts. Computed only if `debug_value_labels` is non-empty. 192a0318f36SChris Fallin pub bb_edges: Vec<(CodeOffset, CodeOffset)>, 193a0318f36SChris Fallin 194a0318f36SChris Fallin /// Final instruction offsets, recorded during emission. Computed 195a0318f36SChris Fallin /// only if `debug_value_labels` is non-empty. 196a0318f36SChris Fallin pub inst_offsets: Vec<CodeOffset>, 197a0318f36SChris Fallin 198a0318f36SChris Fallin /// Final length of function body. 199a0318f36SChris Fallin pub func_body_len: CodeOffset, 200a0318f36SChris Fallin 201a0318f36SChris Fallin /// The pretty-printed disassembly, if any. This uses the same 202a0318f36SChris Fallin /// pretty-printing for MachInsts as the pre-regalloc VCode Debug 203a0318f36SChris Fallin /// implementation, but additionally includes the prologue and 204a0318f36SChris Fallin /// epilogue(s), and makes use of the regalloc results. 205a0318f36SChris Fallin pub disasm: Option<String>, 206a0318f36SChris Fallin 2079c43749dSSam Parker /// Offsets of sized stackslots. 2089c43749dSSam Parker pub sized_stackslot_offsets: PrimaryMap<StackSlot, u32>, 2099c43749dSSam Parker 2109c43749dSSam Parker /// Offsets of dynamic stackslots. 2119c43749dSSam Parker pub dynamic_stackslot_offsets: PrimaryMap<DynamicStackSlot, u32>, 212a0318f36SChris Fallin 213a0318f36SChris Fallin /// Value-labels information (debug metadata). 214a0318f36SChris Fallin pub value_labels_ranges: ValueLabelsRanges, 215a0318f36SChris Fallin 216a0318f36SChris Fallin /// Stack frame size. 217a0318f36SChris Fallin pub frame_size: u32, 218dde2c5a3STrevor Elliott 219dde2c5a3STrevor Elliott /// The alignment requirement for pc-relative loads. 220dde2c5a3STrevor Elliott pub alignment: u32, 221d9d64694SChris Fallin } 222d9d64694SChris Fallin 223a0318f36SChris Fallin /// A builder for a VCode function body. 224d8357426SChris Fallin /// 225a0318f36SChris Fallin /// This builder has the ability to accept instructions in either 226a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that 227a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst> 228a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions 229a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will 230a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine 231a0318f36SChris Fallin /// order. 232a0318f36SChris Fallin /// 233a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the 234a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the 235a0318f36SChris Fallin /// order of construction. Note that this means we do not know the 236a0318f36SChris Fallin /// final block or instruction indices when building, so we do not 237a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending 238a0318f36SChris Fallin /// terminator instructions with successor blocks.) 239d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 240d8357426SChris Fallin /// In-progress VCode. 2412986f6b0SChris Fallin pub(crate) vcode: VCode<I>, 242d8357426SChris Fallin 243a0318f36SChris Fallin /// In what direction is the build occuring? 244a0318f36SChris Fallin direction: VCodeBuildDirection, 24508353fccSChris Fallin 24672e6be93SChris Fallin /// Index of the last block-start in the vcode. 247a0318f36SChris Fallin block_start: usize, 248d8357426SChris Fallin 249d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 250d8357426SChris Fallin succ_start: usize, 251b691770fSChris Fallin 252a0318f36SChris Fallin /// Start of blockparams for the current block in the concatenated 253a0318f36SChris Fallin /// blockparams list. 254a0318f36SChris Fallin block_params_start: usize, 255a0318f36SChris Fallin 256a0318f36SChris Fallin /// Start of successor blockparam arg list entries in 257a0318f36SChris Fallin /// the concatenated branch_block_arg_range list. 258a0318f36SChris Fallin branch_block_arg_succ_start: usize, 259a0318f36SChris Fallin 260b691770fSChris Fallin /// Current source location. 2618a9b1a90SBenjamin Bouvier cur_srcloc: RelSourceLoc, 262a0318f36SChris Fallin 263a0318f36SChris Fallin /// Debug-value label in-progress map, keyed by label. For each 264a0318f36SChris Fallin /// label, we keep disjoint ranges mapping to vregs. We'll flatten 265a0318f36SChris Fallin /// this into (vreg, range, label) tuples when done. 266a0318f36SChris Fallin debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>, 267a0318f36SChris Fallin } 268a0318f36SChris Fallin 269a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode. 270a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)] 271a0318f36SChris Fallin pub enum VCodeBuildDirection { 272a0318f36SChris Fallin // TODO: add `Forward` once we need it and can test it adequately. 273a0318f36SChris Fallin /// Backward-build pass: we expect the producer to call `emit()` 274a0318f36SChris Fallin /// with instructions in reverse program order within each block. 275a0318f36SChris Fallin Backward, 276d8357426SChris Fallin } 277d8357426SChris Fallin 278d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 279d8357426SChris Fallin /// Create a new VCodeBuilder. 280c5bbc874SBenjamin Bouvier pub fn new( 281f18a1f14SNick Fitzgerald sigs: SigSet, 282f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 283c5bbc874SBenjamin Bouvier emit_info: I::Info, 284c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 28583f182b3SAndrew Brown constants: VCodeConstants, 286a0318f36SChris Fallin direction: VCodeBuildDirection, 287c5bbc874SBenjamin Bouvier ) -> VCodeBuilder<I> { 288f18a1f14SNick Fitzgerald let vcode = VCode::new(sigs, abi, emit_info, block_order, constants); 28908353fccSChris Fallin 290d8357426SChris Fallin VCodeBuilder { 291d8357426SChris Fallin vcode, 292a0318f36SChris Fallin direction, 29372e6be93SChris Fallin block_start: 0, 294d8357426SChris Fallin succ_start: 0, 295a0318f36SChris Fallin block_params_start: 0, 296a0318f36SChris Fallin branch_block_arg_succ_start: 0, 2978a9b1a90SBenjamin Bouvier cur_srcloc: Default::default(), 298a0318f36SChris Fallin debug_info: FxHashMap::default(), 299d8357426SChris Fallin } 300d8357426SChris Fallin } 301d8357426SChris Fallin 302f18a1f14SNick Fitzgerald pub fn init_abi(&mut self, temps: Vec<Writable<Reg>>) { 303f18a1f14SNick Fitzgerald self.vcode.abi.init(&self.vcode.sigs, temps); 304f18a1f14SNick Fitzgerald } 305f18a1f14SNick Fitzgerald 306d8357426SChris Fallin /// Access the ABI object. 307f18a1f14SNick Fitzgerald pub fn abi(&self) -> &Callee<I::ABIMachineSpec> { 308f18a1f14SNick Fitzgerald &self.vcode.abi 309f18a1f14SNick Fitzgerald } 310f18a1f14SNick Fitzgerald 311f18a1f14SNick Fitzgerald /// Access the ABI object. 312f18a1f14SNick Fitzgerald pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> { 313f0c60f46SNick Fitzgerald &mut self.vcode.abi 314d8357426SChris Fallin } 315d8357426SChris Fallin 316f18a1f14SNick Fitzgerald pub fn sigs(&self) -> &SigSet { 317f18a1f14SNick Fitzgerald &self.vcode.sigs 318f18a1f14SNick Fitzgerald } 319f18a1f14SNick Fitzgerald 320f18a1f14SNick Fitzgerald pub fn sigs_mut(&mut self) -> &mut SigSet { 321f18a1f14SNick Fitzgerald &mut self.vcode.sigs 322f18a1f14SNick Fitzgerald } 323f18a1f14SNick Fitzgerald 32472e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 32572e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 32672e6be93SChris Fallin &self.vcode.block_order 3271d90751bSBenjamin Bouvier } 3281d90751bSBenjamin Bouvier 329d8357426SChris Fallin /// Set the current block as the entry block. 330d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 331d8357426SChris Fallin self.vcode.entry = block; 332d8357426SChris Fallin } 333d8357426SChris Fallin 334d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 335d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 33672e6be93SChris Fallin pub fn end_bb(&mut self) { 33772e6be93SChris Fallin let start_idx = self.block_start; 338a0318f36SChris Fallin let end_idx = self.vcode.insts.len(); 33972e6be93SChris Fallin self.block_start = end_idx; 340d8357426SChris Fallin // Add the instruction index range to the list of blocks. 341a0318f36SChris Fallin self.vcode 342a0318f36SChris Fallin .block_ranges 343a0318f36SChris Fallin .push((InsnIndex::new(start_idx), InsnIndex::new(end_idx))); 344d8357426SChris Fallin // End the successors list. 345a0318f36SChris Fallin let succ_end = self.vcode.block_succs_preds.len(); 346d8357426SChris Fallin self.vcode 347d8357426SChris Fallin .block_succ_range 348a0318f36SChris Fallin .push((self.succ_start as u32, succ_end as u32)); 349d8357426SChris Fallin self.succ_start = succ_end; 350a0318f36SChris Fallin // End the blockparams list. 351a0318f36SChris Fallin let block_params_end = self.vcode.block_params.len(); 352a0318f36SChris Fallin self.vcode 353a0318f36SChris Fallin .block_params_range 354a0318f36SChris Fallin .push((self.block_params_start as u32, block_params_end as u32)); 355a0318f36SChris Fallin self.block_params_start = block_params_end; 356a0318f36SChris Fallin // End the branch blockparam args list. 357a0318f36SChris Fallin let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); 358a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.push(( 359a0318f36SChris Fallin self.branch_block_arg_succ_start as u32, 360a0318f36SChris Fallin branch_block_arg_succ_end as u32, 361a0318f36SChris Fallin )); 362a0318f36SChris Fallin self.branch_block_arg_succ_start = branch_block_arg_succ_end; 363d8357426SChris Fallin } 364d8357426SChris Fallin 365d94173eaSTrevor Elliott pub fn add_block_param(&mut self, param: VirtualReg) { 366a0318f36SChris Fallin self.vcode.block_params.push(param.into()); 367a0318f36SChris Fallin } 368a0318f36SChris Fallin 3695774e068SChris Fallin fn add_branch_args_for_succ(&mut self, args: &[Reg]) { 370a0318f36SChris Fallin let start = self.vcode.branch_block_args.len(); 371a0318f36SChris Fallin self.vcode 372a0318f36SChris Fallin .branch_block_args 373a0318f36SChris Fallin .extend(args.iter().map(|&arg| VReg::from(arg))); 374a0318f36SChris Fallin let end = self.vcode.branch_block_args.len(); 375a0318f36SChris Fallin self.vcode 376a0318f36SChris Fallin .branch_block_arg_range 377a0318f36SChris Fallin .push((start as u32, end as u32)); 378a0318f36SChris Fallin } 379a0318f36SChris Fallin 380a0318f36SChris Fallin /// Push an instruction for the current BB and current IR inst 381a0318f36SChris Fallin /// within the BB. 382a0318f36SChris Fallin pub fn push(&mut self, insn: I) { 38372e6be93SChris Fallin self.vcode.insts.push(insn); 38472e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 38572e6be93SChris Fallin } 38672e6be93SChris Fallin 3875774e068SChris Fallin /// Add a successor block with branch args. 3885774e068SChris Fallin pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { 3895774e068SChris Fallin self.vcode.block_succs_preds.push(block); 3905774e068SChris Fallin self.add_branch_args_for_succ(args); 3915774e068SChris Fallin } 3925774e068SChris Fallin 393b691770fSChris Fallin /// Set the current source location. 3948a9b1a90SBenjamin Bouvier pub fn set_srcloc(&mut self, srcloc: RelSourceLoc) { 395b691770fSChris Fallin self.cur_srcloc = srcloc; 396d8357426SChris Fallin } 397d8357426SChris Fallin 398a0318f36SChris Fallin /// Add a debug value label to a register. 399a0318f36SChris Fallin pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { 400a0318f36SChris Fallin // We'll fix up labels in reverse(). Because we're generating 401a0318f36SChris Fallin // code bottom-to-top, the liverange of the label goes *from* 402a0318f36SChris Fallin // the last index at which was defined (or 0, which is the end 403a0318f36SChris Fallin // of the eventual function) *to* just this instruction, and 404a0318f36SChris Fallin // no further. 405a0318f36SChris Fallin let inst = InsnIndex::new(self.vcode.insts.len()); 406a0318f36SChris Fallin let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); 407a0318f36SChris Fallin let last = labels 408a0318f36SChris Fallin .last() 409a0318f36SChris Fallin .map(|(_start, end, _vreg)| *end) 410a0318f36SChris Fallin .unwrap_or(InsnIndex::new(0)); 411a0318f36SChris Fallin labels.push((last, inst, reg.into())); 412a0318f36SChris Fallin } 413a0318f36SChris Fallin 414a0318f36SChris Fallin pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { 415a0318f36SChris Fallin let from = from.into(); 416a0318f36SChris Fallin let resolved_to = self.resolve_vreg_alias(to.into()); 417a0318f36SChris Fallin // Disallow cycles (see below). 418a0318f36SChris Fallin assert_ne!(resolved_to, from); 419a0318f36SChris Fallin self.vcode.vreg_aliases.insert(from, resolved_to); 420a0318f36SChris Fallin } 421a0318f36SChris Fallin 422a0318f36SChris Fallin pub fn resolve_vreg_alias(&self, from: regalloc2::VReg) -> regalloc2::VReg { 423a0318f36SChris Fallin Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, from) 424a0318f36SChris Fallin } 425a0318f36SChris Fallin 426a0318f36SChris Fallin fn resolve_vreg_alias_impl( 427a0318f36SChris Fallin aliases: &FxHashMap<regalloc2::VReg, regalloc2::VReg>, 428a0318f36SChris Fallin from: regalloc2::VReg, 429a0318f36SChris Fallin ) -> regalloc2::VReg { 430a0318f36SChris Fallin // We prevent cycles from existing by resolving targets of 431a0318f36SChris Fallin // aliases eagerly before setting them. If the target resolves 432a0318f36SChris Fallin // to the origin of the alias, then a cycle would be created 433a0318f36SChris Fallin // and the alias is disallowed. Because of the structure of 434a0318f36SChris Fallin // SSA code (one instruction can refer to another's defs but 435a0318f36SChris Fallin // not vice-versa, except indirectly through 436a0318f36SChris Fallin // phis/blockparams), cycles should not occur as we use 437a0318f36SChris Fallin // aliases to redirect vregs to the temps that actually define 438a0318f36SChris Fallin // them. 439a0318f36SChris Fallin 440a0318f36SChris Fallin let mut vreg = from; 441a0318f36SChris Fallin while let Some(to) = aliases.get(&vreg) { 442a0318f36SChris Fallin vreg = *to; 443a0318f36SChris Fallin } 444a0318f36SChris Fallin vreg 445a0318f36SChris Fallin } 446a0318f36SChris Fallin 44783f182b3SAndrew Brown /// Access the constants. 44883f182b3SAndrew Brown pub fn constants(&mut self) -> &mut VCodeConstants { 44983f182b3SAndrew Brown &mut self.vcode.constants 45083f182b3SAndrew Brown } 45183f182b3SAndrew Brown 452a0318f36SChris Fallin fn compute_preds_from_succs(&mut self) { 453a0318f36SChris Fallin // Compute predecessors from successors. In order to gather 454a0318f36SChris Fallin // all preds for a block into a contiguous sequence, we build 455a0318f36SChris Fallin // a list of (succ, pred) tuples and then sort. 456a0318f36SChris Fallin let mut succ_pred_edges: Vec<(BlockIndex, BlockIndex)> = 457a0318f36SChris Fallin Vec::with_capacity(self.vcode.block_succs_preds.len()); 458a0318f36SChris Fallin for (pred, &(start, end)) in self.vcode.block_succ_range.iter().enumerate() { 459a0318f36SChris Fallin let pred = BlockIndex::new(pred); 460a0318f36SChris Fallin for i in start..end { 461a0318f36SChris Fallin let succ = BlockIndex::new(self.vcode.block_succs_preds[i as usize].index()); 462a0318f36SChris Fallin succ_pred_edges.push((succ, pred)); 463a0318f36SChris Fallin } 464a0318f36SChris Fallin } 465a0318f36SChris Fallin succ_pred_edges.sort_unstable(); 466a0318f36SChris Fallin 467a0318f36SChris Fallin let mut i = 0; 468a0318f36SChris Fallin for succ in 0..self.vcode.num_blocks() { 469a0318f36SChris Fallin let succ = BlockIndex::new(succ); 470a0318f36SChris Fallin let start = self.vcode.block_succs_preds.len(); 471a0318f36SChris Fallin while i < succ_pred_edges.len() && succ_pred_edges[i].0 == succ { 472a0318f36SChris Fallin let pred = succ_pred_edges[i].1; 473a0318f36SChris Fallin self.vcode.block_succs_preds.push(pred); 474a0318f36SChris Fallin i += 1; 475a0318f36SChris Fallin } 476a0318f36SChris Fallin let end = self.vcode.block_succs_preds.len(); 477a0318f36SChris Fallin self.vcode.block_pred_range.push((start as u32, end as u32)); 478d8357426SChris Fallin } 479d8357426SChris Fallin } 480d8357426SChris Fallin 481a0318f36SChris Fallin /// Called once, when a build in Backward order is complete, to 482a0318f36SChris Fallin /// perform the overall reversal (into final forward order) and 483a0318f36SChris Fallin /// finalize metadata accordingly. 484a0318f36SChris Fallin fn reverse_and_finalize(&mut self) { 485a0318f36SChris Fallin let n_insts = self.vcode.insts.len(); 486a0318f36SChris Fallin if n_insts == 0 { 487a0318f36SChris Fallin return; 488a0318f36SChris Fallin } 489a0318f36SChris Fallin 490a0318f36SChris Fallin // Reverse the per-block and per-inst sequences. 491a0318f36SChris Fallin self.vcode.block_ranges.reverse(); 492a0318f36SChris Fallin // block_params_range is indexed by block (and blocks were 493a0318f36SChris Fallin // traversed in reverse) so we reverse it; but block-param 494a0318f36SChris Fallin // sequences in the concatenated vec can remain in reverse 495a0318f36SChris Fallin // order (it is effectively an arena of arbitrarily-placed 496a0318f36SChris Fallin // referenced sequences). 497a0318f36SChris Fallin self.vcode.block_params_range.reverse(); 498a0318f36SChris Fallin // Likewise, we reverse block_succ_range, but the block_succ 499a0318f36SChris Fallin // concatenated array can remain as-is. 500a0318f36SChris Fallin self.vcode.block_succ_range.reverse(); 501a0318f36SChris Fallin self.vcode.insts.reverse(); 502a0318f36SChris Fallin self.vcode.srclocs.reverse(); 503a0318f36SChris Fallin // Likewise, branch_block_arg_succ_range is indexed by block 504a0318f36SChris Fallin // so must be reversed. 505a0318f36SChris Fallin self.vcode.branch_block_arg_succ_range.reverse(); 506a0318f36SChris Fallin 507a0318f36SChris Fallin // To translate an instruction index *endpoint* in reversed 508a0318f36SChris Fallin // order to forward order, compute `n_insts - i`. 509a0318f36SChris Fallin // 510a0318f36SChris Fallin // Why not `n_insts - 1 - i`? That would be correct to 511a0318f36SChris Fallin // translate an individual instruction index (for ten insts 0 512a0318f36SChris Fallin // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes 513a0318f36SChris Fallin // 0). But for the usual inclusive-start, exclusive-end range 514a0318f36SChris Fallin // idiom, inclusive starts become exclusive ends and 515a0318f36SChris Fallin // vice-versa, so e.g. an (inclusive) start of 0 becomes an 516a0318f36SChris Fallin // (exclusive) end of 10. 517a0318f36SChris Fallin let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); 518a0318f36SChris Fallin 519a0318f36SChris Fallin // Edit the block-range instruction indices. 520a0318f36SChris Fallin for tuple in &mut self.vcode.block_ranges { 521a0318f36SChris Fallin let (start, end) = *tuple; 522a0318f36SChris Fallin *tuple = (translate(end), translate(start)); // Note reversed order. 523a0318f36SChris Fallin } 524a0318f36SChris Fallin 525a0318f36SChris Fallin // Generate debug-value labels based on per-label maps. 526a0318f36SChris Fallin for (label, tuples) in &self.debug_info { 527a0318f36SChris Fallin for &(start, end, vreg) in tuples { 528a0318f36SChris Fallin let vreg = self.resolve_vreg_alias(vreg); 529a0318f36SChris Fallin let fwd_start = translate(end); 530a0318f36SChris Fallin let fwd_end = translate(start); 531a0318f36SChris Fallin self.vcode 532a0318f36SChris Fallin .debug_value_labels 533a0318f36SChris Fallin .push((vreg, fwd_start, fwd_end, label.as_u32())); 534a0318f36SChris Fallin } 535a0318f36SChris Fallin } 536a0318f36SChris Fallin 537a0318f36SChris Fallin // Now sort debug value labels by VReg, as required 538a0318f36SChris Fallin // by regalloc2. 539a0318f36SChris Fallin self.vcode 540a0318f36SChris Fallin .debug_value_labels 541a0318f36SChris Fallin .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); 542a0318f36SChris Fallin } 543a0318f36SChris Fallin 544a0318f36SChris Fallin fn collect_operands(&mut self) { 545a0318f36SChris Fallin for (i, insn) in self.vcode.insts.iter().enumerate() { 546a0318f36SChris Fallin // Push operands from the instruction onto the operand list. 547a0318f36SChris Fallin // 548a0318f36SChris Fallin // We rename through the vreg alias table as we collect 549a0318f36SChris Fallin // the operands. This is better than a separate post-pass 550a0318f36SChris Fallin // over operands, because it has more cache locality: 551a0318f36SChris Fallin // operands only need to pass through L1 once. This is 552a0318f36SChris Fallin // also better than renaming instructions' 553a0318f36SChris Fallin // operands/registers while lowering, because here we only 554a0318f36SChris Fallin // need to do the `match` over the instruction to visit 555a0318f36SChris Fallin // its register fields (which is slow, branchy code) once. 556a0318f36SChris Fallin 557a0318f36SChris Fallin let vreg_aliases = &self.vcode.vreg_aliases; 558a0318f36SChris Fallin let mut op_collector = OperandCollector::new(&mut self.vcode.operands, |vreg| { 559a0318f36SChris Fallin Self::resolve_vreg_alias_impl(vreg_aliases, vreg) 560a0318f36SChris Fallin }); 561a0318f36SChris Fallin insn.get_operands(&mut op_collector); 562a0318f36SChris Fallin let (ops, clobbers) = op_collector.finish(); 563a0318f36SChris Fallin self.vcode.operand_ranges.push(ops); 564a0318f36SChris Fallin 565b2e28b91SChris Fallin if clobbers != PRegSet::default() { 566b2e28b91SChris Fallin self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); 567a0318f36SChris Fallin } 568a0318f36SChris Fallin 569a0318f36SChris Fallin if let Some((dst, src)) = insn.is_move() { 570a0318f36SChris Fallin let src = Operand::reg_use(Self::resolve_vreg_alias_impl(vreg_aliases, src.into())); 571a0318f36SChris Fallin let dst = Operand::reg_def(Self::resolve_vreg_alias_impl( 572a0318f36SChris Fallin vreg_aliases, 573a0318f36SChris Fallin dst.to_reg().into(), 574a0318f36SChris Fallin )); 575a0318f36SChris Fallin // Note that regalloc2 requires these in (src, dst) order. 576a0318f36SChris Fallin self.vcode.is_move.insert(InsnIndex::new(i), (src, dst)); 577a0318f36SChris Fallin } 578a0318f36SChris Fallin } 579a0318f36SChris Fallin 580a0318f36SChris Fallin // Translate blockparam args via the vreg aliases table as well. 581a0318f36SChris Fallin for arg in &mut self.vcode.branch_block_args { 582a0318f36SChris Fallin let new_arg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *arg); 5838d022434SBenjamin Bouvier trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); 584a0318f36SChris Fallin *arg = new_arg; 585a0318f36SChris Fallin } 586a0318f36SChris Fallin } 587a0318f36SChris Fallin 588a0318f36SChris Fallin /// Build the final VCode. 589d94173eaSTrevor Elliott pub fn build(mut self, vregs: VRegAllocator<I>) -> VCode<I> { 590d94173eaSTrevor Elliott self.vcode.vreg_types = vregs.vreg_types; 591d94173eaSTrevor Elliott self.vcode.reftyped_vregs = vregs.reftyped_vregs; 592d94173eaSTrevor Elliott 593a0318f36SChris Fallin if self.direction == VCodeBuildDirection::Backward { 594a0318f36SChris Fallin self.reverse_and_finalize(); 595a0318f36SChris Fallin } 596a0318f36SChris Fallin self.collect_operands(); 5972154c63dSAlex Crichton 5982154c63dSAlex Crichton // Apply register aliases to the `reftyped_vregs` list since this list 5992154c63dSAlex Crichton // will be returned directly to `regalloc2` eventually and all 6002154c63dSAlex Crichton // operands/results of instructions will use the alias-resolved vregs 6012154c63dSAlex Crichton // from `regalloc2`'s perspective. 6022127c3a3SAlex Crichton // 6032127c3a3SAlex Crichton // Also note that `reftyped_vregs` can't have duplicates, so after the 6042127c3a3SAlex Crichton // aliases are applied duplicates are removed. 6052154c63dSAlex Crichton for reg in self.vcode.reftyped_vregs.iter_mut() { 6062154c63dSAlex Crichton *reg = Self::resolve_vreg_alias_impl(&self.vcode.vreg_aliases, *reg); 6072154c63dSAlex Crichton } 6082127c3a3SAlex Crichton self.vcode.reftyped_vregs.sort(); 6092127c3a3SAlex Crichton self.vcode.reftyped_vregs.dedup(); 6102154c63dSAlex Crichton 611a0318f36SChris Fallin self.compute_preds_from_succs(); 612a0318f36SChris Fallin self.vcode.debug_value_labels.sort_unstable(); 613a0318f36SChris Fallin self.vcode 614d8357426SChris Fallin } 615d8357426SChris Fallin } 616d8357426SChris Fallin 61708353fccSChris Fallin /// Is this type a reference type? 61808353fccSChris Fallin fn is_reftype(ty: Type) -> bool { 61926529006SChris Fallin ty == types::R64 || ty == types::R32 62008353fccSChris Fallin } 62108353fccSChris Fallin 622d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 623d8357426SChris Fallin /// New empty VCode. 624c5bbc874SBenjamin Bouvier fn new( 625f18a1f14SNick Fitzgerald sigs: SigSet, 626f0c60f46SNick Fitzgerald abi: Callee<I::ABIMachineSpec>, 627c5bbc874SBenjamin Bouvier emit_info: I::Info, 628c5bbc874SBenjamin Bouvier block_order: BlockLoweringOrder, 62983f182b3SAndrew Brown constants: VCodeConstants, 630c5bbc874SBenjamin Bouvier ) -> VCode<I> { 631a0318f36SChris Fallin let n_blocks = block_order.lowered_order().len(); 632d8357426SChris Fallin VCode { 633f18a1f14SNick Fitzgerald sigs, 634d8357426SChris Fallin vreg_types: vec![], 635a0318f36SChris Fallin insts: Vec::with_capacity(10 * n_blocks), 636a0318f36SChris Fallin operands: Vec::with_capacity(30 * n_blocks), 637a0318f36SChris Fallin operand_ranges: Vec::with_capacity(10 * n_blocks), 638b2e28b91SChris Fallin clobbers: FxHashMap::default(), 639a0318f36SChris Fallin is_move: FxHashMap::default(), 640a0318f36SChris Fallin srclocs: Vec::with_capacity(10 * n_blocks), 641a0318f36SChris Fallin entry: BlockIndex::new(0), 642a0318f36SChris Fallin block_ranges: Vec::with_capacity(n_blocks), 643a0318f36SChris Fallin block_succ_range: Vec::with_capacity(n_blocks), 644a0318f36SChris Fallin block_succs_preds: Vec::with_capacity(2 * n_blocks), 645a0318f36SChris Fallin block_pred_range: Vec::with_capacity(n_blocks), 646a0318f36SChris Fallin block_params_range: Vec::with_capacity(n_blocks), 647a0318f36SChris Fallin block_params: Vec::with_capacity(5 * n_blocks), 648a0318f36SChris Fallin branch_block_args: Vec::with_capacity(10 * n_blocks), 649a0318f36SChris Fallin branch_block_arg_range: Vec::with_capacity(2 * n_blocks), 650a0318f36SChris Fallin branch_block_arg_succ_range: Vec::with_capacity(n_blocks), 65172e6be93SChris Fallin block_order, 652d8357426SChris Fallin abi, 653c5bbc874SBenjamin Bouvier emit_info, 654a0318f36SChris Fallin reftyped_vregs: vec![], 65583f182b3SAndrew Brown constants, 656a0318f36SChris Fallin debug_value_labels: vec![], 657a0318f36SChris Fallin vreg_aliases: FxHashMap::with_capacity_and_hasher(10 * n_blocks, Default::default()), 658d8357426SChris Fallin } 659d8357426SChris Fallin } 660d8357426SChris Fallin 661d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 662d8357426SChris Fallin /// (self.num_blocks() - 1)`. 663d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 664d8357426SChris Fallin self.block_ranges.len() 665d8357426SChris Fallin } 666d8357426SChris Fallin 667d8357426SChris Fallin /// Get the successors for a block. 668a0318f36SChris Fallin pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] { 669a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 670a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 671d8357426SChris Fallin } 672d8357426SChris Fallin 673a0318f36SChris Fallin fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec<Writable<RealReg>> { 674a0318f36SChris Fallin // Compute clobbered registers. 675a0318f36SChris Fallin let mut clobbered = vec![]; 676a0318f36SChris Fallin let mut clobbered_set = FxHashSet::default(); 677d8357426SChris Fallin 678a0318f36SChris Fallin // All moves are included in clobbers. 679a0318f36SChris Fallin for edit in ®alloc.edits { 680a0318f36SChris Fallin let Edit::Move { to, .. } = edit.1; 681a0318f36SChris Fallin if let Some(preg) = to.as_reg() { 682a0318f36SChris Fallin let reg = RealReg::from(preg); 683a0318f36SChris Fallin if clobbered_set.insert(reg) { 684a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 685a0318f36SChris Fallin } 686a0318f36SChris Fallin } 687d8357426SChris Fallin } 688d8357426SChris Fallin 689a0318f36SChris Fallin for (i, (start, end)) in self.operand_ranges.iter().enumerate() { 690a0318f36SChris Fallin // Skip this instruction if not "included in clobbers" as 691a0318f36SChris Fallin // per the MachInst. (Some backends use this to implement 692a0318f36SChris Fallin // ABI specifics; e.g., excluding calls of the same ABI as 693a0318f36SChris Fallin // the current function from clobbers, because by 694a0318f36SChris Fallin // definition everything clobbered by the call can be 695a0318f36SChris Fallin // clobbered by this function without saving as well.) 696a0318f36SChris Fallin if !self.insts[i].is_included_in_clobbers() { 697d8357426SChris Fallin continue; 698d8357426SChris Fallin } 699d8357426SChris Fallin 700a0318f36SChris Fallin let start = *start as usize; 701a0318f36SChris Fallin let end = *end as usize; 702a0318f36SChris Fallin let operands = &self.operands[start..end]; 703a0318f36SChris Fallin let allocs = ®alloc.allocs[start..end]; 704a0318f36SChris Fallin for (operand, alloc) in operands.iter().zip(allocs.iter()) { 705a0318f36SChris Fallin // We're interested only in writes (Mods or Defs). 706a0318f36SChris Fallin if operand.kind() == OperandKind::Use { 707a0318f36SChris Fallin continue; 708d8357426SChris Fallin } 709a0318f36SChris Fallin if let Some(preg) = alloc.as_reg() { 710a0318f36SChris Fallin let reg = RealReg::from(preg); 711a0318f36SChris Fallin if clobbered_set.insert(reg) { 712a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 713a0318f36SChris Fallin } 71408353fccSChris Fallin } 715d8357426SChris Fallin } 716d8357426SChris Fallin 717a0318f36SChris Fallin // Also add explicitly-clobbered registers. 718b2e28b91SChris Fallin for preg in self 719b2e28b91SChris Fallin .clobbers 720b2e28b91SChris Fallin .get(&InsnIndex::new(i)) 721b2e28b91SChris Fallin .cloned() 722b2e28b91SChris Fallin .unwrap_or_default() 723b2e28b91SChris Fallin { 724a0318f36SChris Fallin let reg = RealReg::from(preg); 725a0318f36SChris Fallin if clobbered_set.insert(reg) { 726a0318f36SChris Fallin clobbered.push(Writable::from_reg(reg)); 727a0318f36SChris Fallin } 728a0318f36SChris Fallin } 729a0318f36SChris Fallin } 730d8357426SChris Fallin 731a0318f36SChris Fallin clobbered 732d8357426SChris Fallin } 733d8357426SChris Fallin 734a0318f36SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up 735a0318f36SChris Fallin /// code and external reloc/trap/etc. records ready for use. Takes 736a0318f36SChris Fallin /// the regalloc results as well. 737a0318f36SChris Fallin /// 738a0318f36SChris Fallin /// Returns the machine code itself, and optionally metadata 739a0318f36SChris Fallin /// and/or a disassembly, as an `EmitResult`. The `VCode` itself 740a0318f36SChris Fallin /// is consumed by the emission process. 74111a2ef01SChris Fallin pub fn emit( 742a0318f36SChris Fallin mut self, 743a0318f36SChris Fallin regalloc: ®alloc2::Output, 744a0318f36SChris Fallin want_disasm: bool, 745a0318f36SChris Fallin want_metadata: bool, 746a0318f36SChris Fallin ) -> EmitResult<I> 747d8357426SChris Fallin where 748f18a1f14SNick Fitzgerald I: VCodeInst, 749d8357426SChris Fallin { 750a0318f36SChris Fallin // To write into disasm string. 751a0318f36SChris Fallin use core::fmt::Write; 752a0318f36SChris Fallin 7532b9fefe8SChris Fallin let _tt = timing::vcode_emit(); 75472e6be93SChris Fallin let mut buffer = MachBuffer::new(); 75511a2ef01SChris Fallin let mut bb_starts: Vec<Option<CodeOffset>> = vec![]; 756d8357426SChris Fallin 75783f182b3SAndrew Brown // The first M MachLabels are reserved for block indices, the next N MachLabels for 75883f182b3SAndrew Brown // constants. 759a0318f36SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks()); 76083f182b3SAndrew Brown buffer.reserve_labels_for_constants(&self.constants); 761d8357426SChris Fallin 762ef1b2d2fSChris Fallin // Construct the final order we emit code in: cold blocks at the end. 763ef1b2d2fSChris Fallin let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; 764ef1b2d2fSChris Fallin let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; 765ef1b2d2fSChris Fallin for block in 0..self.num_blocks() { 766a0318f36SChris Fallin let block = BlockIndex::new(block); 767ef1b2d2fSChris Fallin if self.block_order.is_cold(block) { 768ef1b2d2fSChris Fallin cold_blocks.push(block); 769ef1b2d2fSChris Fallin } else { 770ef1b2d2fSChris Fallin final_order.push(block); 771ef1b2d2fSChris Fallin } 772ef1b2d2fSChris Fallin } 773d9d64694SChris Fallin final_order.extend(cold_blocks.clone()); 774ef1b2d2fSChris Fallin 775a0318f36SChris Fallin // Compute/save info we need for the prologue: clobbers and 776a0318f36SChris Fallin // number of spillslots. 777a0318f36SChris Fallin // 778a0318f36SChris Fallin // We clone `abi` here because we will mutate it as we 779a0318f36SChris Fallin // generate the prologue and set other info, but we can't 780a0318f36SChris Fallin // mutate `VCode`. The info it usually carries prior to 781a0318f36SChris Fallin // setting clobbers is fairly minimal so this should be 782a0318f36SChris Fallin // relatively cheap. 783a0318f36SChris Fallin let clobbers = self.compute_clobbers(regalloc); 784a0318f36SChris Fallin self.abi.set_num_spillslots(regalloc.num_spillslots); 785a0318f36SChris Fallin self.abi.set_clobbered(clobbers); 786a0318f36SChris Fallin 787a0318f36SChris Fallin // We need to generate the prologue in order to get the ABI 788a0318f36SChris Fallin // object into the right state first. We'll emit it when we 789a0318f36SChris Fallin // hit the right block below. 790f18a1f14SNick Fitzgerald let prologue_insts = self.abi.gen_prologue(&self.sigs); 791a0318f36SChris Fallin 792ef1b2d2fSChris Fallin // Emit blocks. 793964c6087SChris Fallin let mut cur_srcloc = None; 79411a2ef01SChris Fallin let mut last_offset = None; 795a0318f36SChris Fallin let mut inst_offsets = vec![]; 796f0c60f46SNick Fitzgerald let mut state = I::State::new(&self.abi); 797a0318f36SChris Fallin 798a0318f36SChris Fallin let mut disasm = String::new(); 799a0318f36SChris Fallin 800a0318f36SChris Fallin if !self.debug_value_labels.is_empty() { 801a0318f36SChris Fallin inst_offsets.resize(self.insts.len(), 0); 802a0318f36SChris Fallin } 803a0318f36SChris Fallin 804863659e0SChris Fallin // Count edits per block ahead of time; this is needed for 805863659e0SChris Fallin // lookahead island emission. (We could derive it per-block 806863659e0SChris Fallin // with binary search in the edit list, but it's more 807863659e0SChris Fallin // efficient to do it in one pass here.) 808863659e0SChris Fallin let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; 809863659e0SChris Fallin let mut edit_idx = 0; 810863659e0SChris Fallin for block in 0..self.num_blocks() { 811863659e0SChris Fallin let end_inst = self.block_ranges[block].1; 812863659e0SChris Fallin let start_edit_idx = edit_idx; 813863659e0SChris Fallin while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { 814863659e0SChris Fallin edit_idx += 1; 815863659e0SChris Fallin } 816863659e0SChris Fallin let end_edit_idx = edit_idx; 817863659e0SChris Fallin ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); 818863659e0SChris Fallin } 819863659e0SChris Fallin 820d8b29089SAnton Kirilov let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); 821d8b29089SAnton Kirilov 822863659e0SChris Fallin for (block_order_idx, &block) in final_order.iter().enumerate() { 8238d022434SBenjamin Bouvier trace!("emitting block {:?}", 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()); 849a0318f36SChris Fallin for inst in &prologue_insts { 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 857a0318f36SChris Fallin buffer.bind_label(MachLabel::from_block(block)); 858a0318f36SChris Fallin 859a0318f36SChris Fallin if want_disasm { 860a0318f36SChris Fallin writeln!(&mut disasm, "block{}:", block.index()).unwrap(); 861a0318f36SChris Fallin } 862a0318f36SChris Fallin 863a0318f36SChris Fallin if want_metadata { 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 if self.insts[iix.index()].is_move().is_some() { 908a0318f36SChris Fallin // Skip moves in the pre-regalloc program; 909a0318f36SChris Fallin // all of these are incorporated by the 910a0318f36SChris Fallin // regalloc into its unified move handling 911a0318f36SChris Fallin // and they come out the other end, if 912a0318f36SChris Fallin // still needed (not elided), as 913a0318f36SChris Fallin // regalloc-inserted moves. 914a0318f36SChris Fallin continue; 915a0318f36SChris Fallin } 916a0318f36SChris Fallin 917a0318f36SChris Fallin // Update the srcloc at this point in the buffer. 918a0318f36SChris Fallin let srcloc = self.srclocs[iix.index()]; 919964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 920964c6087SChris Fallin if cur_srcloc.is_some() { 92172e6be93SChris Fallin buffer.end_srcloc(); 922b691770fSChris Fallin } 92372e6be93SChris Fallin buffer.start_srcloc(srcloc); 924964c6087SChris Fallin cur_srcloc = Some(srcloc); 925b691770fSChris Fallin } 9268a9b1a90SBenjamin Bouvier state.pre_sourceloc(cur_srcloc.unwrap_or_default()); 927b691770fSChris Fallin 928a0318f36SChris Fallin // If this is a safepoint, compute a stack map 929a0318f36SChris Fallin // and pass it to the emit state. 930a0318f36SChris Fallin if self.insts[iix.index()].is_safepoint() { 931a0318f36SChris Fallin let mut safepoint_slots: SmallVec<[SpillSlot; 8]> = smallvec![]; 932a0318f36SChris Fallin // Find the contiguous range of 933a0318f36SChris Fallin // (progpoint, allocation) safepoint slot 934a0318f36SChris Fallin // records in `regalloc.safepoint_slots` 935a0318f36SChris Fallin // for this instruction index. 936a0318f36SChris Fallin let safepoint_slots_start = regalloc 937a0318f36SChris Fallin .safepoint_slots 938a0318f36SChris Fallin .binary_search_by(|(progpoint, _alloc)| { 939a0318f36SChris Fallin if progpoint.inst() >= iix { 940a0318f36SChris Fallin std::cmp::Ordering::Greater 941a0318f36SChris Fallin } else { 942a0318f36SChris Fallin std::cmp::Ordering::Less 943a0318f36SChris Fallin } 944a0318f36SChris Fallin }) 945a0318f36SChris Fallin .unwrap_err(); 946a0318f36SChris Fallin 947a0318f36SChris Fallin for (_, alloc) in regalloc.safepoint_slots[safepoint_slots_start..] 948a0318f36SChris Fallin .iter() 949a0318f36SChris Fallin .take_while(|(progpoint, _)| progpoint.inst() == iix) 950a0318f36SChris Fallin { 951a0318f36SChris Fallin let slot = alloc.as_stack().unwrap(); 952a0318f36SChris Fallin safepoint_slots.push(slot); 953a0318f36SChris Fallin } 954a0318f36SChris Fallin if !safepoint_slots.is_empty() { 955666c2554SChris Fallin let stack_map = self 956666c2554SChris Fallin .abi 957a0318f36SChris Fallin .spillslots_to_stack_map(&safepoint_slots[..], &state); 95805bf9ea3SNick Fitzgerald state.pre_safepoint(stack_map); 95908353fccSChris Fallin } 960a0318f36SChris Fallin } 96108353fccSChris Fallin 962a0318f36SChris Fallin // Get the allocations for this inst from the regalloc result. 963a0318f36SChris Fallin let allocs = regalloc.inst_allocs(iix); 964de4af90aSYury Delendik 965a0318f36SChris Fallin // If the instruction we are about to emit is 966a0318f36SChris Fallin // a return, place an epilogue at this point 967a0318f36SChris Fallin // (and don't emit the return; the actual 968a0318f36SChris Fallin // epilogue will contain it). 969a0318f36SChris Fallin if self.insts[iix.index()].is_term() == MachTerminator::Ret { 970a0318f36SChris Fallin for inst in self.abi.gen_epilogue() { 971a0318f36SChris Fallin do_emit(&inst, &[], &mut disasm, &mut buffer, &mut state); 972a0318f36SChris Fallin } 973c84d6be6SChris Fallin } else { 974a0318f36SChris Fallin // Emit the instruction! 975a0318f36SChris Fallin do_emit( 976a0318f36SChris Fallin &self.insts[iix.index()], 977a0318f36SChris Fallin allocs, 978a0318f36SChris Fallin &mut disasm, 979a0318f36SChris Fallin &mut buffer, 980a0318f36SChris Fallin &mut state, 981a0318f36SChris Fallin ); 982c84d6be6SChris Fallin } 983c84d6be6SChris Fallin } 984a0318f36SChris Fallin 985a0318f36SChris Fallin InstOrEdit::Edit(Edit::Move { from, to }) => { 986a0318f36SChris Fallin // Create a move/spill/reload instruction and 987a0318f36SChris Fallin // immediately emit it. 988a0318f36SChris Fallin match (from.as_reg(), to.as_reg()) { 989a0318f36SChris Fallin (Some(from), Some(to)) => { 990a0318f36SChris Fallin // Reg-to-reg move. 991a0318f36SChris Fallin let from_rreg = Reg::from(from); 992a0318f36SChris Fallin let to_rreg = Writable::from_reg(Reg::from(to)); 993a0318f36SChris Fallin debug_assert_eq!(from.class(), to.class()); 994a0318f36SChris Fallin let ty = I::canonical_type_for_rc(from.class()); 995a0318f36SChris Fallin let mv = I::gen_move(to_rreg, from_rreg, ty); 996a0318f36SChris Fallin do_emit(&mv, &[], &mut disasm, &mut buffer, &mut state); 997a0318f36SChris Fallin } 998a0318f36SChris Fallin (Some(from), None) => { 999a0318f36SChris Fallin // Spill from register to spillslot. 1000a0318f36SChris Fallin let to = to.as_stack().unwrap(); 1001a0318f36SChris Fallin let from_rreg = RealReg::from(from); 1002a0318f36SChris Fallin let spill = self.abi.gen_spill(to, from_rreg); 1003a0318f36SChris Fallin do_emit(&spill, &[], &mut disasm, &mut buffer, &mut state); 1004a0318f36SChris Fallin } 1005a0318f36SChris Fallin (None, Some(to)) => { 1006a0318f36SChris Fallin // Load from spillslot to register. 1007a0318f36SChris Fallin let from = from.as_stack().unwrap(); 1008a0318f36SChris Fallin let to_rreg = Writable::from_reg(RealReg::from(to)); 1009a0318f36SChris Fallin let reload = self.abi.gen_reload(to_rreg, from); 1010a0318f36SChris Fallin do_emit(&reload, &[], &mut disasm, &mut buffer, &mut state); 1011a0318f36SChris Fallin } 1012a0318f36SChris Fallin (None, None) => { 1013a0318f36SChris Fallin panic!("regalloc2 should have eliminated stack-to-stack moves!"); 1014a0318f36SChris Fallin } 1015a0318f36SChris Fallin } 1016a0318f36SChris Fallin } 1017c84d6be6SChris Fallin } 1018d8357426SChris Fallin } 1019b691770fSChris Fallin 1020964c6087SChris Fallin if cur_srcloc.is_some() { 102172e6be93SChris Fallin buffer.end_srcloc(); 1022964c6087SChris Fallin cur_srcloc = None; 1023b691770fSChris Fallin } 102472e6be93SChris Fallin 1025a0318f36SChris Fallin // Do we need an island? Get the worst-case size of the 1026a0318f36SChris Fallin // next BB and see if, having emitted that many bytes, we 1027a0318f36SChris Fallin // will be beyond the deadline. 1028863659e0SChris Fallin if block_order_idx < final_order.len() - 1 { 1029863659e0SChris Fallin let next_block = final_order[block_order_idx + 1]; 1030863659e0SChris Fallin let next_block_range = self.block_ranges[next_block.index()]; 1031863659e0SChris Fallin let next_block_size = 1032863659e0SChris Fallin (next_block_range.1.index() - next_block_range.0.index()) as u32; 1033863659e0SChris Fallin let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; 1034863659e0SChris Fallin let worst_case_next_bb = 1035863659e0SChris Fallin I::worst_case_size() * (next_block_size + next_block_ra_insertions); 103672e6be93SChris Fallin if buffer.island_needed(worst_case_next_bb) { 10371532516aSAlex Crichton buffer.emit_island(worst_case_next_bb); 103872e6be93SChris Fallin } 103972e6be93SChris Fallin } 1040d8357426SChris Fallin } 1041d8357426SChris Fallin 104283f182b3SAndrew Brown // Emit the constants used by the function. 1043dde2c5a3STrevor Elliott let mut alignment = 1; 104483f182b3SAndrew Brown for (constant, data) in self.constants.iter() { 1045dde2c5a3STrevor Elliott alignment = data.alignment().max(alignment); 1046dde2c5a3STrevor Elliott 104783f182b3SAndrew Brown let label = buffer.get_label_for_constant(constant); 104883f182b3SAndrew Brown buffer.defer_constant(label, data.alignment(), data.as_slice(), u32::max_value()); 104983f182b3SAndrew Brown } 105083f182b3SAndrew Brown 1051a0318f36SChris Fallin let func_body_len = buffer.cur_offset(); 1052de4af90aSYury Delendik 105311a2ef01SChris Fallin // Create `bb_edges` and final (filtered) `bb_starts`. 105411a2ef01SChris Fallin let mut bb_edges = vec![]; 1055a0318f36SChris Fallin let mut bb_offsets = vec![]; 1056a0318f36SChris Fallin if want_metadata { 105711a2ef01SChris Fallin for block in 0..self.num_blocks() { 105811a2ef01SChris Fallin if bb_starts[block].is_none() { 105911a2ef01SChris Fallin // Block was deleted by MachBuffer; skip. 106011a2ef01SChris Fallin continue; 106111a2ef01SChris Fallin } 106211a2ef01SChris Fallin let from = bb_starts[block].unwrap(); 106311a2ef01SChris Fallin 1064a0318f36SChris Fallin bb_offsets.push(from); 106511a2ef01SChris Fallin // Resolve each `succ` label and add edges. 1066a0318f36SChris Fallin let succs = self.block_succs(BlockIndex::new(block)); 1067a0318f36SChris Fallin for &succ in succs.iter() { 1068a0318f36SChris Fallin let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); 106911a2ef01SChris Fallin bb_edges.push((from, to)); 107011a2ef01SChris Fallin } 107111a2ef01SChris Fallin } 1072800cf25bSChris Fallin } 107311a2ef01SChris Fallin 1074a0318f36SChris Fallin let value_labels_ranges = 1075a0318f36SChris Fallin self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); 1076a0318f36SChris Fallin let frame_size = self.abi.frame_size(); 1077a0318f36SChris Fallin 1078a0318f36SChris Fallin EmitResult { 1079a0318f36SChris Fallin buffer, 1080a0318f36SChris Fallin bb_offsets, 1081a0318f36SChris Fallin bb_edges, 1082a0318f36SChris Fallin inst_offsets, 1083a0318f36SChris Fallin func_body_len, 1084a0318f36SChris Fallin disasm: if want_disasm { Some(disasm) } else { None }, 10859c43749dSSam Parker sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), 10869c43749dSSam Parker dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), 1087a0318f36SChris Fallin value_labels_ranges, 1088a0318f36SChris Fallin frame_size, 1089dde2c5a3STrevor Elliott alignment, 1090a0318f36SChris Fallin } 1091d8357426SChris Fallin } 1092d8357426SChris Fallin 1093a0318f36SChris Fallin fn compute_value_labels_ranges( 1094a0318f36SChris Fallin &self, 1095a0318f36SChris Fallin regalloc: ®alloc2::Output, 1096a0318f36SChris Fallin inst_offsets: &[CodeOffset], 1097a0318f36SChris Fallin func_body_len: u32, 1098a0318f36SChris Fallin ) -> ValueLabelsRanges { 1099a0318f36SChris Fallin if self.debug_value_labels.is_empty() { 1100602006ffSbjorn3 return ValueLabelsRanges::default(); 1101997fab55SChris Fallin } 1102997fab55SChris Fallin 1103a0318f36SChris Fallin let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); 1104a0318f36SChris Fallin for &(label, from, to, alloc) in ®alloc.debug_locations { 1105a0318f36SChris Fallin let ranges = value_labels_ranges 1106a0318f36SChris Fallin .entry(ValueLabel::from_u32(label)) 1107a0318f36SChris Fallin .or_insert_with(|| vec![]); 1108a0318f36SChris Fallin let from_offset = inst_offsets[from.inst().index()]; 1109a0318f36SChris Fallin let to_offset = if to.inst().index() == inst_offsets.len() { 1110a0318f36SChris Fallin func_body_len 1111a0318f36SChris Fallin } else { 1112a0318f36SChris Fallin inst_offsets[to.inst().index()] 1113a0318f36SChris Fallin }; 1114a0318f36SChris Fallin 1115a0318f36SChris Fallin // Empty range or to-offset of zero can happen because of 1116a0318f36SChris Fallin // cold blocks (see above). 1117a0318f36SChris Fallin if to_offset == 0 || from_offset == to_offset { 1118a0318f36SChris Fallin continue; 111976d61504Sbjorn3 } 112076d61504Sbjorn3 1121a0318f36SChris Fallin let loc = if let Some(preg) = alloc.as_reg() { 1122a0318f36SChris Fallin LabelValueLoc::Reg(Reg::from(preg)) 1123a0318f36SChris Fallin } else { 1124a0318f36SChris Fallin // We can't translate spillslot locations at the 1125a0318f36SChris Fallin // moment because ValueLabelLoc requires an 1126a0318f36SChris Fallin // instantaneous SP offset, and this can *change* 1127a0318f36SChris Fallin // within the range we have here because of callsites 1128a0318f36SChris Fallin // adjusting SP temporarily. To avoid the complexity 1129a0318f36SChris Fallin // of accurately plumbing through nominal-SP 1130a0318f36SChris Fallin // adjustment sites, we just omit debug info for 1131a0318f36SChris Fallin // values that are spilled. Not ideal, but debug info 1132a0318f36SChris Fallin // is best-effort. 1133a0318f36SChris Fallin continue; 1134a0318f36SChris Fallin }; 1135a0318f36SChris Fallin 1136a0318f36SChris Fallin ranges.push(ValueLocRange { 1137a0318f36SChris Fallin loc, 1138a0318f36SChris Fallin // ValueLocRanges are recorded by *instruction-end 1139a0318f36SChris Fallin // offset*. `from_offset` is the *start* of the 1140a0318f36SChris Fallin // instruction; that is the same as the end of another 1141a0318f36SChris Fallin // instruction, so we only want to begin coverage once 1142a0318f36SChris Fallin // we are past the previous instruction's end. 1143a0318f36SChris Fallin start: from_offset + 1, 1144a0318f36SChris Fallin // Likewise, `end` is exclusive, but we want to 1145a0318f36SChris Fallin // *include* the end of the last 1146a0318f36SChris Fallin // instruction. `to_offset` is the start of the 1147a0318f36SChris Fallin // `to`-instruction, which is the exclusive end, i.e., 1148a0318f36SChris Fallin // the first instruction not covered. That 1149a0318f36SChris Fallin // instruction's start is the same as the end of the 1150a0318f36SChris Fallin // last instruction that is included, so we go one 1151a0318f36SChris Fallin // byte further to be sure to include it. 1152a0318f36SChris Fallin end: to_offset + 1, 1153a0318f36SChris Fallin }); 1154a0318f36SChris Fallin } 1155a0318f36SChris Fallin 1156a0318f36SChris Fallin value_labels_ranges 1157c84d6be6SChris Fallin } 1158c84d6be6SChris Fallin 1159d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 1160d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 1161a0318f36SChris Fallin self.block_order.lowered_order()[block.index()].orig_block() 1162d8357426SChris Fallin } 11632154c63dSAlex Crichton 11642154c63dSAlex Crichton #[inline] 11652154c63dSAlex Crichton fn assert_no_vreg_aliases<'a>(&self, list: &'a [VReg]) -> &'a [VReg] { 11662154c63dSAlex Crichton for vreg in list { 11672154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 11682154c63dSAlex Crichton } 11692154c63dSAlex Crichton list 11702154c63dSAlex Crichton } 11712154c63dSAlex Crichton 11722154c63dSAlex Crichton #[inline] 11732154c63dSAlex Crichton fn assert_not_vreg_alias(&self, vreg: VReg) -> VReg { 11742154c63dSAlex Crichton debug_assert!(VCodeBuilder::<I>::resolve_vreg_alias_impl(&self.vreg_aliases, vreg) == vreg); 11752154c63dSAlex Crichton vreg 11762154c63dSAlex Crichton } 11772154c63dSAlex Crichton 11782154c63dSAlex Crichton #[inline] 11792154c63dSAlex Crichton fn assert_operand_not_vreg_alias(&self, op: Operand) -> Operand { 11802154c63dSAlex Crichton // It should be true by construction that `Operand`s do not contain any 11812154c63dSAlex Crichton // aliased vregs since they're all collected and mapped when the VCode 11822154c63dSAlex Crichton // is itself constructed. 11832154c63dSAlex Crichton self.assert_not_vreg_alias(op.vreg()); 11842154c63dSAlex Crichton op 11852154c63dSAlex Crichton } 1186d8357426SChris Fallin } 1187d8357426SChris Fallin 1188d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 1189a0318f36SChris Fallin fn num_insts(&self) -> usize { 1190a0318f36SChris Fallin self.insts.len() 1191d8357426SChris Fallin } 1192d8357426SChris Fallin 1193a0318f36SChris Fallin fn num_blocks(&self) -> usize { 1194a0318f36SChris Fallin self.block_ranges.len() 1195d8357426SChris Fallin } 1196d8357426SChris Fallin 1197a0318f36SChris Fallin fn entry_block(&self) -> BlockIndex { 1198a0318f36SChris Fallin self.entry 1199d8357426SChris Fallin } 1200d8357426SChris Fallin 1201a0318f36SChris Fallin fn block_insns(&self, block: BlockIndex) -> InstRange { 1202a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1203a0318f36SChris Fallin InstRange::forward(start, end) 1204d8357426SChris Fallin } 1205d8357426SChris Fallin 1206a0318f36SChris Fallin fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { 1207a0318f36SChris Fallin let (start, end) = self.block_succ_range[block.index()]; 1208a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1209d8357426SChris Fallin } 1210d8357426SChris Fallin 1211a0318f36SChris Fallin fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { 1212a0318f36SChris Fallin let (start, end) = self.block_pred_range[block.index()]; 1213a0318f36SChris Fallin &self.block_succs_preds[start as usize..end as usize] 1214d8357426SChris Fallin } 1215d8357426SChris Fallin 1216a0318f36SChris Fallin fn block_params(&self, block: BlockIndex) -> &[VReg] { 1217a0318f36SChris Fallin let (start, end) = self.block_params_range[block.index()]; 12182154c63dSAlex Crichton let ret = &self.block_params[start as usize..end as usize]; 12192154c63dSAlex Crichton // Currently block params are never aliased to another vreg, but 12202154c63dSAlex Crichton // double-check just to be sure. 12212154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1222d8357426SChris Fallin } 1223d8357426SChris Fallin 1224a0318f36SChris Fallin fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { 1225a0318f36SChris Fallin let (succ_range_start, succ_range_end) = self.branch_block_arg_succ_range[block.index()]; 1226a0318f36SChris Fallin let succ_ranges = 1227a0318f36SChris Fallin &self.branch_block_arg_range[succ_range_start as usize..succ_range_end as usize]; 1228a0318f36SChris Fallin let (branch_block_args_start, branch_block_args_end) = succ_ranges[succ_idx]; 12292154c63dSAlex Crichton let ret = &self.branch_block_args 12302154c63dSAlex Crichton [branch_block_args_start as usize..branch_block_args_end as usize]; 12312154c63dSAlex Crichton self.assert_no_vreg_aliases(ret) 1232d8357426SChris Fallin } 1233d8357426SChris Fallin 1234a0318f36SChris Fallin fn is_ret(&self, insn: InsnIndex) -> bool { 1235a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 1236d8357426SChris Fallin MachTerminator::Ret => true, 1237d8357426SChris Fallin _ => false, 1238d8357426SChris Fallin } 1239d8357426SChris Fallin } 1240d8357426SChris Fallin 1241a0318f36SChris Fallin fn is_branch(&self, insn: InsnIndex) -> bool { 1242a0318f36SChris Fallin match self.insts[insn.index()].is_term() { 12435774e068SChris Fallin MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, 1244a0318f36SChris Fallin _ => false, 1245a0318f36SChris Fallin } 124671768bb6SChris Fallin } 124771768bb6SChris Fallin 1248a0318f36SChris Fallin fn requires_refs_on_stack(&self, insn: InsnIndex) -> bool { 1249a0318f36SChris Fallin self.insts[insn.index()].is_safepoint() 1250d8357426SChris Fallin } 1251d8357426SChris Fallin 1252a0318f36SChris Fallin fn is_move(&self, insn: InsnIndex) -> Option<(Operand, Operand)> { 12532154c63dSAlex Crichton let (a, b) = self.is_move.get(&insn)?; 12542154c63dSAlex Crichton Some(( 12552154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*a), 12562154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*b), 12572154c63dSAlex Crichton )) 1258d8357426SChris Fallin } 1259d8357426SChris Fallin 1260a0318f36SChris Fallin fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { 1261a0318f36SChris Fallin let (start, end) = self.operand_ranges[insn.index()]; 12622154c63dSAlex Crichton let ret = &self.operands[start as usize..end as usize]; 12632154c63dSAlex Crichton for op in ret { 12642154c63dSAlex Crichton self.assert_operand_not_vreg_alias(*op); 12652154c63dSAlex Crichton } 12662154c63dSAlex Crichton ret 1267d8357426SChris Fallin } 1268d8357426SChris Fallin 1269b2e28b91SChris Fallin fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { 1270b2e28b91SChris Fallin self.clobbers.get(&insn).cloned().unwrap_or_default() 1271be6f060aSChris Fallin } 1272be6f060aSChris Fallin 1273a0318f36SChris Fallin fn num_vregs(&self) -> usize { 1274a0318f36SChris Fallin std::cmp::max(self.vreg_types.len(), first_user_vreg_index()) 1275d8357426SChris Fallin } 1276d8357426SChris Fallin 1277a0318f36SChris Fallin fn reftype_vregs(&self) -> &[VReg] { 12782154c63dSAlex Crichton self.assert_no_vreg_aliases(&self.reftyped_vregs[..]) 1279d8357426SChris Fallin } 1280d8357426SChris Fallin 1281a0318f36SChris Fallin fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { 12822154c63dSAlex Crichton // VRegs here are inserted into `debug_value_labels` after code is 12832154c63dSAlex Crichton // generated and aliases are fully defined, so no double-check that 12842154c63dSAlex Crichton // aliases are not lingering. 12852154c63dSAlex Crichton for (vreg, ..) in self.debug_value_labels.iter() { 12862154c63dSAlex Crichton self.assert_not_vreg_alias(*vreg); 12872154c63dSAlex Crichton } 1288a0318f36SChris Fallin &self.debug_value_labels[..] 1289d8357426SChris Fallin } 1290d8357426SChris Fallin 1291a0318f36SChris Fallin fn is_pinned_vreg(&self, vreg: VReg) -> Option<PReg> { 1292a0318f36SChris Fallin pinned_vreg_to_preg(vreg) 1293d8357426SChris Fallin } 1294d8357426SChris Fallin 1295a0318f36SChris Fallin fn spillslot_size(&self, regclass: RegClass) -> usize { 1296a0318f36SChris Fallin self.abi.get_spillslot_size(regclass) as usize 1297d8357426SChris Fallin } 1298d8357426SChris Fallin 1299a0318f36SChris Fallin fn allow_multiple_vreg_defs(&self) -> bool { 1300a0318f36SChris Fallin // At least the s390x backend requires this, because the 1301a0318f36SChris Fallin // `Loop` pseudo-instruction aggregates all Operands so pinned 1302a0318f36SChris Fallin // vregs (RealRegs) may occur more than once. 1303a0318f36SChris Fallin true 1304d8357426SChris Fallin } 1305d8357426SChris Fallin } 1306d8357426SChris Fallin 1307d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 1308d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1309a0318f36SChris Fallin writeln!(f, "VCode {{")?; 1310a0318f36SChris Fallin writeln!(f, " Entry block: {}", self.entry.index())?; 1311a0318f36SChris Fallin 1312a0318f36SChris Fallin let mut state = Default::default(); 1313a0318f36SChris Fallin 1314a0318f36SChris Fallin let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>(); 1315a0318f36SChris Fallin alias_keys.sort_unstable(); 1316a0318f36SChris Fallin for key in alias_keys { 1317a0318f36SChris Fallin let dest = self.vreg_aliases.get(&key).unwrap(); 1318a0318f36SChris Fallin writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; 1319a0318f36SChris Fallin } 1320d8357426SChris Fallin 1321d8357426SChris Fallin for block in 0..self.num_blocks() { 1322a0318f36SChris Fallin let block = BlockIndex::new(block); 1323a0318f36SChris Fallin writeln!(f, "Block {}:", block.index())?; 1324a0318f36SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 1325a0318f36SChris Fallin writeln!(f, " (original IR block: {})", bb)?; 1326d8357426SChris Fallin } 1327a0318f36SChris Fallin for succ in self.succs(block) { 1328a0318f36SChris Fallin writeln!(f, " (successor: Block {})", succ.index())?; 1329a0318f36SChris Fallin } 1330a0318f36SChris Fallin let (start, end) = self.block_ranges[block.index()]; 1331a0318f36SChris Fallin writeln!( 1332a0318f36SChris Fallin f, 1333a0318f36SChris Fallin " (instruction range: {} .. {})", 1334a0318f36SChris Fallin start.index(), 1335a0318f36SChris Fallin end.index() 1336a0318f36SChris Fallin )?; 1337a0318f36SChris Fallin for inst in start.index()..end.index() { 1338a0318f36SChris Fallin writeln!( 1339a0318f36SChris Fallin f, 1340a0318f36SChris Fallin " Inst {}: {}", 1341a0318f36SChris Fallin inst, 1342a0318f36SChris Fallin self.insts[inst].pretty_print_inst(&[], &mut state) 1343a0318f36SChris Fallin )?; 1344d8357426SChris Fallin } 1345d8357426SChris Fallin } 1346d8357426SChris Fallin 1347d8357426SChris Fallin writeln!(f, "}}")?; 1348d8357426SChris Fallin Ok(()) 1349d8357426SChris Fallin } 1350d8357426SChris Fallin } 1351d8357426SChris Fallin 1352d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder. 1353d94173eaSTrevor Elliott pub struct VRegAllocator<I> { 1354d94173eaSTrevor Elliott /// Next virtual register number to allocate. 1355d94173eaSTrevor Elliott next_vreg: usize, 1356d94173eaSTrevor Elliott 1357d94173eaSTrevor Elliott /// VReg IR-level types. 1358d94173eaSTrevor Elliott vreg_types: Vec<Type>, 1359d94173eaSTrevor Elliott 1360d94173eaSTrevor Elliott /// A set with the same contents as `reftyped_vregs`, in order to 1361d94173eaSTrevor Elliott /// avoid inserting more than once. 1362d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet<VReg>, 1363d94173eaSTrevor Elliott 1364d94173eaSTrevor Elliott /// Reference-typed `regalloc2::VReg`s. The regalloc requires 1365d94173eaSTrevor Elliott /// these in a dense slice (as opposed to querying the 1366d94173eaSTrevor Elliott /// reftype-status of each vreg) for efficient iteration. 1367d94173eaSTrevor Elliott reftyped_vregs: Vec<VReg>, 1368d94173eaSTrevor Elliott 1369d94173eaSTrevor Elliott /// The type of instruction that this allocator makes registers for. 1370d94173eaSTrevor Elliott _inst: core::marker::PhantomData<I>, 1371d94173eaSTrevor Elliott } 1372d94173eaSTrevor Elliott 1373d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> { 1374d94173eaSTrevor Elliott /// Make a new VRegAllocator. 1375d94173eaSTrevor Elliott pub fn new() -> Self { 1376d94173eaSTrevor Elliott Self { 1377d94173eaSTrevor Elliott next_vreg: first_user_vreg_index(), 1378d94173eaSTrevor Elliott vreg_types: vec![], 1379d94173eaSTrevor Elliott reftyped_vregs_set: FxHashSet::default(), 1380d94173eaSTrevor Elliott reftyped_vregs: vec![], 1381d94173eaSTrevor Elliott _inst: core::marker::PhantomData::default(), 1382d94173eaSTrevor Elliott } 1383d94173eaSTrevor Elliott } 1384d94173eaSTrevor Elliott 1385d94173eaSTrevor Elliott /// Allocate a fresh ValueRegs. 1386d94173eaSTrevor Elliott pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> { 1387d94173eaSTrevor Elliott let v = self.next_vreg; 1388d94173eaSTrevor Elliott let (regclasses, tys) = I::rc_for_type(ty)?; 1389d94173eaSTrevor Elliott self.next_vreg += regclasses.len(); 1390d94173eaSTrevor Elliott if self.next_vreg >= VReg::MAX { 1391d94173eaSTrevor Elliott return Err(CodegenError::CodeTooLarge); 1392d94173eaSTrevor Elliott } 1393d94173eaSTrevor Elliott 1394d94173eaSTrevor Elliott let regs: ValueRegs<Reg> = match regclasses { 1395d94173eaSTrevor Elliott &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), 1396d94173eaSTrevor Elliott &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), 1397d94173eaSTrevor Elliott // We can extend this if/when we support 32-bit targets; e.g., 1398d94173eaSTrevor Elliott // an i128 on a 32-bit machine will need up to four machine regs 1399d94173eaSTrevor Elliott // for a `Value`. 1400d94173eaSTrevor Elliott _ => panic!("Value must reside in 1 or 2 registers"), 1401d94173eaSTrevor Elliott }; 1402d94173eaSTrevor Elliott for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { 1403d94173eaSTrevor Elliott self.set_vreg_type(reg.to_virtual_reg().unwrap(), reg_ty); 1404d94173eaSTrevor Elliott } 1405d94173eaSTrevor Elliott Ok(regs) 1406d94173eaSTrevor Elliott } 1407d94173eaSTrevor Elliott 1408d94173eaSTrevor Elliott /// Set the type of this virtual register. 1409d94173eaSTrevor Elliott pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 1410d94173eaSTrevor Elliott if self.vreg_types.len() <= vreg.index() { 1411*70bca801STrevor Elliott self.vreg_types.resize(vreg.index() + 1, ir::types::INVALID); 1412d94173eaSTrevor Elliott } 1413d94173eaSTrevor Elliott self.vreg_types[vreg.index()] = ty; 1414d94173eaSTrevor Elliott if is_reftype(ty) { 1415d94173eaSTrevor Elliott let vreg: VReg = vreg.into(); 1416d94173eaSTrevor Elliott if self.reftyped_vregs_set.insert(vreg) { 1417d94173eaSTrevor Elliott self.reftyped_vregs.push(vreg); 1418d94173eaSTrevor Elliott } 1419d94173eaSTrevor Elliott } 1420d94173eaSTrevor Elliott } 1421d94173eaSTrevor Elliott } 1422d94173eaSTrevor Elliott 142383f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the 142483f182b3SAndrew Brown /// [MachBuffer]. 142583f182b3SAndrew Brown /// 142683f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using 142783f182b3SAndrew Brown /// [VCodeConstants.insert]; an intermediate handle, [VCodeConstant], tracks what constants are 142883f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant 142983f182b3SAndrew Brown /// values are inserted. 143083f182b3SAndrew Brown /// 143183f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the 143283f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer] 143383f182b3SAndrew Brown /// then writes the constant values to the buffer. 143483f182b3SAndrew Brown #[derive(Default)] 143583f182b3SAndrew Brown pub struct VCodeConstants { 143683f182b3SAndrew Brown constants: PrimaryMap<VCodeConstant, VCodeConstantData>, 143783f182b3SAndrew Brown pool_uses: HashMap<Constant, VCodeConstant>, 143883f182b3SAndrew Brown well_known_uses: HashMap<*const [u8], VCodeConstant>, 1439eb435f30SChris Fallin u64s: HashMap<[u8; 8], VCodeConstant>, 144083f182b3SAndrew Brown } 144183f182b3SAndrew Brown impl VCodeConstants { 144283f182b3SAndrew Brown /// Initialize the structure with the expected number of constants. 144383f182b3SAndrew Brown pub fn with_capacity(expected_num_constants: usize) -> Self { 144483f182b3SAndrew Brown Self { 144583f182b3SAndrew Brown constants: PrimaryMap::with_capacity(expected_num_constants), 144683f182b3SAndrew Brown pool_uses: HashMap::with_capacity(expected_num_constants), 144783f182b3SAndrew Brown well_known_uses: HashMap::new(), 1448eb435f30SChris Fallin u64s: HashMap::new(), 144983f182b3SAndrew Brown } 145083f182b3SAndrew Brown } 145183f182b3SAndrew Brown 145283f182b3SAndrew Brown /// Insert a constant; using this method indicates that a constant value will be used and thus 145383f182b3SAndrew Brown /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants 145483f182b3SAndrew Brown /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not 145583f182b3SAndrew Brown /// [VCodeConstantData::Generated]. 145683f182b3SAndrew Brown pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { 145783f182b3SAndrew Brown match data { 145883f182b3SAndrew Brown VCodeConstantData::Generated(_) => self.constants.push(data), 145983f182b3SAndrew Brown VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { 146083f182b3SAndrew Brown None => { 146183f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 146283f182b3SAndrew Brown self.pool_uses.insert(constant, vcode_constant); 146383f182b3SAndrew Brown vcode_constant 146483f182b3SAndrew Brown } 146583f182b3SAndrew Brown Some(&vcode_constant) => vcode_constant, 146683f182b3SAndrew Brown }, 146783f182b3SAndrew Brown VCodeConstantData::WellKnown(data_ref) => { 1468eb435f30SChris Fallin match self.well_known_uses.entry(data_ref as *const [u8]) { 1469eb435f30SChris Fallin Entry::Vacant(v) => { 147083f182b3SAndrew Brown let vcode_constant = self.constants.push(data); 1471eb435f30SChris Fallin v.insert(vcode_constant); 147283f182b3SAndrew Brown vcode_constant 147383f182b3SAndrew Brown } 1474eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 147583f182b3SAndrew Brown } 147683f182b3SAndrew Brown } 1477eb435f30SChris Fallin VCodeConstantData::U64(value) => match self.u64s.entry(value) { 1478eb435f30SChris Fallin Entry::Vacant(v) => { 1479eb435f30SChris Fallin let vcode_constant = self.constants.push(data); 1480eb435f30SChris Fallin v.insert(vcode_constant); 1481eb435f30SChris Fallin vcode_constant 1482eb435f30SChris Fallin } 1483eb435f30SChris Fallin Entry::Occupied(o) => *o.get(), 1484eb435f30SChris Fallin }, 148583f182b3SAndrew Brown } 148683f182b3SAndrew Brown } 148783f182b3SAndrew Brown 148883f182b3SAndrew Brown /// Return the number of constants inserted. 148983f182b3SAndrew Brown pub fn len(&self) -> usize { 149083f182b3SAndrew Brown self.constants.len() 149183f182b3SAndrew Brown } 149283f182b3SAndrew Brown 149383f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys inserted in this structure. 149483f182b3SAndrew Brown pub fn keys(&self) -> Keys<VCodeConstant> { 149583f182b3SAndrew Brown self.constants.keys() 149683f182b3SAndrew Brown } 149783f182b3SAndrew Brown 149883f182b3SAndrew Brown /// Iterate over the [VCodeConstant] keys and the data (as a byte slice) inserted in this 149983f182b3SAndrew Brown /// structure. 150083f182b3SAndrew Brown pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> { 150183f182b3SAndrew Brown self.constants.iter() 150283f182b3SAndrew Brown } 150383f182b3SAndrew Brown } 150483f182b3SAndrew Brown 150583f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants]. 150683f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)] 150783f182b3SAndrew Brown pub struct VCodeConstant(u32); 150883f182b3SAndrew Brown entity_impl!(VCodeConstant); 150983f182b3SAndrew Brown 151083f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking 151183f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication. 151283f182b3SAndrew Brown pub enum VCodeConstantData { 151383f182b3SAndrew Brown /// A constant already present in the Cranelift IR 151483f182b3SAndrew Brown /// [ConstantPool](crate::ir::constant::ConstantPool). 151583f182b3SAndrew Brown Pool(Constant, ConstantData), 151683f182b3SAndrew Brown /// A reference to a well-known constant value that is statically encoded within the compiler. 151783f182b3SAndrew Brown WellKnown(&'static [u8]), 151883f182b3SAndrew Brown /// A constant value generated during lowering; the value may depend on the instruction context 151983f182b3SAndrew Brown /// which makes it difficult to de-duplicate--if possible, use other variants. 152083f182b3SAndrew Brown Generated(ConstantData), 1521eb435f30SChris Fallin /// A constant of at most 64 bits. These are deduplicated as 1522eb435f30SChris Fallin /// well. Stored as a fixed-size array of `u8` so that we do not 1523eb435f30SChris Fallin /// encounter endianness problems when cross-compiling. 1524eb435f30SChris Fallin U64([u8; 8]), 152583f182b3SAndrew Brown } 152683f182b3SAndrew Brown impl VCodeConstantData { 152783f182b3SAndrew Brown /// Retrieve the constant data as a byte slice. 152883f182b3SAndrew Brown pub fn as_slice(&self) -> &[u8] { 152983f182b3SAndrew Brown match self { 153083f182b3SAndrew Brown VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), 153183f182b3SAndrew Brown VCodeConstantData::WellKnown(d) => d, 1532eb435f30SChris Fallin VCodeConstantData::U64(value) => &value[..], 153383f182b3SAndrew Brown } 153483f182b3SAndrew Brown } 153583f182b3SAndrew Brown 153683f182b3SAndrew Brown /// Calculate the alignment of the constant data. 153783f182b3SAndrew Brown pub fn alignment(&self) -> u32 { 153883f182b3SAndrew Brown if self.as_slice().len() <= 8 { 153983f182b3SAndrew Brown 8 154083f182b3SAndrew Brown } else { 154183f182b3SAndrew Brown 16 154283f182b3SAndrew Brown } 154383f182b3SAndrew Brown } 154483f182b3SAndrew Brown } 154583f182b3SAndrew Brown 154683f182b3SAndrew Brown #[cfg(test)] 154783f182b3SAndrew Brown mod test { 154883f182b3SAndrew Brown use super::*; 15495e5e5206SChris Fallin use std::mem::size_of; 155083f182b3SAndrew Brown 155183f182b3SAndrew Brown #[test] 155283f182b3SAndrew Brown fn size_of_constant_structs() { 155383f182b3SAndrew Brown assert_eq!(size_of::<Constant>(), 4); 155483f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstant>(), 4); 155583f182b3SAndrew Brown assert_eq!(size_of::<ConstantData>(), 24); 155683f182b3SAndrew Brown assert_eq!(size_of::<VCodeConstantData>(), 32); 155783f182b3SAndrew Brown assert_eq!( 155883f182b3SAndrew Brown size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(), 155983f182b3SAndrew Brown 24 156083f182b3SAndrew Brown ); 15615e5e5206SChris Fallin // TODO The VCodeConstants structure's memory size could be further optimized. 15625e5e5206SChris Fallin // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at 15635e5e5206SChris Fallin // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. 156483f182b3SAndrew Brown } 156583f182b3SAndrew Brown } 1566