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 
2090ac295eSAlex Crichton use crate::CodegenError;
2176911c29SSSD use crate::FxHashMap;
2290ac295eSAlex Crichton use crate::ir::{self, Constant, ConstantData, ValueLabel, types};
232c409535SJamey Sharp use crate::ranges::Ranges;
242b9fefe8SChris Fallin use crate::timing;
258d022434SBenjamin Bouvier use crate::trace;
26729e2640Sbjorn3 use crate::{LabelValueLoc, ValueLocRange};
2790ac295eSAlex Crichton use crate::{machinst::*, trace_log_enabled};
28a0318f36SChris Fallin use regalloc2::{
295ded0f4eSUlrich Weigand     Edit, Function as RegallocFunction, InstOrEdit, InstPosition, InstRange, Operand,
305b63c874SSingleAccretion     OperandConstraint, OperandKind, PRegSet, ProgPoint, RegClass,
31be6f060aSChris Fallin };
32d8357426SChris Fallin 
330889323aSSSD use crate::HashMap;
340889323aSSSD use crate::hash_map::Entry;
353da7fc8eSSingleAccretion use core::cmp::Ordering;
363da7fc8eSSingleAccretion use core::fmt::{self, Write};
373aa32064SJamey Sharp use core::mem::take;
38a3d6e407SChris Fallin use core::ops::Range;
3990ac295eSAlex Crichton use cranelift_entity::{Keys, entity_impl};
40d8357426SChris Fallin 
41d8357426SChris Fallin /// Index referring to an instruction in VCode.
42a0318f36SChris Fallin pub type InsnIndex = regalloc2::Inst;
43a0318f36SChris Fallin 
44e20b4244SNick Fitzgerald /// Extension trait for `InsnIndex` to allow conversion to a
45e20b4244SNick Fitzgerald /// `BackwardsInsnIndex`.
46e20b4244SNick Fitzgerald trait ToBackwardsInsnIndex {
to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex47e20b4244SNick Fitzgerald     fn to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex;
48e20b4244SNick Fitzgerald }
49e20b4244SNick Fitzgerald 
50e20b4244SNick Fitzgerald impl ToBackwardsInsnIndex for InsnIndex {
to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex51e20b4244SNick Fitzgerald     fn to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex {
52e20b4244SNick Fitzgerald         BackwardsInsnIndex::new(num_insts - self.index() - 1)
53e20b4244SNick Fitzgerald     }
54e20b4244SNick Fitzgerald }
55e20b4244SNick Fitzgerald 
56e20b4244SNick Fitzgerald /// An index referring to an instruction in the VCode when it is backwards,
57e20b4244SNick Fitzgerald /// during VCode construction.
58e20b4244SNick Fitzgerald #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
59e20b4244SNick Fitzgerald #[cfg_attr(
60e20b4244SNick Fitzgerald     feature = "enable-serde",
61e20b4244SNick Fitzgerald     derive(::serde::Serialize, ::serde::Deserialize)
62e20b4244SNick Fitzgerald )]
63e20b4244SNick Fitzgerald pub struct BackwardsInsnIndex(InsnIndex);
64e20b4244SNick Fitzgerald 
65e20b4244SNick Fitzgerald impl BackwardsInsnIndex {
new(i: usize) -> Self66e20b4244SNick Fitzgerald     pub fn new(i: usize) -> Self {
67e20b4244SNick Fitzgerald         BackwardsInsnIndex(InsnIndex::new(i))
68e20b4244SNick Fitzgerald     }
69e20b4244SNick Fitzgerald }
70e20b4244SNick Fitzgerald 
71d8357426SChris Fallin /// Index referring to a basic block in VCode.
72a0318f36SChris Fallin pub type BlockIndex = regalloc2::Block;
73d8357426SChris Fallin 
74d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
75d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
7672e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {}
7772e6be93SChris Fallin impl<I: MachInst + MachInstEmit> VCodeInst for I {}
78d8357426SChris Fallin 
79a0318f36SChris Fallin /// A function in "VCode" (virtualized-register code) form, after
80a0318f36SChris Fallin /// lowering.  This is essentially a standard CFG of basic blocks,
81a0318f36SChris Fallin /// where each basic block consists of lowered instructions produced
82a0318f36SChris Fallin /// by the machine-specific backend.
83a0318f36SChris Fallin ///
84a0318f36SChris Fallin /// Note that the VCode is immutable once produced, and is not
85a0318f36SChris Fallin /// modified by register allocation in particular. Rather, register
86a0318f36SChris Fallin /// allocation on the `VCode` produces a separate `regalloc2::Output`
87a0318f36SChris Fallin /// struct, and this can be passed to `emit`. `emit` in turn does not
88a0318f36SChris Fallin /// modify the vcode, but produces an `EmitResult`, which contains the
89a0318f36SChris Fallin /// machine code itself, and the associated disassembly and/or
90a0318f36SChris Fallin /// metadata as requested.
91d8357426SChris Fallin pub struct VCode<I: VCodeInst> {
92d8357426SChris Fallin     /// VReg IR-level types.
93d8357426SChris Fallin     vreg_types: Vec<Type>,
94d8357426SChris Fallin 
95d8357426SChris Fallin     /// Lowered machine instructions in order corresponding to the original IR.
9648cf2c2fSChris Fallin     insts: Vec<I>,
97d8357426SChris Fallin 
98e20b4244SNick Fitzgerald     /// A map from backwards instruction index to the user stack map for that
99e20b4244SNick Fitzgerald     /// instruction.
100e20b4244SNick Fitzgerald     ///
101e20b4244SNick Fitzgerald     /// This is a sparse side table that only has entries for instructions that
102e20b4244SNick Fitzgerald     /// are safepoints, and only for a subset of those that have an associated
103e20b4244SNick Fitzgerald     /// user stack map.
104e20b4244SNick Fitzgerald     user_stack_maps: FxHashMap<BackwardsInsnIndex, ir::UserStackMap>,
105e20b4244SNick Fitzgerald 
106a3d6e407SChris Fallin     /// A map from backwards instruction index to the debug tags for
107a3d6e407SChris Fallin     /// that instruction. Each entry indexes a range in the
108a3d6e407SChris Fallin     /// `debug_tag_pool`.
109a3d6e407SChris Fallin     debug_tags: FxHashMap<BackwardsInsnIndex, Range<u32>>,
110a3d6e407SChris Fallin 
111a3d6e407SChris Fallin     /// Pooled storage for sequences of debug tags; indexed by entries
112a3d6e407SChris Fallin     /// in `debug_tags`.
113a3d6e407SChris Fallin     debug_tag_pool: Vec<ir::DebugTag>,
114a3d6e407SChris Fallin 
115a0318f36SChris Fallin     /// Operands: pre-regalloc references to virtual registers with
116a0318f36SChris Fallin     /// constraints, in one flattened array. This allows the regalloc
117a0318f36SChris Fallin     /// to efficiently access all operands without requiring expensive
118a0318f36SChris Fallin     /// matches or method invocations on insts.
119a0318f36SChris Fallin     operands: Vec<Operand>,
120a0318f36SChris Fallin 
121a0318f36SChris Fallin     /// Operand index ranges: for each instruction in `insts`, there
122a0318f36SChris Fallin     /// is a tuple here providing the range in `operands` for that
123a0318f36SChris Fallin     /// instruction's operands.
1242c409535SJamey Sharp     operand_ranges: Ranges,
125a0318f36SChris Fallin 
126b2e28b91SChris Fallin     /// Clobbers: a sparse map from instruction indices to clobber masks.
127b2e28b91SChris Fallin     clobbers: FxHashMap<InsnIndex, PRegSet>,
128a0318f36SChris Fallin 
129b691770fSChris Fallin     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
130b691770fSChris Fallin     /// reasonable to keep one of these per instruction.)
1318a9b1a90SBenjamin Bouvier     srclocs: Vec<RelSourceLoc>,
132b691770fSChris Fallin 
133d8357426SChris Fallin     /// Entry block.
134d8357426SChris Fallin     entry: BlockIndex,
135d8357426SChris Fallin 
136d8357426SChris Fallin     /// Block instruction indices.
1372c409535SJamey Sharp     block_ranges: Ranges,
138d8357426SChris Fallin 
1390f4c0d4aSJamey Sharp     /// Block successors: index range in the `block_succs` list.
1402c409535SJamey Sharp     block_succ_range: Ranges,
141d8357426SChris Fallin 
1420f4c0d4aSJamey Sharp     /// Block successor lists, concatenated into one vec. The
1430f4c0d4aSJamey Sharp     /// `block_succ_range` list of tuples above gives (start, end)
1440f4c0d4aSJamey Sharp     /// ranges within this list that correspond to each basic block's
1450f4c0d4aSJamey Sharp     /// successors.
1460f4c0d4aSJamey Sharp     block_succs: Vec<regalloc2::Block>,
1470f4c0d4aSJamey Sharp 
1480f4c0d4aSJamey Sharp     /// Block predecessors: index range in the `block_preds` list.
1492c409535SJamey Sharp     block_pred_range: Ranges,
150a0318f36SChris Fallin 
1510f4c0d4aSJamey Sharp     /// Block predecessor lists, concatenated into one vec. The
1520f4c0d4aSJamey Sharp     /// `block_pred_range` list of tuples above gives (start, end)
1530f4c0d4aSJamey Sharp     /// ranges within this list that correspond to each basic block's
1540f4c0d4aSJamey Sharp     /// predecessors.
1550f4c0d4aSJamey Sharp     block_preds: Vec<regalloc2::Block>,
156a0318f36SChris Fallin 
157a0318f36SChris Fallin     /// Block parameters: index range in `block_params` below.
1582c409535SJamey Sharp     block_params_range: Ranges,
159a0318f36SChris Fallin 
160a0318f36SChris Fallin     /// Block parameter lists, concatenated into one vec. The
161a0318f36SChris Fallin     /// `block_params_range` list of tuples above gives (start, end)
162a0318f36SChris Fallin     /// ranges within this list that correspond to each basic block's
163a0318f36SChris Fallin     /// blockparam vregs.
164a0318f36SChris Fallin     block_params: Vec<regalloc2::VReg>,
165a0318f36SChris Fallin 
166a0318f36SChris Fallin     /// Outgoing block arguments on branch instructions, concatenated
167a0318f36SChris Fallin     /// into one list.
168a0318f36SChris Fallin     ///
169a0318f36SChris Fallin     /// Note that this is conceptually a 3D array: we have a VReg list
170a0318f36SChris Fallin     /// per block, per successor. We flatten those three dimensions
171a0318f36SChris Fallin     /// into this 1D vec, then store index ranges in two levels of
172a0318f36SChris Fallin     /// indirection.
173a0318f36SChris Fallin     ///
174a0318f36SChris Fallin     /// Indexed by the indices in `branch_block_arg_succ_range`.
175a0318f36SChris Fallin     branch_block_args: Vec<regalloc2::VReg>,
176a0318f36SChris Fallin 
177a0318f36SChris Fallin     /// Array of sequences of (start, end) tuples in
178a0318f36SChris Fallin     /// `branch_block_args`, one for each successor; these sequences
179a0318f36SChris Fallin     /// for each block are concatenated.
180a0318f36SChris Fallin     ///
181a0318f36SChris Fallin     /// Indexed by the indices in `branch_block_arg_succ_range`.
1822c409535SJamey Sharp     branch_block_arg_range: Ranges,
183a0318f36SChris Fallin 
184a0318f36SChris Fallin     /// For a given block, indices in `branch_block_arg_range`
185a0318f36SChris Fallin     /// corresponding to all of its successors.
1862c409535SJamey Sharp     branch_block_arg_succ_range: Ranges,
187a0318f36SChris Fallin 
18872e6be93SChris Fallin     /// Block-order information.
18972e6be93SChris Fallin     block_order: BlockLoweringOrder,
190d8357426SChris Fallin 
191d8357426SChris Fallin     /// ABI object.
1922986f6b0SChris Fallin     pub(crate) abi: Callee<I::ABIMachineSpec>,
19308353fccSChris Fallin 
194c5bbc874SBenjamin Bouvier     /// Constant information used during code emission. This should be
195c5bbc874SBenjamin Bouvier     /// immutable across function compilations within the same module.
196c5bbc874SBenjamin Bouvier     emit_info: I::Info,
197c5bbc874SBenjamin Bouvier 
19883f182b3SAndrew Brown     /// Constants.
1994513d9caSChris Fallin     pub(crate) constants: VCodeConstants,
200997fab55SChris Fallin 
201a0318f36SChris Fallin     /// Value labels for debuginfo attached to vregs.
202a0318f36SChris Fallin     debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>,
203f18a1f14SNick Fitzgerald 
2042986f6b0SChris Fallin     pub(crate) sigs: SigSet,
205f466aa26SChris Fallin 
2062af0a1f7Sbjorn3     log2_min_function_alignment: u8,
207d8357426SChris Fallin }
208d8357426SChris Fallin 
209a0318f36SChris Fallin /// The result of `VCode::emit`. Contains all information computed
210a0318f36SChris Fallin /// during emission: actual machine code, optionally a disassembly,
211a0318f36SChris Fallin /// and optionally metadata about the code layout.
21249dd8fd7SAlex Crichton pub struct EmitResult {
213a0318f36SChris Fallin     /// The MachBuffer containing the machine code.
21449dd8fd7SAlex Crichton     pub buffer: MachBufferFinalized<Stencil>,
215a0318f36SChris Fallin 
216a0318f36SChris Fallin     /// Offset of each basic block, recorded during emission. Computed
2170854775bSbjorn3     /// only if `machine_code_cfg_info` is enabled.
218a0318f36SChris Fallin     pub bb_offsets: Vec<CodeOffset>,
219a0318f36SChris Fallin 
220a0318f36SChris Fallin     /// Final basic-block edges, in terms of code offsets of
2210854775bSbjorn3     /// bb-starts. Computed only if `machine_code_cfg_info` is enabled.
222a0318f36SChris Fallin     pub bb_edges: Vec<(CodeOffset, CodeOffset)>,
223a0318f36SChris Fallin 
224a0318f36SChris Fallin     /// The pretty-printed disassembly, if any. This uses the same
225a0318f36SChris Fallin     /// pretty-printing for MachInsts as the pre-regalloc VCode Debug
226a0318f36SChris Fallin     /// implementation, but additionally includes the prologue and
227a0318f36SChris Fallin     /// epilogue(s), and makes use of the regalloc results.
228a0318f36SChris Fallin     pub disasm: Option<String>,
229a0318f36SChris Fallin 
230a0318f36SChris Fallin     /// Value-labels information (debug metadata).
231a0318f36SChris Fallin     pub value_labels_ranges: ValueLabelsRanges,
232d9d64694SChris Fallin }
233d9d64694SChris Fallin 
234a0318f36SChris Fallin /// A builder for a VCode function body.
235d8357426SChris Fallin ///
236a0318f36SChris Fallin /// This builder has the ability to accept instructions in either
237a0318f36SChris Fallin /// forward or reverse order, depending on the pass direction that
238a0318f36SChris Fallin /// produces the VCode. The lowering from CLIF to VCode<MachInst>
239a0318f36SChris Fallin /// ordinarily occurs in reverse order (in order to allow instructions
240a0318f36SChris Fallin /// to be lowered only if used, and not merged) so a reversal will
241a0318f36SChris Fallin /// occur at the end of lowering to ensure the VCode is in machine
242a0318f36SChris Fallin /// order.
243a0318f36SChris Fallin ///
244a0318f36SChris Fallin /// If built in reverse, block and instruction indices used once the
245a0318f36SChris Fallin /// VCode is built are relative to the final (reversed) order, not the
246a0318f36SChris Fallin /// order of construction. Note that this means we do not know the
247a0318f36SChris Fallin /// final block or instruction indices when building, so we do not
248a0318f36SChris Fallin /// hand them out. (The user is assumed to know them when appending
249a0318f36SChris Fallin /// terminator instructions with successor blocks.)
250d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> {
251d8357426SChris Fallin     /// In-progress VCode.
2522986f6b0SChris Fallin     pub(crate) vcode: VCode<I>,
253d8357426SChris Fallin 
2540e9121daSFrankReh     /// In what direction is the build occurring?
255a0318f36SChris Fallin     direction: VCodeBuildDirection,
25608353fccSChris Fallin 
257a0318f36SChris Fallin     /// Debug-value label in-progress map, keyed by label. For each
258a0318f36SChris Fallin     /// label, we keep disjoint ranges mapping to vregs. We'll flatten
259a0318f36SChris Fallin     /// this into (vreg, range, label) tuples when done.
260a0318f36SChris Fallin     debug_info: FxHashMap<ValueLabel, Vec<(InsnIndex, InsnIndex, VReg)>>,
261a0318f36SChris Fallin }
262a0318f36SChris Fallin 
263a0318f36SChris Fallin /// Direction in which a VCodeBuilder builds VCode.
264a0318f36SChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq)]
265a0318f36SChris Fallin pub enum VCodeBuildDirection {
266a0318f36SChris Fallin     // TODO: add `Forward` once we need it and can test it adequately.
267a0318f36SChris Fallin     /// Backward-build pass: we expect the producer to call `emit()`
268a0318f36SChris Fallin     /// with instructions in reverse program order within each block.
269a0318f36SChris Fallin     Backward,
270d8357426SChris Fallin }
271d8357426SChris Fallin 
272d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> {
273d8357426SChris Fallin     /// Create a new VCodeBuilder.
new( sigs: SigSet, abi: Callee<I::ABIMachineSpec>, emit_info: I::Info, block_order: BlockLoweringOrder, constants: VCodeConstants, direction: VCodeBuildDirection, log2_min_function_alignment: u8, ) -> Self274c5bbc874SBenjamin Bouvier     pub fn new(
275f18a1f14SNick Fitzgerald         sigs: SigSet,
276f0c60f46SNick Fitzgerald         abi: Callee<I::ABIMachineSpec>,
277c5bbc874SBenjamin Bouvier         emit_info: I::Info,
278c5bbc874SBenjamin Bouvier         block_order: BlockLoweringOrder,
27983f182b3SAndrew Brown         constants: VCodeConstants,
280a0318f36SChris Fallin         direction: VCodeBuildDirection,
2812af0a1f7Sbjorn3         log2_min_function_alignment: u8,
282e20b4244SNick Fitzgerald     ) -> Self {
2832af0a1f7Sbjorn3         let vcode = VCode::new(
2842af0a1f7Sbjorn3             sigs,
2852af0a1f7Sbjorn3             abi,
2862af0a1f7Sbjorn3             emit_info,
2872af0a1f7Sbjorn3             block_order,
2882af0a1f7Sbjorn3             constants,
2892af0a1f7Sbjorn3             log2_min_function_alignment,
2902af0a1f7Sbjorn3         );
29108353fccSChris Fallin 
292d8357426SChris Fallin         VCodeBuilder {
293d8357426SChris Fallin             vcode,
294a0318f36SChris Fallin             direction,
295a0318f36SChris Fallin             debug_info: FxHashMap::default(),
296d8357426SChris Fallin         }
297d8357426SChris Fallin     }
298d8357426SChris Fallin 
init_retval_area(&mut self, vregs: &mut VRegAllocator<I>) -> CodegenResult<()>299b6e7cc38SJamey Sharp     pub fn init_retval_area(&mut self, vregs: &mut VRegAllocator<I>) -> CodegenResult<()> {
300b6e7cc38SJamey Sharp         self.vcode.abi.init_retval_area(&self.vcode.sigs, vregs)
301f18a1f14SNick Fitzgerald     }
302f18a1f14SNick Fitzgerald 
303d8357426SChris Fallin     /// Access the ABI object.
abi(&self) -> &Callee<I::ABIMachineSpec>304f18a1f14SNick Fitzgerald     pub fn abi(&self) -> &Callee<I::ABIMachineSpec> {
305f18a1f14SNick Fitzgerald         &self.vcode.abi
306f18a1f14SNick Fitzgerald     }
307f18a1f14SNick Fitzgerald 
308f18a1f14SNick Fitzgerald     /// Access the ABI object.
abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec>309f18a1f14SNick Fitzgerald     pub fn abi_mut(&mut self) -> &mut Callee<I::ABIMachineSpec> {
310f0c60f46SNick Fitzgerald         &mut self.vcode.abi
311d8357426SChris Fallin     }
312d8357426SChris Fallin 
sigs(&self) -> &SigSet313f18a1f14SNick Fitzgerald     pub fn sigs(&self) -> &SigSet {
314f18a1f14SNick Fitzgerald         &self.vcode.sigs
315f18a1f14SNick Fitzgerald     }
316f18a1f14SNick Fitzgerald 
sigs_mut(&mut self) -> &mut SigSet317f18a1f14SNick Fitzgerald     pub fn sigs_mut(&mut self) -> &mut SigSet {
318f18a1f14SNick Fitzgerald         &mut self.vcode.sigs
319f18a1f14SNick Fitzgerald     }
320f18a1f14SNick Fitzgerald 
32172e6be93SChris Fallin     /// Access to the BlockLoweringOrder object.
block_order(&self) -> &BlockLoweringOrder32272e6be93SChris Fallin     pub fn block_order(&self) -> &BlockLoweringOrder {
32372e6be93SChris Fallin         &self.vcode.block_order
3241d90751bSBenjamin Bouvier     }
3251d90751bSBenjamin Bouvier 
326d8357426SChris Fallin     /// Set the current block as the entry block.
set_entry(&mut self, block: BlockIndex)327d8357426SChris Fallin     pub fn set_entry(&mut self, block: BlockIndex) {
328d8357426SChris Fallin         self.vcode.entry = block;
329d8357426SChris Fallin     }
330d8357426SChris Fallin 
331d8357426SChris Fallin     /// End the current basic block. Must be called after emitting vcode insts
332d8357426SChris Fallin     /// for IR insts and prior to ending the function (building the VCode).
end_bb(&mut self)33372e6be93SChris Fallin     pub fn end_bb(&mut self) {
334a0318f36SChris Fallin         let end_idx = self.vcode.insts.len();
335d8357426SChris Fallin         // Add the instruction index range to the list of blocks.
3362c409535SJamey Sharp         self.vcode.block_ranges.push_end(end_idx);
337d8357426SChris Fallin         // End the successors list.
3380f4c0d4aSJamey Sharp         let succ_end = self.vcode.block_succs.len();
3392c409535SJamey Sharp         self.vcode.block_succ_range.push_end(succ_end);
340a0318f36SChris Fallin         // End the blockparams list.
341a0318f36SChris Fallin         let block_params_end = self.vcode.block_params.len();
3422c409535SJamey Sharp         self.vcode.block_params_range.push_end(block_params_end);
343a0318f36SChris Fallin         // End the branch blockparam args list.
344a0318f36SChris Fallin         let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len();
3452c409535SJamey Sharp         self.vcode
3462c409535SJamey Sharp             .branch_block_arg_succ_range
3472c409535SJamey Sharp             .push_end(branch_block_arg_succ_end);
348d8357426SChris Fallin     }
349d8357426SChris Fallin 
add_block_param(&mut self, param: VirtualReg)350d94173eaSTrevor Elliott     pub fn add_block_param(&mut self, param: VirtualReg) {
351a0318f36SChris Fallin         self.vcode.block_params.push(param.into());
352a0318f36SChris Fallin     }
353a0318f36SChris Fallin 
add_branch_args_for_succ(&mut self, args: &[Reg])3545774e068SChris Fallin     fn add_branch_args_for_succ(&mut self, args: &[Reg]) {
355a0318f36SChris Fallin         self.vcode
356a0318f36SChris Fallin             .branch_block_args
357a0318f36SChris Fallin             .extend(args.iter().map(|&arg| VReg::from(arg)));
358a0318f36SChris Fallin         let end = self.vcode.branch_block_args.len();
3592c409535SJamey Sharp         self.vcode.branch_block_arg_range.push_end(end);
360a0318f36SChris Fallin     }
361a0318f36SChris Fallin 
362a0318f36SChris Fallin     /// Push an instruction for the current BB and current IR inst
363a0318f36SChris Fallin     /// within the BB.
push(&mut self, insn: I, loc: RelSourceLoc)3643e878837SJamey Sharp     pub fn push(&mut self, insn: I, loc: RelSourceLoc) {
365392c7a96SChris Fallin         assert!(!insn.is_low_level_branch()); // These are not meant to be in VCode.
36672e6be93SChris Fallin         self.vcode.insts.push(insn);
3673e878837SJamey Sharp         self.vcode.srclocs.push(loc);
36872e6be93SChris Fallin     }
36972e6be93SChris Fallin 
3705774e068SChris Fallin     /// Add a successor block with branch args.
add_succ(&mut self, block: BlockIndex, args: &[Reg])3715774e068SChris Fallin     pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) {
3720f4c0d4aSJamey Sharp         self.vcode.block_succs.push(block);
3735774e068SChris Fallin         self.add_branch_args_for_succ(args);
3745774e068SChris Fallin     }
3755774e068SChris Fallin 
376a0318f36SChris Fallin     /// Add a debug value label to a register.
add_value_label(&mut self, reg: Reg, label: ValueLabel)377a0318f36SChris Fallin     pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) {
3785b63c874SSingleAccretion         // 1) In the reversed order, we consider the instructions
3795b63c874SSingleAccretion         //    that define ranges in the "debug_info" array to refer
3805b63c874SSingleAccretion         //    to the IP **after** them (when reversed):
3815b63c874SSingleAccretion         //      IP[2]__| Inst 3 |
3825b63c874SSingleAccretion         //      IP[1]__| Inst 2 |
3835b63c874SSingleAccretion         //      IP[0]__| Inst 1 |
3845b63c874SSingleAccretion         //             | Inst 0 |
3855b63c874SSingleAccretion         //    This is so that we can represent IP[<function start>],
3865b63c874SSingleAccretion         //    done at the cost of not being to represent IP[<function end>],
3875b63c874SSingleAccretion         //    which is OK since no values will be live at that point.
3885b63c874SSingleAccretion         // 2) The live range for "reg" begins at the current IP
3895b63c874SSingleAccretion         //    and continues until the next, in execution order,
3905b63c874SSingleAccretion         //    VReg that defines "label". Since the ranges are open
3915b63c874SSingleAccretion         //    at the end, the subtraction of 1 cancels out:
3925b63c874SSingleAccretion         //      [last..current IP] <=>
3935b63c874SSingleAccretion         //      [last..last emitted inst index] <=>
3945b63c874SSingleAccretion         //      [last..next_inst_index - 1] <=>
3955b63c874SSingleAccretion         //      [last..next_inst_index)
3965b63c874SSingleAccretion         //
3975b63c874SSingleAccretion         let next_inst_index = self.vcode.insts.len();
3985b63c874SSingleAccretion         if next_inst_index == 0 {
3995b63c874SSingleAccretion             // This would produce a defective [0..0) range.
4005b63c874SSingleAccretion             return;
4015b63c874SSingleAccretion         }
4025b63c874SSingleAccretion         let next_inst = InsnIndex::new(next_inst_index);
403a0318f36SChris Fallin         let labels = self.debug_info.entry(label).or_insert_with(|| vec![]);
404a0318f36SChris Fallin         let last = labels
405a0318f36SChris Fallin             .last()
406a0318f36SChris Fallin             .map(|(_start, end, _vreg)| *end)
407a0318f36SChris Fallin             .unwrap_or(InsnIndex::new(0));
4085b63c874SSingleAccretion         labels.push((last, next_inst, reg.into()));
409a0318f36SChris Fallin     }
410a0318f36SChris Fallin 
41183f182b3SAndrew Brown     /// Access the constants.
constants(&mut self) -> &mut VCodeConstants41283f182b3SAndrew Brown     pub fn constants(&mut self) -> &mut VCodeConstants {
41383f182b3SAndrew Brown         &mut self.vcode.constants
41483f182b3SAndrew Brown     }
41583f182b3SAndrew Brown 
compute_preds_from_succs(&mut self)416a0318f36SChris Fallin     fn compute_preds_from_succs(&mut self) {
4170f4c0d4aSJamey Sharp         // Do a linear-time counting sort: first determine how many
4180f4c0d4aSJamey Sharp         // times each block appears as a successor.
4190f4c0d4aSJamey Sharp         let mut starts = vec![0u32; self.vcode.num_blocks()];
4200f4c0d4aSJamey Sharp         for succ in &self.vcode.block_succs {
4210f4c0d4aSJamey Sharp             starts[succ.index()] += 1;
4220f4c0d4aSJamey Sharp         }
4230f4c0d4aSJamey Sharp 
4240f4c0d4aSJamey Sharp         // Determine for each block the starting index where that
4250f4c0d4aSJamey Sharp         // block's predecessors should go. This is equivalent to the
4260f4c0d4aSJamey Sharp         // ranges we need to store in block_pred_range.
4270f4c0d4aSJamey Sharp         self.vcode.block_pred_range.reserve(starts.len());
4280f4c0d4aSJamey Sharp         let mut end = 0;
4290f4c0d4aSJamey Sharp         for count in starts.iter_mut() {
4300f4c0d4aSJamey Sharp             let start = end;
4310f4c0d4aSJamey Sharp             end += *count;
4320f4c0d4aSJamey Sharp             *count = start;
4332c409535SJamey Sharp             self.vcode.block_pred_range.push_end(end as usize);
4340f4c0d4aSJamey Sharp         }
4350f4c0d4aSJamey Sharp         let end = end as usize;
4360f4c0d4aSJamey Sharp         debug_assert_eq!(end, self.vcode.block_succs.len());
4370f4c0d4aSJamey Sharp 
4380f4c0d4aSJamey Sharp         // Walk over the successors again, this time grouped by
4390f4c0d4aSJamey Sharp         // predecessor, and push the predecessor at the current
4402c409535SJamey Sharp         // starting position of each of its successors. We build
4412c409535SJamey Sharp         // each group of predecessors in whatever order Ranges::iter
4422c409535SJamey Sharp         // returns them; regalloc2 doesn't care.
4430f4c0d4aSJamey Sharp         self.vcode.block_preds.resize(end, BlockIndex::invalid());
4442c409535SJamey Sharp         for (pred, range) in self.vcode.block_succ_range.iter() {
445a0318f36SChris Fallin             let pred = BlockIndex::new(pred);
4462c409535SJamey Sharp             for succ in &self.vcode.block_succs[range] {
4470f4c0d4aSJamey Sharp                 let pos = &mut starts[succ.index()];
4480f4c0d4aSJamey Sharp                 self.vcode.block_preds[*pos as usize] = pred;
4490f4c0d4aSJamey Sharp                 *pos += 1;
450a0318f36SChris Fallin             }
451a0318f36SChris Fallin         }
4520f4c0d4aSJamey Sharp         debug_assert!(self.vcode.block_preds.iter().all(|pred| pred.is_valid()));
453d8357426SChris Fallin     }
454d8357426SChris Fallin 
455a0318f36SChris Fallin     /// Called once, when a build in Backward order is complete, to
456a0318f36SChris Fallin     /// perform the overall reversal (into final forward order) and
457a0318f36SChris Fallin     /// finalize metadata accordingly.
reverse_and_finalize(&mut self, vregs: &VRegAllocator<I>)4583aa32064SJamey Sharp     fn reverse_and_finalize(&mut self, vregs: &VRegAllocator<I>) {
459a0318f36SChris Fallin         let n_insts = self.vcode.insts.len();
460a0318f36SChris Fallin         if n_insts == 0 {
461a0318f36SChris Fallin             return;
462a0318f36SChris Fallin         }
463a0318f36SChris Fallin 
464a0318f36SChris Fallin         // Reverse the per-block and per-inst sequences.
4652c409535SJamey Sharp         self.vcode.block_ranges.reverse_index();
4662c409535SJamey Sharp         self.vcode.block_ranges.reverse_target(n_insts);
467a0318f36SChris Fallin         // block_params_range is indexed by block (and blocks were
468a0318f36SChris Fallin         // traversed in reverse) so we reverse it; but block-param
469a0318f36SChris Fallin         // sequences in the concatenated vec can remain in reverse
470a0318f36SChris Fallin         // order (it is effectively an arena of arbitrarily-placed
471a0318f36SChris Fallin         // referenced sequences).
4722c409535SJamey Sharp         self.vcode.block_params_range.reverse_index();
473a0318f36SChris Fallin         // Likewise, we reverse block_succ_range, but the block_succ
474a0318f36SChris Fallin         // concatenated array can remain as-is.
4752c409535SJamey Sharp         self.vcode.block_succ_range.reverse_index();
476a0318f36SChris Fallin         self.vcode.insts.reverse();
477a0318f36SChris Fallin         self.vcode.srclocs.reverse();
478a0318f36SChris Fallin         // Likewise, branch_block_arg_succ_range is indexed by block
479a0318f36SChris Fallin         // so must be reversed.
4802c409535SJamey Sharp         self.vcode.branch_block_arg_succ_range.reverse_index();
481a0318f36SChris Fallin 
482a0318f36SChris Fallin         // To translate an instruction index *endpoint* in reversed
483a0318f36SChris Fallin         // order to forward order, compute `n_insts - i`.
484a0318f36SChris Fallin         //
485a0318f36SChris Fallin         // Why not `n_insts - 1 - i`? That would be correct to
486a0318f36SChris Fallin         // translate an individual instruction index (for ten insts 0
487a0318f36SChris Fallin         // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes
488a0318f36SChris Fallin         // 0). But for the usual inclusive-start, exclusive-end range
489a0318f36SChris Fallin         // idiom, inclusive starts become exclusive ends and
490a0318f36SChris Fallin         // vice-versa, so e.g. an (inclusive) start of 0 becomes an
491a0318f36SChris Fallin         // (exclusive) end of 10.
492a0318f36SChris Fallin         let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index());
493a0318f36SChris Fallin 
494a0318f36SChris Fallin         // Generate debug-value labels based on per-label maps.
495a0318f36SChris Fallin         for (label, tuples) in &self.debug_info {
496a0318f36SChris Fallin             for &(start, end, vreg) in tuples {
4973aa32064SJamey Sharp                 let vreg = vregs.resolve_vreg_alias(vreg);
498a0318f36SChris Fallin                 let fwd_start = translate(end);
499a0318f36SChris Fallin                 let fwd_end = translate(start);
500a0318f36SChris Fallin                 self.vcode
501a0318f36SChris Fallin                     .debug_value_labels
502a0318f36SChris Fallin                     .push((vreg, fwd_start, fwd_end, label.as_u32()));
503a0318f36SChris Fallin             }
504a0318f36SChris Fallin         }
505a0318f36SChris Fallin 
506a0318f36SChris Fallin         // Now sort debug value labels by VReg, as required
507a0318f36SChris Fallin         // by regalloc2.
508a0318f36SChris Fallin         self.vcode
509a0318f36SChris Fallin             .debug_value_labels
510a0318f36SChris Fallin             .sort_unstable_by_key(|(vreg, _, _, _)| *vreg);
511a0318f36SChris Fallin     }
512a0318f36SChris Fallin 
collect_operands(&mut self, vregs: &VRegAllocator<I>)5133aa32064SJamey Sharp     fn collect_operands(&mut self, vregs: &VRegAllocator<I>) {
5145ded0f4eSUlrich Weigand         let allocatable = PRegSet::from(self.vcode.abi.machine_env());
515d180b907SJamey Sharp         for (i, insn) in self.vcode.insts.iter_mut().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 
527a007e02bSTrevor Elliott             let mut op_collector =
528a007e02bSTrevor Elliott                 OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| {
5293aa32064SJamey Sharp                     vregs.resolve_vreg_alias(vreg)
530a0318f36SChris Fallin                 });
531a0318f36SChris Fallin             insn.get_operands(&mut op_collector);
532a0318f36SChris Fallin             let (ops, clobbers) = op_collector.finish();
5332c409535SJamey Sharp             self.vcode.operand_ranges.push_end(ops);
534a0318f36SChris Fallin 
535b2e28b91SChris Fallin             if clobbers != PRegSet::default() {
536b2e28b91SChris Fallin                 self.vcode.clobbers.insert(InsnIndex::new(i), clobbers);
537a0318f36SChris Fallin             }
538a0318f36SChris Fallin 
539a0318f36SChris Fallin             if let Some((dst, src)) = insn.is_move() {
540fac4a915STrevor Elliott                 // We should never see non-virtual registers present in move
541fac4a915STrevor Elliott                 // instructions.
542fac4a915STrevor Elliott                 assert!(
543fac4a915STrevor Elliott                     src.is_virtual(),
544a0442ea0SHamir Mahal                     "the real register {src:?} was used as the source of a move instruction"
545fac4a915STrevor Elliott                 );
546fac4a915STrevor Elliott                 assert!(
547fac4a915STrevor Elliott                     dst.to_reg().is_virtual(),
548fac4a915STrevor Elliott                     "the real register {:?} was used as the destination of a move instruction",
549fac4a915STrevor Elliott                     dst.to_reg()
550fac4a915STrevor Elliott                 );
551a0318f36SChris Fallin             }
552a0318f36SChris Fallin         }
553a0318f36SChris Fallin 
554a0318f36SChris Fallin         // Translate blockparam args via the vreg aliases table as well.
555a0318f36SChris Fallin         for arg in &mut self.vcode.branch_block_args {
5563aa32064SJamey Sharp             let new_arg = vregs.resolve_vreg_alias(*arg);
5578d022434SBenjamin Bouvier             trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg);
558a0318f36SChris Fallin             *arg = new_arg;
559a0318f36SChris Fallin         }
560a0318f36SChris Fallin     }
561a0318f36SChris Fallin 
562a0318f36SChris Fallin     /// Build the final VCode.
build(mut self, mut vregs: VRegAllocator<I>) -> VCode<I>5633aa32064SJamey Sharp     pub fn build(mut self, mut vregs: VRegAllocator<I>) -> VCode<I> {
5643aa32064SJamey Sharp         self.vcode.vreg_types = take(&mut vregs.vreg_types);
565d94173eaSTrevor Elliott 
566a0318f36SChris Fallin         if self.direction == VCodeBuildDirection::Backward {
5673aa32064SJamey Sharp             self.reverse_and_finalize(&vregs);
568a0318f36SChris Fallin         }
5693aa32064SJamey Sharp         self.collect_operands(&vregs);
5702154c63dSAlex Crichton 
571a0318f36SChris Fallin         self.compute_preds_from_succs();
572a0318f36SChris Fallin         self.vcode.debug_value_labels.sort_unstable();
573d180b907SJamey Sharp 
5743aa32064SJamey Sharp         // At this point, nothing in the vcode should mention any
5753aa32064SJamey Sharp         // VReg which has been aliased. All the appropriate rewriting
5763aa32064SJamey Sharp         // should have happened above. Just to be sure, let's
5773aa32064SJamey Sharp         // double-check each field which has vregs.
5783aa32064SJamey Sharp         // Note: can't easily check vcode.insts, resolved in collect_operands.
5793aa32064SJamey Sharp         // Operands are resolved in collect_operands.
5803aa32064SJamey Sharp         vregs.debug_assert_no_vreg_aliases(self.vcode.operands.iter().map(|op| op.vreg()));
5813aa32064SJamey Sharp         // Currently block params are never aliased to another vreg.
5823aa32064SJamey Sharp         vregs.debug_assert_no_vreg_aliases(self.vcode.block_params.iter().copied());
5833aa32064SJamey Sharp         // Branch block args are resolved in collect_operands.
5843aa32064SJamey Sharp         vregs.debug_assert_no_vreg_aliases(self.vcode.branch_block_args.iter().copied());
5853aa32064SJamey Sharp         // Debug value labels are resolved in reverse_and_finalize.
5863aa32064SJamey Sharp         vregs.debug_assert_no_vreg_aliases(
5873aa32064SJamey Sharp             self.vcode.debug_value_labels.iter().map(|&(vreg, ..)| vreg),
5883aa32064SJamey Sharp         );
5893aa32064SJamey Sharp 
590a0318f36SChris Fallin         self.vcode
591d8357426SChris Fallin     }
592e20b4244SNick Fitzgerald 
593e20b4244SNick Fitzgerald     /// Add a user stack map for the associated instruction.
add_user_stack_map( &mut self, inst: BackwardsInsnIndex, entries: &[ir::UserStackMapEntry], )594e20b4244SNick Fitzgerald     pub fn add_user_stack_map(
595e20b4244SNick Fitzgerald         &mut self,
596e20b4244SNick Fitzgerald         inst: BackwardsInsnIndex,
597e20b4244SNick Fitzgerald         entries: &[ir::UserStackMapEntry],
598e20b4244SNick Fitzgerald     ) {
599e20b4244SNick Fitzgerald         let stack_map = ir::UserStackMap::new(entries, self.vcode.abi.sized_stackslot_offsets());
600e20b4244SNick Fitzgerald         let old_entry = self.vcode.user_stack_maps.insert(inst, stack_map);
601e20b4244SNick Fitzgerald         debug_assert!(old_entry.is_none());
602e20b4244SNick Fitzgerald     }
603a3d6e407SChris Fallin 
604a3d6e407SChris Fallin     /// Add debug tags for the associated instruction.
add_debug_tags(&mut self, inst: BackwardsInsnIndex, entries: &[ir::DebugTag])605a3d6e407SChris Fallin     pub fn add_debug_tags(&mut self, inst: BackwardsInsnIndex, entries: &[ir::DebugTag]) {
606a3d6e407SChris Fallin         let start = u32::try_from(self.vcode.debug_tag_pool.len()).unwrap();
607a3d6e407SChris Fallin         self.vcode.debug_tag_pool.extend(entries.iter().cloned());
608a3d6e407SChris Fallin         let end = u32::try_from(self.vcode.debug_tag_pool.len()).unwrap();
609a3d6e407SChris Fallin         self.vcode.debug_tags.insert(inst, start..end);
610a3d6e407SChris Fallin     }
611d8357426SChris Fallin }
612d8357426SChris Fallin 
613d4a4d4f9SSingleAccretion const NO_INST_OFFSET: CodeOffset = u32::MAX;
614d4a4d4f9SSingleAccretion 
615d8357426SChris Fallin impl<I: VCodeInst> VCode<I> {
616d8357426SChris Fallin     /// New empty VCode.
new( sigs: SigSet, abi: Callee<I::ABIMachineSpec>, emit_info: I::Info, block_order: BlockLoweringOrder, constants: VCodeConstants, log2_min_function_alignment: u8, ) -> Self617c5bbc874SBenjamin Bouvier     fn new(
618f18a1f14SNick Fitzgerald         sigs: SigSet,
619f0c60f46SNick Fitzgerald         abi: Callee<I::ABIMachineSpec>,
620c5bbc874SBenjamin Bouvier         emit_info: I::Info,
621c5bbc874SBenjamin Bouvier         block_order: BlockLoweringOrder,
62283f182b3SAndrew Brown         constants: VCodeConstants,
6232af0a1f7Sbjorn3         log2_min_function_alignment: u8,
624e20b4244SNick Fitzgerald     ) -> Self {
625a0318f36SChris Fallin         let n_blocks = block_order.lowered_order().len();
626d8357426SChris Fallin         VCode {
627f18a1f14SNick Fitzgerald             sigs,
628d8357426SChris Fallin             vreg_types: vec![],
629a0318f36SChris Fallin             insts: Vec::with_capacity(10 * n_blocks),
630e20b4244SNick Fitzgerald             user_stack_maps: FxHashMap::default(),
631a3d6e407SChris Fallin             debug_tags: FxHashMap::default(),
632a3d6e407SChris Fallin             debug_tag_pool: vec![],
633a0318f36SChris Fallin             operands: Vec::with_capacity(30 * n_blocks),
6342c409535SJamey Sharp             operand_ranges: Ranges::with_capacity(10 * n_blocks),
635b2e28b91SChris Fallin             clobbers: FxHashMap::default(),
636a0318f36SChris Fallin             srclocs: Vec::with_capacity(10 * n_blocks),
637a0318f36SChris Fallin             entry: BlockIndex::new(0),
6382c409535SJamey Sharp             block_ranges: Ranges::with_capacity(n_blocks),
6392c409535SJamey Sharp             block_succ_range: Ranges::with_capacity(n_blocks),
6400f4c0d4aSJamey Sharp             block_succs: Vec::with_capacity(n_blocks),
6412c409535SJamey Sharp             block_pred_range: Ranges::default(),
6420f4c0d4aSJamey Sharp             block_preds: Vec::new(),
6432c409535SJamey Sharp             block_params_range: Ranges::with_capacity(n_blocks),
644a0318f36SChris Fallin             block_params: Vec::with_capacity(5 * n_blocks),
645a0318f36SChris Fallin             branch_block_args: Vec::with_capacity(10 * n_blocks),
6462c409535SJamey Sharp             branch_block_arg_range: Ranges::with_capacity(2 * n_blocks),
6472c409535SJamey Sharp             branch_block_arg_succ_range: Ranges::with_capacity(n_blocks),
64872e6be93SChris Fallin             block_order,
649d8357426SChris Fallin             abi,
650c5bbc874SBenjamin Bouvier             emit_info,
65183f182b3SAndrew Brown             constants,
652a0318f36SChris Fallin             debug_value_labels: vec![],
6532af0a1f7Sbjorn3             log2_min_function_alignment,
654d8357426SChris Fallin         }
655d8357426SChris Fallin     }
656d8357426SChris Fallin 
657d8357426SChris Fallin     /// Get the number of blocks. Block indices will be in the range `0 ..
658d8357426SChris Fallin     /// (self.num_blocks() - 1)`.
num_blocks(&self) -> usize659d8357426SChris Fallin     pub fn num_blocks(&self) -> usize {
660d8357426SChris Fallin         self.block_ranges.len()
661d8357426SChris Fallin     }
662d8357426SChris Fallin 
6636fe69d00SNick Fitzgerald     /// The number of lowered instructions.
num_insts(&self) -> usize6646fe69d00SNick Fitzgerald     pub fn num_insts(&self) -> usize {
6656fe69d00SNick Fitzgerald         self.insts.len()
6666fe69d00SNick Fitzgerald     }
6676fe69d00SNick Fitzgerald 
compute_clobbers_and_function_calls( &self, regalloc: &regalloc2::Output, ) -> (Vec<Writable<RealReg>>, FunctionCalls)6683b85d838SPaul Nodet     fn compute_clobbers_and_function_calls(
6693fe9c3c7SPaul Nodet         &self,
6703fe9c3c7SPaul Nodet         regalloc: &regalloc2::Output,
6713b85d838SPaul Nodet     ) -> (Vec<Writable<RealReg>>, FunctionCalls) {
6721a17dfb5SJamey Sharp         let mut clobbered = PRegSet::default();
6733b85d838SPaul Nodet         let mut function_calls = FunctionCalls::None;
674d8357426SChris Fallin 
675a0318f36SChris Fallin         // All moves are included in clobbers.
6761a17dfb5SJamey Sharp         for (_, Edit::Move { to, .. }) in &regalloc.edits {
677a0318f36SChris Fallin             if let Some(preg) = to.as_reg() {
6781a17dfb5SJamey Sharp                 clobbered.add(preg);
679a0318f36SChris Fallin             }
680d8357426SChris Fallin         }
681d8357426SChris Fallin 
6822c409535SJamey Sharp         for (i, range) in self.operand_ranges.iter() {
6832c409535SJamey Sharp             let operands = &self.operands[range.clone()];
6842c409535SJamey Sharp             let allocs = &regalloc.allocs[range];
685a0318f36SChris Fallin             for (operand, alloc) in operands.iter().zip(allocs.iter()) {
6861a17dfb5SJamey Sharp                 if operand.kind() == OperandKind::Def {
687a0318f36SChris Fallin                     if let Some(preg) = alloc.as_reg() {
6881a17dfb5SJamey Sharp                         clobbered.add(preg);
689a0318f36SChris Fallin                     }
69008353fccSChris Fallin                 }
691d8357426SChris Fallin             }
692d8357426SChris Fallin 
6933b85d838SPaul Nodet             function_calls.update(self.insts[i].call_type());
6943fe9c3c7SPaul Nodet 
695a0318f36SChris Fallin             // Also add explicitly-clobbered registers.
696a62b396fSChris Fallin             //
697a62b396fSChris Fallin             // Skip merging this instruction's clobber list if not
698a62b396fSChris Fallin             // "included in clobbers" as per the MachInst. (Some
699a62b396fSChris Fallin             // backends use this to implement ABI specifics; e.g.,
700a62b396fSChris Fallin             // excluding calls of the same ABI as the current function
701a62b396fSChris Fallin             // from clobbers, because by definition everything
702a62b396fSChris Fallin             // clobbered by the call can be clobbered by this function
703a62b396fSChris Fallin             // without saving as well.
704a62b396fSChris Fallin             //
705a62b396fSChris Fallin             // This is important for a particular optimization: when
706a62b396fSChris Fallin             // some registers are "half-clobbered", e.g. vector/float
707a62b396fSChris Fallin             // registers on aarch64, we want them to be seen as
708a62b396fSChris Fallin             // clobbered by regalloc so it avoids carrying values
709a62b396fSChris Fallin             // across calls in these registers but not seen as
710a62b396fSChris Fallin             // clobbered by prologue generation here (because the
711a62b396fSChris Fallin             // actual half-clobber implied by the clobber list fits
712a62b396fSChris Fallin             // within the clobbers that we allow without
713a62b396fSChris Fallin             // clobber-saves).
714a62b396fSChris Fallin             if self.insts[i].is_included_in_clobbers() {
7151a17dfb5SJamey Sharp                 if let Some(&inst_clobbered) = self.clobbers.get(&InsnIndex::new(i)) {
7161a17dfb5SJamey Sharp                     clobbered.union_from(inst_clobbered);
717a0318f36SChris Fallin                 }
718a0318f36SChris Fallin             }
719a62b396fSChris Fallin         }
720d8357426SChris Fallin 
7213fe9c3c7SPaul Nodet         let clobbered_regs = clobbered
7221a17dfb5SJamey Sharp             .into_iter()
7231a17dfb5SJamey Sharp             .map(|preg| Writable::from_reg(RealReg::from(preg)))
7243fe9c3c7SPaul Nodet             .collect();
7253fe9c3c7SPaul Nodet 
7263b85d838SPaul Nodet         (clobbered_regs, function_calls)
727d8357426SChris Fallin     }
728d8357426SChris Fallin 
729a0318f36SChris Fallin     /// Emit the instructions to a `MachBuffer`, containing fixed-up
730a0318f36SChris Fallin     /// code and external reloc/trap/etc. records ready for use. Takes
731a0318f36SChris Fallin     /// the regalloc results as well.
732a0318f36SChris Fallin     ///
733a0318f36SChris Fallin     /// Returns the machine code itself, and optionally metadata
734a0318f36SChris Fallin     /// and/or a disassembly, as an `EmitResult`. The `VCode` itself
735a0318f36SChris Fallin     /// is consumed by the emission process.
emit( mut self, regalloc: &regalloc2::Output, want_disasm: bool, flags: &settings::Flags, ctrl_plane: &mut ControlPlane, ) -> EmitResult where I: VCodeInst,73611a2ef01SChris Fallin     pub fn emit(
737a0318f36SChris Fallin         mut self,
738a0318f36SChris Fallin         regalloc: &regalloc2::Output,
739a0318f36SChris Fallin         want_disasm: bool,
74049dd8fd7SAlex Crichton         flags: &settings::Flags,
7417eb89140SRemo Senekowitsch         ctrl_plane: &mut ControlPlane,
74249dd8fd7SAlex Crichton     ) -> EmitResult
743d8357426SChris Fallin     where
744f18a1f14SNick Fitzgerald         I: VCodeInst,
745d8357426SChris Fallin     {
7462b9fefe8SChris Fallin         let _tt = timing::vcode_emit();
74772e6be93SChris Fallin         let mut buffer = MachBuffer::new();
7482af0a1f7Sbjorn3         buffer.set_log2_min_function_alignment(self.log2_min_function_alignment);
74911a2ef01SChris Fallin         let mut bb_starts: Vec<Option<CodeOffset>> = vec![];
750d8357426SChris Fallin 
75149dd8fd7SAlex Crichton         // The first M MachLabels are reserved for block indices.
752a0318f36SChris Fallin         buffer.reserve_labels_for_blocks(self.num_blocks());
75349dd8fd7SAlex Crichton 
75449dd8fd7SAlex Crichton         // Register all allocated constants with the `MachBuffer` to ensure that
75549dd8fd7SAlex Crichton         // any references to the constants during instructions can be handled
75649dd8fd7SAlex Crichton         // correctly.
75749dd8fd7SAlex Crichton         buffer.register_constants(&self.constants);
758d8357426SChris Fallin 
759ef1b2d2fSChris Fallin         // Construct the final order we emit code in: cold blocks at the end.
760ef1b2d2fSChris Fallin         let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![];
761ef1b2d2fSChris Fallin         let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![];
762ef1b2d2fSChris Fallin         for block in 0..self.num_blocks() {
763a0318f36SChris Fallin             let block = BlockIndex::new(block);
764ef1b2d2fSChris Fallin             if self.block_order.is_cold(block) {
765ef1b2d2fSChris Fallin                 cold_blocks.push(block);
766ef1b2d2fSChris Fallin             } else {
767ef1b2d2fSChris Fallin                 final_order.push(block);
768ef1b2d2fSChris Fallin             }
769ef1b2d2fSChris Fallin         }
770d9d64694SChris Fallin         final_order.extend(cold_blocks.clone());
771ef1b2d2fSChris Fallin 
772a0318f36SChris Fallin         // Compute/save info we need for the prologue: clobbers and
773a0318f36SChris Fallin         // number of spillslots.
774a0318f36SChris Fallin         //
775a0318f36SChris Fallin         // We clone `abi` here because we will mutate it as we
776a0318f36SChris Fallin         // generate the prologue and set other info, but we can't
777a0318f36SChris Fallin         // mutate `VCode`. The info it usually carries prior to
778a0318f36SChris Fallin         // setting clobbers is fairly minimal so this should be
779a0318f36SChris Fallin         // relatively cheap.
7803b85d838SPaul Nodet         let (clobbers, function_calls) = self.compute_clobbers_and_function_calls(regalloc);
7813b85d838SPaul Nodet         self.abi.compute_frame_layout(
7823b85d838SPaul Nodet             &self.sigs,
7833b85d838SPaul Nodet             regalloc.num_spillslots,
7843b85d838SPaul Nodet             clobbers,
7853b85d838SPaul Nodet             function_calls,
7863b85d838SPaul Nodet         );
787a0318f36SChris Fallin 
788ef1b2d2fSChris Fallin         // Emit blocks.
789964c6087SChris Fallin         let mut cur_srcloc = None;
79011a2ef01SChris Fallin         let mut last_offset = None;
791a0318f36SChris Fallin         let mut inst_offsets = vec![];
7920889323aSSSD         let mut state = I::State::new(&self.abi, core::mem::take(ctrl_plane));
793a0318f36SChris Fallin 
794a0318f36SChris Fallin         let mut disasm = String::new();
795a0318f36SChris Fallin 
796a0318f36SChris Fallin         if !self.debug_value_labels.is_empty() {
797d4a4d4f9SSingleAccretion             inst_offsets.resize(self.insts.len(), NO_INST_OFFSET);
798a0318f36SChris Fallin         }
799a0318f36SChris Fallin 
800863659e0SChris Fallin         // Count edits per block ahead of time; this is needed for
801863659e0SChris Fallin         // lookahead island emission. (We could derive it per-block
802863659e0SChris Fallin         // with binary search in the edit list, but it's more
803863659e0SChris Fallin         // efficient to do it in one pass here.)
804863659e0SChris Fallin         let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![];
805863659e0SChris Fallin         let mut edit_idx = 0;
806863659e0SChris Fallin         for block in 0..self.num_blocks() {
8072c409535SJamey Sharp             let end_inst = InsnIndex::new(self.block_ranges.get(block).end);
808863659e0SChris Fallin             let start_edit_idx = edit_idx;
809863659e0SChris Fallin             while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst {
810863659e0SChris Fallin                 edit_idx += 1;
811863659e0SChris Fallin             }
812863659e0SChris Fallin             let end_edit_idx = edit_idx;
813863659e0SChris Fallin             ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32);
814863659e0SChris Fallin         }
815863659e0SChris Fallin 
816d8b29089SAnton Kirilov         let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled();
817475d1ba5SAlex Crichton         let mut bb_padding = match flags.bb_padding_log2_minus_one() {
81849dd8fd7SAlex Crichton             0 => Vec::new(),
81949dd8fd7SAlex Crichton             n => vec![0; 1 << (n - 1)],
82049dd8fd7SAlex Crichton         };
821475d1ba5SAlex Crichton         let mut total_bb_padding = 0;
822d8b29089SAnton Kirilov 
823863659e0SChris Fallin         for (block_order_idx, &block) in final_order.iter().enumerate() {
8248d022434SBenjamin Bouvier             trace!("emitting block {:?}", block);
82560e4a004SAfonso Bordado 
82660e4a004SAfonso Bordado             // Call the new block hook for state
82760e4a004SAfonso Bordado             state.on_new_block();
82860e4a004SAfonso Bordado 
82960e4a004SAfonso Bordado             // Emit NOPs to align the block.
83072e6be93SChris Fallin             let new_offset = I::align_basic_block(buffer.cur_offset());
83172e6be93SChris Fallin             while new_offset > buffer.cur_offset() {
832d8357426SChris Fallin                 // Pad with NOPs up to the aligned block offset.
83372e6be93SChris Fallin                 let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
8347d703191SJamey Sharp                 nop.emit(&mut buffer, &self.emit_info, &mut Default::default());
835d8357426SChris Fallin             }
83672e6be93SChris Fallin             assert_eq!(buffer.cur_offset(), new_offset);
837d8357426SChris Fallin 
838a0318f36SChris Fallin             let do_emit = |inst: &I,
839a0318f36SChris Fallin                            disasm: &mut String,
840a0318f36SChris Fallin                            buffer: &mut MachBuffer<I>,
841a0318f36SChris Fallin                            state: &mut I::State| {
8422986f6b0SChris Fallin                 if want_disasm && !inst.is_args() {
843a0318f36SChris Fallin                     let mut s = state.clone();
8447d703191SJamey Sharp                     writeln!(disasm, "  {}", inst.pretty_print_inst(&mut s)).unwrap();
845a0318f36SChris Fallin                 }
8467d703191SJamey Sharp                 inst.emit(buffer, &self.emit_info, state);
847a0318f36SChris Fallin             };
848a0318f36SChris Fallin 
849a0318f36SChris Fallin             // Is this the first block? Emit the prologue directly if so.
850a0318f36SChris Fallin             if block == self.entry {
8518d022434SBenjamin Bouvier                 trace!(" -> entry block");
8528a9b1a90SBenjamin Bouvier                 buffer.start_srcloc(Default::default());
85386652959SUlrich Weigand                 for inst in &self.abi.gen_prologue() {
8547d703191SJamey Sharp                     do_emit(&inst, &mut disasm, &mut buffer, &mut state);
855a0318f36SChris Fallin                 }
856a0318f36SChris Fallin                 buffer.end_srcloc();
857d9d64694SChris Fallin             }
858d9d64694SChris Fallin 
859a0318f36SChris Fallin             // Now emit the regular block body.
86011a2ef01SChris Fallin 
8617eb89140SRemo Senekowitsch             buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut());
862a0318f36SChris Fallin 
863a0318f36SChris Fallin             if want_disasm {
864a0318f36SChris Fallin                 writeln!(&mut disasm, "block{}:", block.index()).unwrap();
865a0318f36SChris Fallin             }
866a0318f36SChris Fallin 
86749dd8fd7SAlex Crichton             if flags.machine_code_cfg_info() {
86811a2ef01SChris Fallin                 // Track BB starts. If we have backed up due to MachBuffer
86911a2ef01SChris Fallin                 // branch opts, note that the removed blocks were removed.
87011a2ef01SChris Fallin                 let cur_offset = buffer.cur_offset();
87111a2ef01SChris Fallin                 if last_offset.is_some() && cur_offset <= last_offset.unwrap() {
87211a2ef01SChris Fallin                     for i in (0..bb_starts.len()).rev() {
87311a2ef01SChris Fallin                         if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() {
87411a2ef01SChris Fallin                             break;
87511a2ef01SChris Fallin                         }
87611a2ef01SChris Fallin                         bb_starts[i] = None;
87711a2ef01SChris Fallin                     }
87811a2ef01SChris Fallin                 }
87911a2ef01SChris Fallin                 bb_starts.push(Some(cur_offset));
88011a2ef01SChris Fallin                 last_offset = Some(cur_offset);
881800cf25bSChris Fallin             }
88211a2ef01SChris Fallin 
883d8b29089SAnton Kirilov             if let Some(block_start) = I::gen_block_start(
884d8b29089SAnton Kirilov                 self.block_order.is_indirect_branch_target(block),
885d8b29089SAnton Kirilov                 is_forward_edge_cfi_enabled,
886d8b29089SAnton Kirilov             ) {
8877d703191SJamey Sharp                 do_emit(&block_start, &mut disasm, &mut buffer, &mut state);
888d8b29089SAnton Kirilov             }
889d8b29089SAnton Kirilov 
890a0318f36SChris Fallin             for inst_or_edit in regalloc.block_insts_and_edits(&self, block) {
891a0318f36SChris Fallin                 match inst_or_edit {
892a0318f36SChris Fallin                     InstOrEdit::Inst(iix) => {
893a0318f36SChris Fallin                         if !self.debug_value_labels.is_empty() {
894a0318f36SChris Fallin                             // If we need to produce debug info,
895a0318f36SChris Fallin                             // record the offset of each instruction
896a0318f36SChris Fallin                             // so that we can translate value-label
897a0318f36SChris Fallin                             // ranges to machine-code offsets.
898a0318f36SChris Fallin 
899a0318f36SChris Fallin                             // Cold blocks violate monotonicity
900a0318f36SChris Fallin                             // assumptions elsewhere (that
901a0318f36SChris Fallin                             // instructions in inst-index order are in
902a0318f36SChris Fallin                             // order in machine code), so we omit
903a0318f36SChris Fallin                             // their offsets here. Value-label range
904a0318f36SChris Fallin                             // generation below will skip empty ranges
905a0318f36SChris Fallin                             // and ranges with to-offsets of zero.
906a0318f36SChris Fallin                             if !self.block_order.is_cold(block) {
907a0318f36SChris Fallin                                 inst_offsets[iix.index()] = buffer.cur_offset();
908a0318f36SChris Fallin                             }
909a0318f36SChris Fallin                         }
910a0318f36SChris Fallin 
911a0318f36SChris Fallin                         // Update the srcloc at this point in the buffer.
912a0318f36SChris Fallin                         let srcloc = self.srclocs[iix.index()];
913964c6087SChris Fallin                         if cur_srcloc != Some(srcloc) {
914964c6087SChris Fallin                             if cur_srcloc.is_some() {
91572e6be93SChris Fallin                                 buffer.end_srcloc();
916b691770fSChris Fallin                             }
91772e6be93SChris Fallin                             buffer.start_srcloc(srcloc);
918964c6087SChris Fallin                             cur_srcloc = Some(srcloc);
919b691770fSChris Fallin                         }
920b691770fSChris Fallin 
921a0318f36SChris Fallin                         // If this is a safepoint, compute a stack map
922a0318f36SChris Fallin                         // and pass it to the emit state.
923e20b4244SNick Fitzgerald                         let stack_map_disasm = if self.insts[iix.index()].is_safepoint() {
924e20b4244SNick Fitzgerald                             let (user_stack_map, user_stack_map_disasm) = {
925e20b4244SNick Fitzgerald                                 // The `user_stack_maps` is keyed by reverse
926e20b4244SNick Fitzgerald                                 // instruction index, so we must flip the
927e20b4244SNick Fitzgerald                                 // index. We can't put this into a helper method
928e20b4244SNick Fitzgerald                                 // due to borrowck issues because parts of
929e20b4244SNick Fitzgerald                                 // `self` are borrowed mutably elsewhere in this
930e20b4244SNick Fitzgerald                                 // function.
931e20b4244SNick Fitzgerald                                 let index = iix.to_backwards_insn_index(self.num_insts());
932e20b4244SNick Fitzgerald                                 let user_stack_map = self.user_stack_maps.remove(&index);
933a3d6e407SChris Fallin                                 let user_stack_map_disasm = if want_disasm {
934a3d6e407SChris Fallin                                     user_stack_map.as_ref().map(|m| format!("  ; {m:?}"))
935a3d6e407SChris Fallin                                 } else {
936a3d6e407SChris Fallin                                     None
937a3d6e407SChris Fallin                                 };
938e20b4244SNick Fitzgerald                                 (user_stack_map, user_stack_map_disasm)
939e20b4244SNick Fitzgerald                             };
940e20b4244SNick Fitzgerald 
941c0c3a68cSNick Fitzgerald                             state.pre_safepoint(user_stack_map);
942e20b4244SNick Fitzgerald 
943e20b4244SNick Fitzgerald                             user_stack_map_disasm
944e20b4244SNick Fitzgerald                         } else {
945e20b4244SNick Fitzgerald                             None
946e20b4244SNick Fitzgerald                         };
94708353fccSChris Fallin 
948a3d6e407SChris Fallin                         // Place debug tags in the emission buffer
949a3d6e407SChris Fallin                         // either at the offset prior to the
950a3d6e407SChris Fallin                         // instruction or after the instruction,
951a3d6e407SChris Fallin                         // depending on whether this is a call. See
952a3d6e407SChris Fallin                         // the documentation on [`MachDebugTagPos`]
953a3d6e407SChris Fallin                         // for details on why.
954a3d6e407SChris Fallin                         let mut debug_tag_disasm = None;
955a3d6e407SChris Fallin                         let mut place_debug_tags =
956a3d6e407SChris Fallin                             |this: &VCode<I>, pos: MachDebugTagPos, buffer: &mut MachBuffer<I>| {
957a3d6e407SChris Fallin                                 // As above, translate the forward instruction
958a3d6e407SChris Fallin                                 // index to a backward index for the lookup.
959a3d6e407SChris Fallin                                 let debug_tag_range = {
960a3d6e407SChris Fallin                                     let index = iix.to_backwards_insn_index(this.num_insts());
961a3d6e407SChris Fallin                                     this.debug_tags.get(&index)
962a3d6e407SChris Fallin                                 };
963a3d6e407SChris Fallin                                 if let Some(range) = debug_tag_range {
964a3d6e407SChris Fallin                                     let start = usize::try_from(range.start).unwrap();
965a3d6e407SChris Fallin                                     let end = usize::try_from(range.end).unwrap();
966a3d6e407SChris Fallin                                     let tags = &this.debug_tag_pool[start..end];
967a3d6e407SChris Fallin 
968a3d6e407SChris Fallin                                     if want_disasm {
969a3d6e407SChris Fallin                                         debug_tag_disasm =
970a3d6e407SChris Fallin                                             Some(format!("  ; ^-- debug @ {pos:?}: {tags:?}"));
971a3d6e407SChris Fallin                                     }
972a3d6e407SChris Fallin                                     buffer.push_debug_tags(pos, tags);
973a3d6e407SChris Fallin                                 }
974a3d6e407SChris Fallin                             };
975a3d6e407SChris Fallin                         let debug_tag_pos =
976a3d6e407SChris Fallin                             if self.insts[iix.index()].call_type() == CallType::Regular {
977a3d6e407SChris Fallin                                 MachDebugTagPos::Post
978a3d6e407SChris Fallin                             } else {
979a3d6e407SChris Fallin                                 MachDebugTagPos::Pre
980a3d6e407SChris Fallin                             };
981a3d6e407SChris Fallin 
982a3d6e407SChris Fallin                         if debug_tag_pos == MachDebugTagPos::Pre {
983a3d6e407SChris Fallin                             place_debug_tags(&self, debug_tag_pos, &mut buffer);
984a3d6e407SChris Fallin                         }
985a3d6e407SChris Fallin 
986a0318f36SChris Fallin                         // If the instruction we are about to emit is
987a0318f36SChris Fallin                         // a return, place an epilogue at this point
988a0318f36SChris Fallin                         // (and don't emit the return; the actual
989a0318f36SChris Fallin                         // epilogue will contain it).
990a0318f36SChris Fallin                         if self.insts[iix.index()].is_term() == MachTerminator::Ret {
991a3d6e407SChris Fallin                             log::trace!("emitting epilogue");
99286652959SUlrich Weigand                             for inst in self.abi.gen_epilogue() {
9937d703191SJamey Sharp                                 do_emit(&inst, &mut disasm, &mut buffer, &mut state);
994a0318f36SChris Fallin                             }
995c84d6be6SChris Fallin                         } else {
996d48d6102SJamey Sharp                             // Update the operands for this inst using the
997d48d6102SJamey Sharp                             // allocations from the regalloc result.
998d48d6102SJamey Sharp                             let mut allocs = regalloc.inst_allocs(iix).iter();
999d48d6102SJamey Sharp                             self.insts[iix.index()].get_operands(
1000d48d6102SJamey Sharp                                 &mut |reg: &mut Reg, constraint, _kind, _pos| {
1001a62b396fSChris Fallin                                     let alloc =
1002a62b396fSChris Fallin                                         allocs.next().expect("enough allocations for all operands");
1003d48d6102SJamey Sharp 
1004a62b396fSChris Fallin                                     if let Some(alloc) = alloc.as_reg() {
1005a62b396fSChris Fallin                                         let alloc: Reg = alloc.into();
1006d48d6102SJamey Sharp                                         if let OperandConstraint::FixedReg(rreg) = constraint {
1007d48d6102SJamey Sharp                                             debug_assert_eq!(Reg::from(rreg), alloc);
1008d48d6102SJamey Sharp                                         }
1009d48d6102SJamey Sharp                                         *reg = alloc;
1010a62b396fSChris Fallin                                     } else if let Some(alloc) = alloc.as_stack() {
1011a62b396fSChris Fallin                                         let alloc: Reg = alloc.into();
1012a62b396fSChris Fallin                                         *reg = alloc;
1013a62b396fSChris Fallin                                     }
1014d48d6102SJamey Sharp                                 },
1015d48d6102SJamey Sharp                             );
1016d48d6102SJamey Sharp                             debug_assert!(allocs.next().is_none());
1017d48d6102SJamey Sharp 
1018a3d6e407SChris Fallin                             log::trace!("emitting: {:?}", self.insts[iix.index()]);
1019a3d6e407SChris Fallin 
1020a0318f36SChris Fallin                             // Emit the instruction!
1021a0318f36SChris Fallin                             do_emit(
1022a0318f36SChris Fallin                                 &self.insts[iix.index()],
1023a0318f36SChris Fallin                                 &mut disasm,
1024a0318f36SChris Fallin                                 &mut buffer,
1025a0318f36SChris Fallin                                 &mut state,
1026a0318f36SChris Fallin                             );
1027a3d6e407SChris Fallin 
1028a3d6e407SChris Fallin                             if debug_tag_pos == MachDebugTagPos::Post {
1029a3d6e407SChris Fallin                                 place_debug_tags(&self, debug_tag_pos, &mut buffer);
1030a3d6e407SChris Fallin                             }
1031a3d6e407SChris Fallin 
1032e20b4244SNick Fitzgerald                             if let Some(stack_map_disasm) = stack_map_disasm {
1033e20b4244SNick Fitzgerald                                 disasm.push_str(&stack_map_disasm);
1034e20b4244SNick Fitzgerald                                 disasm.push('\n');
1035e20b4244SNick Fitzgerald                             }
1036a3d6e407SChris Fallin                             if let Some(debug_tag_disasm) = debug_tag_disasm {
1037a3d6e407SChris Fallin                                 disasm.push_str(&debug_tag_disasm);
1038a3d6e407SChris Fallin                                 disasm.push('\n');
1039a3d6e407SChris Fallin                             }
1040c84d6be6SChris Fallin                         }
1041c84d6be6SChris Fallin                     }
1042a0318f36SChris Fallin 
1043a0318f36SChris Fallin                     InstOrEdit::Edit(Edit::Move { from, to }) => {
1044a0318f36SChris Fallin                         // Create a move/spill/reload instruction and
1045a0318f36SChris Fallin                         // immediately emit it.
1046a0318f36SChris Fallin                         match (from.as_reg(), to.as_reg()) {
1047a0318f36SChris Fallin                             (Some(from), Some(to)) => {
1048a0318f36SChris Fallin                                 // Reg-to-reg move.
1049a0318f36SChris Fallin                                 let from_rreg = Reg::from(from);
1050a0318f36SChris Fallin                                 let to_rreg = Writable::from_reg(Reg::from(to));
1051a0318f36SChris Fallin                                 debug_assert_eq!(from.class(), to.class());
1052a0318f36SChris Fallin                                 let ty = I::canonical_type_for_rc(from.class());
1053a0318f36SChris Fallin                                 let mv = I::gen_move(to_rreg, from_rreg, ty);
10547d703191SJamey Sharp                                 do_emit(&mv, &mut disasm, &mut buffer, &mut state);
1055a0318f36SChris Fallin                             }
1056a0318f36SChris Fallin                             (Some(from), None) => {
1057a0318f36SChris Fallin                                 // Spill from register to spillslot.
1058a0318f36SChris Fallin                                 let to = to.as_stack().unwrap();
1059a0318f36SChris Fallin                                 let from_rreg = RealReg::from(from);
1060a0318f36SChris Fallin                                 let spill = self.abi.gen_spill(to, from_rreg);
10617d703191SJamey Sharp                                 do_emit(&spill, &mut disasm, &mut buffer, &mut state);
1062a0318f36SChris Fallin                             }
1063a0318f36SChris Fallin                             (None, Some(to)) => {
1064a0318f36SChris Fallin                                 // Load from spillslot to register.
1065a0318f36SChris Fallin                                 let from = from.as_stack().unwrap();
1066a0318f36SChris Fallin                                 let to_rreg = Writable::from_reg(RealReg::from(to));
1067a0318f36SChris Fallin                                 let reload = self.abi.gen_reload(to_rreg, from);
10687d703191SJamey Sharp                                 do_emit(&reload, &mut disasm, &mut buffer, &mut state);
1069a0318f36SChris Fallin                             }
1070a0318f36SChris Fallin                             (None, None) => {
1071a0318f36SChris Fallin                                 panic!("regalloc2 should have eliminated stack-to-stack moves!");
1072a0318f36SChris Fallin                             }
1073a0318f36SChris Fallin                         }
1074a0318f36SChris Fallin                     }
1075c84d6be6SChris Fallin                 }
1076d8357426SChris Fallin             }
1077b691770fSChris Fallin 
1078964c6087SChris Fallin             if cur_srcloc.is_some() {
107972e6be93SChris Fallin                 buffer.end_srcloc();
1080964c6087SChris Fallin                 cur_srcloc = None;
1081b691770fSChris Fallin             }
108272e6be93SChris Fallin 
108349dd8fd7SAlex Crichton             // Do we need an island? Get the worst-case size of the next BB, add
108449dd8fd7SAlex Crichton             // it to the optional padding behind the block, and pass this to the
108549dd8fd7SAlex Crichton             // `MachBuffer` to determine if an island is necessary.
108649dd8fd7SAlex Crichton             let worst_case_next_bb = if block_order_idx < final_order.len() - 1 {
1087863659e0SChris Fallin                 let next_block = final_order[block_order_idx + 1];
10882c409535SJamey Sharp                 let next_block_range = self.block_ranges.get(next_block.index());
10892c409535SJamey Sharp                 let next_block_size = next_block_range.len() as u32;
1090863659e0SChris Fallin                 let next_block_ra_insertions = ra_edits_per_block[next_block.index()];
109149dd8fd7SAlex Crichton                 I::worst_case_size() * (next_block_size + next_block_ra_insertions)
109249dd8fd7SAlex Crichton             } else {
109349dd8fd7SAlex Crichton                 0
109449dd8fd7SAlex Crichton             };
109549dd8fd7SAlex Crichton             let padding = if bb_padding.is_empty() {
109649dd8fd7SAlex Crichton                 0
109749dd8fd7SAlex Crichton             } else {
109849dd8fd7SAlex Crichton                 bb_padding.len() as u32 + I::LabelUse::ALIGN - 1
109949dd8fd7SAlex Crichton             };
110049dd8fd7SAlex Crichton             if buffer.island_needed(padding + worst_case_next_bb) {
1101f8c03d5aSAlex Crichton                 buffer.emit_island(padding + worst_case_next_bb, ctrl_plane);
110272e6be93SChris Fallin             }
110349dd8fd7SAlex Crichton 
110449dd8fd7SAlex Crichton             // Insert padding, if configured, to stress the `MachBuffer`'s
110549dd8fd7SAlex Crichton             // relocation and island calculations.
1106475d1ba5SAlex Crichton             //
1107475d1ba5SAlex Crichton             // Padding can get quite large during fuzzing though so place a
1108475d1ba5SAlex Crichton             // total cap on it where when a per-function threshold is exceeded
1109475d1ba5SAlex Crichton             // the padding is turned back down to zero. This avoids a small-ish
1110475d1ba5SAlex Crichton             // test case generating a GB+ memory footprint in Cranelift for
1111475d1ba5SAlex Crichton             // example.
111249dd8fd7SAlex Crichton             if !bb_padding.is_empty() {
111349dd8fd7SAlex Crichton                 buffer.put_data(&bb_padding);
111449dd8fd7SAlex Crichton                 buffer.align_to(I::LabelUse::ALIGN);
1115475d1ba5SAlex Crichton                 total_bb_padding += bb_padding.len();
1116475d1ba5SAlex Crichton                 if total_bb_padding > (150 << 20) {
1117475d1ba5SAlex Crichton                     bb_padding = Vec::new();
1118475d1ba5SAlex Crichton                 }
111972e6be93SChris Fallin             }
1120d8357426SChris Fallin         }
1121d8357426SChris Fallin 
1122e20b4244SNick Fitzgerald         debug_assert!(
1123e20b4244SNick Fitzgerald             self.user_stack_maps.is_empty(),
1124e20b4244SNick Fitzgerald             "any stack maps should have been consumed by instruction emission, still have: {:#?}",
1125e20b4244SNick Fitzgerald             self.user_stack_maps,
1126e20b4244SNick Fitzgerald         );
1127e20b4244SNick Fitzgerald 
1128d4a4d4f9SSingleAccretion         // Do any optimizations on branches at tail of buffer, as if we had
1129d4a4d4f9SSingleAccretion         // bound one last label.
1130d4a4d4f9SSingleAccretion         buffer.optimize_branches(ctrl_plane);
1131d4a4d4f9SSingleAccretion 
11327eb89140SRemo Senekowitsch         // emission state is not needed anymore, move control plane back out
11337eb89140SRemo Senekowitsch         *ctrl_plane = state.take_ctrl_plane();
11347eb89140SRemo Senekowitsch 
1135a0318f36SChris Fallin         let func_body_len = buffer.cur_offset();
1136de4af90aSYury Delendik 
113711a2ef01SChris Fallin         // Create `bb_edges` and final (filtered) `bb_starts`.
113811a2ef01SChris Fallin         let mut bb_edges = vec![];
1139a0318f36SChris Fallin         let mut bb_offsets = vec![];
114049dd8fd7SAlex Crichton         if flags.machine_code_cfg_info() {
114111a2ef01SChris Fallin             for block in 0..self.num_blocks() {
114211a2ef01SChris Fallin                 if bb_starts[block].is_none() {
114311a2ef01SChris Fallin                     // Block was deleted by MachBuffer; skip.
114411a2ef01SChris Fallin                     continue;
114511a2ef01SChris Fallin                 }
114611a2ef01SChris Fallin                 let from = bb_starts[block].unwrap();
114711a2ef01SChris Fallin 
1148a0318f36SChris Fallin                 bb_offsets.push(from);
114911a2ef01SChris Fallin                 // Resolve each `succ` label and add edges.
1150a0318f36SChris Fallin                 let succs = self.block_succs(BlockIndex::new(block));
1151a0318f36SChris Fallin                 for &succ in succs.iter() {
1152a0318f36SChris Fallin                     let to = buffer.resolve_label_offset(MachLabel::from_block(succ));
115311a2ef01SChris Fallin                     bb_edges.push((from, to));
115411a2ef01SChris Fallin                 }
115511a2ef01SChris Fallin             }
1156800cf25bSChris Fallin         }
115711a2ef01SChris Fallin 
1158d4a4d4f9SSingleAccretion         self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len);
1159a0318f36SChris Fallin         let value_labels_ranges =
1160a0318f36SChris Fallin             self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len);
1161a3d6e407SChris Fallin 
1162a3d6e407SChris Fallin         // Store metadata about frame layout in the MachBuffer.
1163a3d6e407SChris Fallin         buffer.set_frame_layout(self.abi.frame_slot_metadata());
1164a0318f36SChris Fallin 
1165a0318f36SChris Fallin         EmitResult {
116649dd8fd7SAlex Crichton             buffer: buffer.finish(&self.constants, ctrl_plane),
1167a0318f36SChris Fallin             bb_offsets,
1168a0318f36SChris Fallin             bb_edges,
1169a0318f36SChris Fallin             disasm: if want_disasm { Some(disasm) } else { None },
1170a0318f36SChris Fallin             value_labels_ranges,
1171a0318f36SChris Fallin         }
1172d8357426SChris Fallin     }
1173d8357426SChris Fallin 
monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32)1174d4a4d4f9SSingleAccretion     fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) {
1175d4a4d4f9SSingleAccretion         if self.debug_value_labels.is_empty() {
1176d4a4d4f9SSingleAccretion             return;
1177d4a4d4f9SSingleAccretion         }
1178d4a4d4f9SSingleAccretion 
1179d4a4d4f9SSingleAccretion         // During emission, branch removal can make offsets of instructions incorrect.
1180d4a4d4f9SSingleAccretion         // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj]
1181d4a4d4f9SSingleAccretion         // It will be recorded as (say):    [30]  [34]  [38]  [42]  [<would be 46>]
1182d4a4d4f9SSingleAccretion         // When the jumps get removed we are left with (in "inst_offsets"):
1183d4a4d4f9SSingleAccretion         // [insi][jmp0][jmp1][jmp2][insj][...]
1184d4a4d4f9SSingleAccretion         // [30]  [34]  [38]  [42]  [34]
1185d4a4d4f9SSingleAccretion         // Which violates the monotonicity invariant. This method sets offsets of these
1186d4a4d4f9SSingleAccretion         // removed instructions such as to make them appear zero-sized:
1187d4a4d4f9SSingleAccretion         // [insi][jmp0][jmp1][jmp2][insj][...]
1188d4a4d4f9SSingleAccretion         // [30]  [34]  [34]  [34]  [34]
1189d4a4d4f9SSingleAccretion         //
1190d4a4d4f9SSingleAccretion         let mut next_offset = func_body_len;
1191d4a4d4f9SSingleAccretion         for inst_index in (0..(inst_offsets.len() - 1)).rev() {
1192d4a4d4f9SSingleAccretion             let inst_offset = inst_offsets[inst_index];
1193d4a4d4f9SSingleAccretion 
1194d4a4d4f9SSingleAccretion             // Not all instructions get their offsets recorded.
1195d4a4d4f9SSingleAccretion             if inst_offset == NO_INST_OFFSET {
1196d4a4d4f9SSingleAccretion                 continue;
1197d4a4d4f9SSingleAccretion             }
1198d4a4d4f9SSingleAccretion 
1199d4a4d4f9SSingleAccretion             if inst_offset > next_offset {
1200d4a4d4f9SSingleAccretion                 trace!(
1201d4a4d4f9SSingleAccretion                     "Fixing code offset of the removed Inst {}: {} -> {}",
120290ac295eSAlex Crichton                     inst_index, inst_offset, next_offset
1203d4a4d4f9SSingleAccretion                 );
1204d4a4d4f9SSingleAccretion                 inst_offsets[inst_index] = next_offset;
1205d4a4d4f9SSingleAccretion                 continue;
1206d4a4d4f9SSingleAccretion             }
1207d4a4d4f9SSingleAccretion 
1208d4a4d4f9SSingleAccretion             next_offset = inst_offset;
1209d4a4d4f9SSingleAccretion         }
1210d4a4d4f9SSingleAccretion     }
1211d4a4d4f9SSingleAccretion 
compute_value_labels_ranges( &self, regalloc: &regalloc2::Output, inst_offsets: &[CodeOffset], func_body_len: u32, ) -> ValueLabelsRanges1212a0318f36SChris Fallin     fn compute_value_labels_ranges(
1213a0318f36SChris Fallin         &self,
1214a0318f36SChris Fallin         regalloc: &regalloc2::Output,
1215a0318f36SChris Fallin         inst_offsets: &[CodeOffset],
1216a0318f36SChris Fallin         func_body_len: u32,
1217a0318f36SChris Fallin     ) -> ValueLabelsRanges {
1218a0318f36SChris Fallin         if self.debug_value_labels.is_empty() {
1219602006ffSbjorn3             return ValueLabelsRanges::default();
1220997fab55SChris Fallin         }
1221997fab55SChris Fallin 
12223da7fc8eSSingleAccretion         if trace_log_enabled!() {
12233da7fc8eSSingleAccretion             self.log_value_labels_ranges(regalloc, inst_offsets);
12243da7fc8eSSingleAccretion         }
12253da7fc8eSSingleAccretion 
1226a0318f36SChris Fallin         let mut value_labels_ranges: ValueLabelsRanges = HashMap::new();
1227a0318f36SChris Fallin         for &(label, from, to, alloc) in &regalloc.debug_locations {
12283da7fc8eSSingleAccretion             let label = ValueLabel::from_u32(label);
12293da7fc8eSSingleAccretion             let ranges = value_labels_ranges.entry(label).or_insert_with(|| vec![]);
12305b63c874SSingleAccretion             let prog_point_to_inst = |prog_point: ProgPoint| {
12315b63c874SSingleAccretion                 let mut inst = prog_point.inst();
12325b63c874SSingleAccretion                 if prog_point.pos() == InstPosition::After {
12335b63c874SSingleAccretion                     inst = inst.next();
12345b63c874SSingleAccretion                 }
12355b63c874SSingleAccretion                 inst.index()
12365b63c874SSingleAccretion             };
12379fe4cc18SPhilip Craig             let inst_to_offset = |inst_index: usize| {
12389fe4cc18SPhilip Craig                 // Skip over cold blocks.
12399fe4cc18SPhilip Craig                 for offset in &inst_offsets[inst_index..] {
12409fe4cc18SPhilip Craig                     if *offset != NO_INST_OFFSET {
12419fe4cc18SPhilip Craig                         return *offset;
12429fe4cc18SPhilip Craig                     }
12439fe4cc18SPhilip Craig                 }
12449fe4cc18SPhilip Craig                 func_body_len
12459fe4cc18SPhilip Craig             };
12465b63c874SSingleAccretion             let from_inst_index = prog_point_to_inst(from);
12475b63c874SSingleAccretion             let to_inst_index = prog_point_to_inst(to);
12489fe4cc18SPhilip Craig             let from_offset = inst_to_offset(from_inst_index);
12499fe4cc18SPhilip Craig             let to_offset = inst_to_offset(to_inst_index);
1250a0318f36SChris Fallin 
1251d4a4d4f9SSingleAccretion             // Empty ranges or unavailable offsets can happen
1252d4a4d4f9SSingleAccretion             // due to cold blocks and branch removal (see above).
12539fe4cc18SPhilip Craig             if from_offset == to_offset {
1254a0318f36SChris Fallin                 continue;
125576d61504Sbjorn3             }
125676d61504Sbjorn3 
1257a0318f36SChris Fallin             let loc = if let Some(preg) = alloc.as_reg() {
1258a0318f36SChris Fallin                 LabelValueLoc::Reg(Reg::from(preg))
1259a0318f36SChris Fallin             } else {
126076911c29SSSD                 #[cfg(not(feature = "unwind"))]
126176911c29SSSD                 continue;
126276911c29SSSD 
126376911c29SSSD                 #[cfg(feature = "unwind")]
126476911c29SSSD                 {
12657b16eccdSSingleAccretion                     let slot = alloc.as_stack().unwrap();
126661d0b319STrevor Elliott                     let slot_offset = self.abi.get_spillslot_offset(slot);
126761d0b319STrevor Elliott                     let slot_base_to_caller_sp_offset = self.abi.slot_base_to_caller_sp_offset();
12687b16eccdSSingleAccretion                     let caller_sp_to_cfa_offset =
12697b16eccdSSingleAccretion                         crate::isa::unwind::systemv::caller_sp_to_cfa_offset();
127061d0b319STrevor Elliott                     // NOTE: this is a negative offset because it's relative to the caller's SP
127161d0b319STrevor Elliott                     let cfa_to_sp_offset =
127261d0b319STrevor Elliott                         -((slot_base_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64);
127361d0b319STrevor Elliott                     LabelValueLoc::CFAOffset(cfa_to_sp_offset + slot_offset)
127476911c29SSSD                 }
1275a0318f36SChris Fallin             };
1276a0318f36SChris Fallin 
12777b16eccdSSingleAccretion             // Coalesce adjacent ranges that for the same location
12787b16eccdSSingleAccretion             // to minimize output size here and for the consumers.
12797b16eccdSSingleAccretion             if let Some(last_loc_range) = ranges.last_mut() {
12805b63c874SSingleAccretion                 if last_loc_range.loc == loc && last_loc_range.end == from_offset {
12817b16eccdSSingleAccretion                     trace!(
12825b63c874SSingleAccretion                         "Extending debug range for {:?} in {:?} to Inst {} ({})",
128390ac295eSAlex Crichton                         label, loc, to_inst_index, to_offset
12847b16eccdSSingleAccretion                     );
12855b63c874SSingleAccretion                     last_loc_range.end = to_offset;
12867b16eccdSSingleAccretion                     continue;
12877b16eccdSSingleAccretion                 }
12887b16eccdSSingleAccretion             }
12897b16eccdSSingleAccretion 
1290d4a4d4f9SSingleAccretion             trace!(
12913da7fc8eSSingleAccretion                 "Recording debug range for {:?} in {:?}: [Inst {}..Inst {}) [{}..{})",
129290ac295eSAlex Crichton                 label, loc, from_inst_index, to_inst_index, from_offset, to_offset
1293d4a4d4f9SSingleAccretion             );
1294d4a4d4f9SSingleAccretion 
12955b63c874SSingleAccretion             ranges.push(ValueLocRange {
12965b63c874SSingleAccretion                 loc,
12975b63c874SSingleAccretion                 start: from_offset,
12985b63c874SSingleAccretion                 end: to_offset,
12995b63c874SSingleAccretion             });
1300a0318f36SChris Fallin         }
1301a0318f36SChris Fallin 
1302a0318f36SChris Fallin         value_labels_ranges
1303c84d6be6SChris Fallin     }
1304c84d6be6SChris Fallin 
log_value_labels_ranges(&self, regalloc: &regalloc2::Output, inst_offsets: &[CodeOffset])13053da7fc8eSSingleAccretion     fn log_value_labels_ranges(&self, regalloc: &regalloc2::Output, inst_offsets: &[CodeOffset]) {
13063da7fc8eSSingleAccretion         debug_assert!(trace_log_enabled!());
13073da7fc8eSSingleAccretion 
13083da7fc8eSSingleAccretion         // What debug labels do we have? Note we'll skip those that have not been
13093da7fc8eSSingleAccretion         // allocated any location at all. They will show up as numeric gaps in the table.
13103da7fc8eSSingleAccretion         let mut labels = vec![];
13113da7fc8eSSingleAccretion         for &(label, _, _, _) in &regalloc.debug_locations {
13123da7fc8eSSingleAccretion             if Some(&label) == labels.last() {
13133da7fc8eSSingleAccretion                 continue;
13143da7fc8eSSingleAccretion             }
13153da7fc8eSSingleAccretion             labels.push(label);
13163da7fc8eSSingleAccretion         }
13173da7fc8eSSingleAccretion 
13183da7fc8eSSingleAccretion         // Reformat the data on what VRegs were the VLs assigned to by lowering, since
13193da7fc8eSSingleAccretion         // the array we have is sorted by VReg, and we want it sorted by VL for easy
13203da7fc8eSSingleAccretion         // access in the loop below.
13213da7fc8eSSingleAccretion         let mut vregs = vec![];
13223da7fc8eSSingleAccretion         for &(vreg, start, end, label) in &self.debug_value_labels {
13233da7fc8eSSingleAccretion             if matches!(labels.binary_search(&label), Ok(_)) {
13243da7fc8eSSingleAccretion                 vregs.push((label, start, end, vreg));
13253da7fc8eSSingleAccretion             }
13263da7fc8eSSingleAccretion         }
13273da7fc8eSSingleAccretion         vregs.sort_unstable_by(
13283da7fc8eSSingleAccretion             |(l_label, l_start, _, _), (r_label, r_start, _, _)| match l_label.cmp(r_label) {
13293da7fc8eSSingleAccretion                 Ordering::Equal => l_start.cmp(r_start),
13303da7fc8eSSingleAccretion                 cmp => cmp,
13313da7fc8eSSingleAccretion             },
13323da7fc8eSSingleAccretion         );
13333da7fc8eSSingleAccretion 
13343da7fc8eSSingleAccretion         #[derive(PartialEq)]
13353da7fc8eSSingleAccretion         enum Mode {
13363da7fc8eSSingleAccretion             Measure,
13373da7fc8eSSingleAccretion             Emit,
13383da7fc8eSSingleAccretion         }
13393da7fc8eSSingleAccretion         #[derive(PartialEq)]
13403da7fc8eSSingleAccretion         enum Row {
13413da7fc8eSSingleAccretion             Head,
13423da7fc8eSSingleAccretion             Line,
13435b63c874SSingleAccretion             Inst(usize, usize),
13443da7fc8eSSingleAccretion         }
13453da7fc8eSSingleAccretion 
13465b63c874SSingleAccretion         let mut widths = vec![0; 3 + 2 * labels.len()];
13473da7fc8eSSingleAccretion         let mut row = String::new();
13483da7fc8eSSingleAccretion         let mut output_row = |row_kind: Row, mode: Mode| {
13493da7fc8eSSingleAccretion             let mut column_index = 0;
13503da7fc8eSSingleAccretion             row.clear();
13513da7fc8eSSingleAccretion 
13523da7fc8eSSingleAccretion             macro_rules! output_cell_impl {
13533da7fc8eSSingleAccretion                 ($fill:literal, $span:literal, $($cell_fmt:tt)*) => {
13543da7fc8eSSingleAccretion                     let column_start = row.len();
13553da7fc8eSSingleAccretion                     {
13563da7fc8eSSingleAccretion                         row.push('|');
13573da7fc8eSSingleAccretion                         write!(row, $($cell_fmt)*).unwrap();
13583da7fc8eSSingleAccretion                     }
13593da7fc8eSSingleAccretion 
13603da7fc8eSSingleAccretion                     let next_column_index = column_index + $span;
13613da7fc8eSSingleAccretion                     let expected_width: usize = widths[column_index..next_column_index].iter().sum();
13623da7fc8eSSingleAccretion                     if mode == Mode::Measure {
13633da7fc8eSSingleAccretion                         let actual_width = row.len() - column_start;
13643da7fc8eSSingleAccretion                         if actual_width > expected_width {
13653da7fc8eSSingleAccretion                             widths[next_column_index - 1] += actual_width - expected_width;
13663da7fc8eSSingleAccretion                         }
13673da7fc8eSSingleAccretion                     } else {
13683da7fc8eSSingleAccretion                         let column_end = column_start + expected_width;
13693da7fc8eSSingleAccretion                         while row.len() != column_end {
13703da7fc8eSSingleAccretion                             row.push($fill);
13713da7fc8eSSingleAccretion                         }
13723da7fc8eSSingleAccretion                     }
13733da7fc8eSSingleAccretion                     column_index = next_column_index;
13743da7fc8eSSingleAccretion                 };
13753da7fc8eSSingleAccretion             }
13763da7fc8eSSingleAccretion             macro_rules! output_cell {
13773da7fc8eSSingleAccretion                 ($($cell_fmt:tt)*) => {
13783da7fc8eSSingleAccretion                     output_cell_impl!(' ', 1, $($cell_fmt)*);
13793da7fc8eSSingleAccretion                 };
13803da7fc8eSSingleAccretion             }
13813da7fc8eSSingleAccretion 
13823da7fc8eSSingleAccretion             match row_kind {
13833da7fc8eSSingleAccretion                 Row::Head => {
13845b63c874SSingleAccretion                     output_cell!("BB");
13853da7fc8eSSingleAccretion                     output_cell!("Inst");
13863da7fc8eSSingleAccretion                     output_cell!("IP");
13873da7fc8eSSingleAccretion                     for label in &labels {
13883da7fc8eSSingleAccretion                         output_cell_impl!(' ', 2, "{:?}", ValueLabel::from_u32(*label));
13893da7fc8eSSingleAccretion                     }
13903da7fc8eSSingleAccretion                 }
13913da7fc8eSSingleAccretion                 Row::Line => {
13923da7fc8eSSingleAccretion                     debug_assert!(mode == Mode::Emit);
13935b63c874SSingleAccretion                     for _ in 0..3 {
13943da7fc8eSSingleAccretion                         output_cell_impl!('-', 1, "");
13955b63c874SSingleAccretion                     }
13963da7fc8eSSingleAccretion                     for _ in &labels {
13973da7fc8eSSingleAccretion                         output_cell_impl!('-', 2, "");
13983da7fc8eSSingleAccretion                     }
13993da7fc8eSSingleAccretion                 }
14005b63c874SSingleAccretion                 Row::Inst(block_index, inst_index) => {
14015b63c874SSingleAccretion                     debug_assert!(inst_index < self.num_insts());
14025b63c874SSingleAccretion                     if self.block_ranges.get(block_index).start == inst_index {
14035b63c874SSingleAccretion                         output_cell!("B{}", block_index);
14045b63c874SSingleAccretion                     } else {
14055b63c874SSingleAccretion                         output_cell!("");
14065b63c874SSingleAccretion                     }
14073da7fc8eSSingleAccretion                     output_cell!("Inst {inst_index} ");
14083da7fc8eSSingleAccretion                     output_cell!("{} ", inst_offsets[inst_index]);
14093da7fc8eSSingleAccretion 
14103da7fc8eSSingleAccretion                     for label in &labels {
14113da7fc8eSSingleAccretion                         // First, the VReg.
14123da7fc8eSSingleAccretion                         use regalloc2::Inst;
14133da7fc8eSSingleAccretion                         let vreg_cmp = |inst: usize,
14143da7fc8eSSingleAccretion                                         vreg_label: &u32,
14153da7fc8eSSingleAccretion                                         range_start: &Inst,
14163da7fc8eSSingleAccretion                                         range_end: &Inst| {
14173da7fc8eSSingleAccretion                             match vreg_label.cmp(&label) {
14183da7fc8eSSingleAccretion                                 Ordering::Equal => {
14193da7fc8eSSingleAccretion                                     if range_end.index() <= inst {
14203da7fc8eSSingleAccretion                                         Ordering::Less
14213da7fc8eSSingleAccretion                                     } else if range_start.index() > inst {
14223da7fc8eSSingleAccretion                                         Ordering::Greater
14233da7fc8eSSingleAccretion                                     } else {
14243da7fc8eSSingleAccretion                                         Ordering::Equal
14253da7fc8eSSingleAccretion                                     }
14263da7fc8eSSingleAccretion                                 }
14273da7fc8eSSingleAccretion                                 cmp => cmp,
14283da7fc8eSSingleAccretion                             }
14293da7fc8eSSingleAccretion                         };
14303da7fc8eSSingleAccretion                         let vreg_index =
14315b63c874SSingleAccretion                             vregs.binary_search_by(|(l, s, e, _)| vreg_cmp(inst_index, l, s, e));
14323da7fc8eSSingleAccretion                         if let Ok(vreg_index) = vreg_index {
14333da7fc8eSSingleAccretion                             let mut prev_vreg = None;
14345b63c874SSingleAccretion                             if inst_index > 0 {
14353da7fc8eSSingleAccretion                                 let prev_vreg_index = vregs.binary_search_by(|(l, s, e, _)| {
14365b63c874SSingleAccretion                                     vreg_cmp(inst_index - 1, l, s, e)
14373da7fc8eSSingleAccretion                                 });
14383da7fc8eSSingleAccretion                                 if let Ok(prev_vreg_index) = prev_vreg_index {
14393da7fc8eSSingleAccretion                                     prev_vreg = Some(vregs[prev_vreg_index].3);
14403da7fc8eSSingleAccretion                                 }
14413da7fc8eSSingleAccretion                             }
14423da7fc8eSSingleAccretion 
14433da7fc8eSSingleAccretion                             let vreg = vregs[vreg_index].3;
14443da7fc8eSSingleAccretion                             if Some(vreg) == prev_vreg {
14453da7fc8eSSingleAccretion                                 output_cell!("*");
14463da7fc8eSSingleAccretion                             } else {
14473da7fc8eSSingleAccretion                                 output_cell!("{}", vreg);
14483da7fc8eSSingleAccretion                             }
14493da7fc8eSSingleAccretion                         } else {
14503da7fc8eSSingleAccretion                             output_cell!("");
14513da7fc8eSSingleAccretion                         }
14523da7fc8eSSingleAccretion 
14533da7fc8eSSingleAccretion                         // Second, the allocated location.
14545b63c874SSingleAccretion                         let inst_prog_point = ProgPoint::before(Inst::new(inst_index));
14553da7fc8eSSingleAccretion                         let range_index = regalloc.debug_locations.binary_search_by(
14563da7fc8eSSingleAccretion                             |(range_label, range_start, range_end, _)| match range_label.cmp(label)
14573da7fc8eSSingleAccretion                             {
14583da7fc8eSSingleAccretion                                 Ordering::Equal => {
14595b63c874SSingleAccretion                                     if *range_end <= inst_prog_point {
14603da7fc8eSSingleAccretion                                         Ordering::Less
14615b63c874SSingleAccretion                                     } else if *range_start > inst_prog_point {
14623da7fc8eSSingleAccretion                                         Ordering::Greater
14633da7fc8eSSingleAccretion                                     } else {
14643da7fc8eSSingleAccretion                                         Ordering::Equal
14653da7fc8eSSingleAccretion                                     }
14663da7fc8eSSingleAccretion                                 }
14673da7fc8eSSingleAccretion                                 cmp => cmp,
14683da7fc8eSSingleAccretion                             },
14693da7fc8eSSingleAccretion                         );
14703da7fc8eSSingleAccretion                         if let Ok(range_index) = range_index {
14713da7fc8eSSingleAccretion                             // Live at this instruction, print the location.
14723da7fc8eSSingleAccretion                             if let Some(reg) = regalloc.debug_locations[range_index].3.as_reg() {
14733da7fc8eSSingleAccretion                                 output_cell!("{:?}", Reg::from(reg));
14743da7fc8eSSingleAccretion                             } else {
14753da7fc8eSSingleAccretion                                 output_cell!("Stk");
14763da7fc8eSSingleAccretion                             }
14773da7fc8eSSingleAccretion                         } else {
14783da7fc8eSSingleAccretion                             // Not live at this instruction.
14793da7fc8eSSingleAccretion                             output_cell!("");
14803da7fc8eSSingleAccretion                         }
14813da7fc8eSSingleAccretion                     }
14823da7fc8eSSingleAccretion                 }
14833da7fc8eSSingleAccretion             }
14843da7fc8eSSingleAccretion             row.push('|');
14853da7fc8eSSingleAccretion 
14863da7fc8eSSingleAccretion             if mode == Mode::Emit {
14873da7fc8eSSingleAccretion                 trace!("{}", row.as_str());
14883da7fc8eSSingleAccretion             }
14893da7fc8eSSingleAccretion         };
14903da7fc8eSSingleAccretion 
14915b63c874SSingleAccretion         for block_index in 0..self.num_blocks() {
14925b63c874SSingleAccretion             for inst_index in self.block_ranges.get(block_index) {
14935b63c874SSingleAccretion                 output_row(Row::Inst(block_index, inst_index), Mode::Measure);
14945b63c874SSingleAccretion             }
14953da7fc8eSSingleAccretion         }
14963da7fc8eSSingleAccretion         output_row(Row::Head, Mode::Measure);
14973da7fc8eSSingleAccretion 
14983da7fc8eSSingleAccretion         output_row(Row::Head, Mode::Emit);
14993da7fc8eSSingleAccretion         output_row(Row::Line, Mode::Emit);
15005b63c874SSingleAccretion         for block_index in 0..self.num_blocks() {
15015b63c874SSingleAccretion             for inst_index in self.block_ranges.get(block_index) {
15025b63c874SSingleAccretion                 output_row(Row::Inst(block_index, inst_index), Mode::Emit);
15035b63c874SSingleAccretion             }
15043da7fc8eSSingleAccretion         }
15053da7fc8eSSingleAccretion     }
15063da7fc8eSSingleAccretion 
1507d8357426SChris Fallin     /// Get the IR block for a BlockIndex, if one exists.
bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block>1508d8357426SChris Fallin     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
1509a0318f36SChris Fallin         self.block_order.lowered_order()[block.index()].orig_block()
1510d8357426SChris Fallin     }
15112154c63dSAlex Crichton 
1512e20b4244SNick Fitzgerald     /// Get the user stack map associated with the given forward instruction index.
get_user_stack_map(&self, inst: InsnIndex) -> Option<&ir::UserStackMap>1513e20b4244SNick Fitzgerald     pub fn get_user_stack_map(&self, inst: InsnIndex) -> Option<&ir::UserStackMap> {
1514e20b4244SNick Fitzgerald         let index = inst.to_backwards_insn_index(self.num_insts());
1515e20b4244SNick Fitzgerald         self.user_stack_maps.get(&index)
1516e20b4244SNick Fitzgerald     }
1517f466aa26SChris Fallin }
1518f466aa26SChris Fallin 
15190889323aSSSD impl<I: VCodeInst> core::ops::Index<InsnIndex> for VCode<I> {
1520f466aa26SChris Fallin     type Output = I;
index(&self, idx: InsnIndex) -> &Self::Output1521f466aa26SChris Fallin     fn index(&self, idx: InsnIndex) -> &Self::Output {
1522f466aa26SChris Fallin         &self.insts[idx.index()]
1523f466aa26SChris Fallin     }
1524d8357426SChris Fallin }
1525d8357426SChris Fallin 
1526d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> {
num_insts(&self) -> usize1527a0318f36SChris Fallin     fn num_insts(&self) -> usize {
1528a0318f36SChris Fallin         self.insts.len()
1529d8357426SChris Fallin     }
1530d8357426SChris Fallin 
num_blocks(&self) -> usize1531a0318f36SChris Fallin     fn num_blocks(&self) -> usize {
1532a0318f36SChris Fallin         self.block_ranges.len()
1533d8357426SChris Fallin     }
1534d8357426SChris Fallin 
entry_block(&self) -> BlockIndex1535a0318f36SChris Fallin     fn entry_block(&self) -> BlockIndex {
1536a0318f36SChris Fallin         self.entry
1537d8357426SChris Fallin     }
1538d8357426SChris Fallin 
block_insns(&self, block: BlockIndex) -> InstRange1539a0318f36SChris Fallin     fn block_insns(&self, block: BlockIndex) -> InstRange {
15402c409535SJamey Sharp         let range = self.block_ranges.get(block.index());
15411854929dSTrevor Elliott         InstRange::new(InsnIndex::new(range.start), InsnIndex::new(range.end))
1542d8357426SChris Fallin     }
1543d8357426SChris Fallin 
block_succs(&self, block: BlockIndex) -> &[BlockIndex]1544a0318f36SChris Fallin     fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] {
15452c409535SJamey Sharp         let range = self.block_succ_range.get(block.index());
15462c409535SJamey Sharp         &self.block_succs[range]
1547d8357426SChris Fallin     }
1548d8357426SChris Fallin 
block_preds(&self, block: BlockIndex) -> &[BlockIndex]1549a0318f36SChris Fallin     fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] {
15502c409535SJamey Sharp         let range = self.block_pred_range.get(block.index());
15512c409535SJamey Sharp         &self.block_preds[range]
1552d8357426SChris Fallin     }
1553d8357426SChris Fallin 
block_params(&self, block: BlockIndex) -> &[VReg]1554a0318f36SChris Fallin     fn block_params(&self, block: BlockIndex) -> &[VReg] {
1555c5379051STrevor Elliott         // As a special case we don't return block params for the entry block, as all the arguments
1556c5379051STrevor Elliott         // will be defined by the `Inst::Args` instruction.
1557c5379051STrevor Elliott         if block == self.entry {
1558c5379051STrevor Elliott             return &[];
1559c5379051STrevor Elliott         }
1560c5379051STrevor Elliott 
15612c409535SJamey Sharp         let range = self.block_params_range.get(block.index());
15622c409535SJamey Sharp         &self.block_params[range]
1563d8357426SChris Fallin     }
1564d8357426SChris Fallin 
branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg]1565a0318f36SChris Fallin     fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] {
15662c409535SJamey Sharp         let succ_range = self.branch_block_arg_succ_range.get(block.index());
15672c409535SJamey Sharp         debug_assert!(succ_idx < succ_range.len());
15682c409535SJamey Sharp         let branch_block_args = self.branch_block_arg_range.get(succ_range.start + succ_idx);
15692c409535SJamey Sharp         &self.branch_block_args[branch_block_args]
1570d8357426SChris Fallin     }
1571d8357426SChris Fallin 
is_ret(&self, insn: InsnIndex) -> bool1572a0318f36SChris Fallin     fn is_ret(&self, insn: InsnIndex) -> bool {
1573a0318f36SChris Fallin         match self.insts[insn.index()].is_term() {
1574c5379051STrevor Elliott             // We treat blocks terminated by an unconditional trap like a return for regalloc.
1575c5379051STrevor Elliott             MachTerminator::None => self.insts[insn.index()].is_trap(),
15764154fa47SNick Fitzgerald             MachTerminator::Ret | MachTerminator::RetCall => true,
157794ec88eaSChris Fallin             MachTerminator::Branch => false,
1578d8357426SChris Fallin         }
1579d8357426SChris Fallin     }
1580d8357426SChris Fallin 
is_branch(&self, insn: InsnIndex) -> bool1581a0318f36SChris Fallin     fn is_branch(&self, insn: InsnIndex) -> bool {
1582a0318f36SChris Fallin         match self.insts[insn.index()].is_term() {
158394ec88eaSChris Fallin             MachTerminator::Branch => true,
1584a0318f36SChris Fallin             _ => false,
1585a0318f36SChris Fallin         }
158671768bb6SChris Fallin     }
158771768bb6SChris Fallin 
inst_operands(&self, insn: InsnIndex) -> &[Operand]1588a0318f36SChris Fallin     fn inst_operands(&self, insn: InsnIndex) -> &[Operand] {
15892c409535SJamey Sharp         let range = self.operand_ranges.get(insn.index());
15902c409535SJamey Sharp         &self.operands[range]
1591d8357426SChris Fallin     }
1592d8357426SChris Fallin 
inst_clobbers(&self, insn: InsnIndex) -> PRegSet1593b2e28b91SChris Fallin     fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet {
1594b2e28b91SChris Fallin         self.clobbers.get(&insn).cloned().unwrap_or_default()
1595be6f060aSChris Fallin     }
1596be6f060aSChris Fallin 
num_vregs(&self) -> usize1597a0318f36SChris Fallin     fn num_vregs(&self) -> usize {
1598b1307638SJamey Sharp         self.vreg_types.len()
1599d8357426SChris Fallin     }
1600d8357426SChris Fallin 
debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)]1601a0318f36SChris Fallin     fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] {
16023aa32064SJamey Sharp         &self.debug_value_labels
1603d8357426SChris Fallin     }
1604d8357426SChris Fallin 
spillslot_size(&self, regclass: RegClass) -> usize1605a0318f36SChris Fallin     fn spillslot_size(&self, regclass: RegClass) -> usize {
1606a0318f36SChris Fallin         self.abi.get_spillslot_size(regclass) as usize
1607d8357426SChris Fallin     }
1608d8357426SChris Fallin 
allow_multiple_vreg_defs(&self) -> bool1609a0318f36SChris Fallin     fn allow_multiple_vreg_defs(&self) -> bool {
1610a0318f36SChris Fallin         // At least the s390x backend requires this, because the
1611a0318f36SChris Fallin         // `Loop` pseudo-instruction aggregates all Operands so pinned
1612a0318f36SChris Fallin         // vregs (RealRegs) may occur more than once.
1613a0318f36SChris Fallin         true
1614d8357426SChris Fallin     }
1615d8357426SChris Fallin }
1616d8357426SChris Fallin 
16173aa32064SJamey Sharp impl<I: VCodeInst> Debug for VRegAllocator<I> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1618d8357426SChris Fallin     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16193aa32064SJamey Sharp         writeln!(f, "VRegAllocator {{")?;
1620a0318f36SChris Fallin 
1621a0318f36SChris Fallin         let mut alias_keys = self.vreg_aliases.keys().cloned().collect::<Vec<_>>();
1622a0318f36SChris Fallin         alias_keys.sort_unstable();
1623a0318f36SChris Fallin         for key in alias_keys {
1624a0318f36SChris Fallin             let dest = self.vreg_aliases.get(&key).unwrap();
1625a0318f36SChris Fallin             writeln!(f, "  {:?} := {:?}", Reg::from(key), Reg::from(*dest))?;
1626a0318f36SChris Fallin         }
1627d8357426SChris Fallin 
16283aa32064SJamey Sharp         writeln!(f, "}}")
16293aa32064SJamey Sharp     }
16303aa32064SJamey Sharp }
16313aa32064SJamey Sharp 
16323aa32064SJamey Sharp impl<I: VCodeInst> fmt::Debug for VCode<I> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result16333aa32064SJamey Sharp     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16343aa32064SJamey Sharp         writeln!(f, "VCode {{")?;
16353aa32064SJamey Sharp         writeln!(f, "  Entry block: {}", self.entry.index())?;
16363aa32064SJamey Sharp 
16373aa32064SJamey Sharp         let mut state = Default::default();
16383aa32064SJamey Sharp 
1639d8357426SChris Fallin         for block in 0..self.num_blocks() {
1640a0318f36SChris Fallin             let block = BlockIndex::new(block);
1641c510a2b9Sbjorn3             writeln!(
1642c510a2b9Sbjorn3                 f,
1643c510a2b9Sbjorn3                 "Block {}({:?}):",
1644c510a2b9Sbjorn3                 block.index(),
1645c510a2b9Sbjorn3                 self.block_params(block)
1646c510a2b9Sbjorn3             )?;
1647a0318f36SChris Fallin             if let Some(bb) = self.bindex_to_bb(block) {
1648a0442ea0SHamir Mahal                 writeln!(f, "    (original IR block: {bb})")?;
1649d8357426SChris Fallin             }
1650c510a2b9Sbjorn3             for (succ_idx, succ) in self.block_succs(block).iter().enumerate() {
1651c510a2b9Sbjorn3                 writeln!(
1652c510a2b9Sbjorn3                     f,
1653c510a2b9Sbjorn3                     "    (successor: Block {}({:?}))",
1654c510a2b9Sbjorn3                     succ.index(),
1655c510a2b9Sbjorn3                     self.branch_blockparams(block, InsnIndex::new(0) /* dummy */, succ_idx)
1656c510a2b9Sbjorn3                 )?;
1657a0318f36SChris Fallin             }
16582c409535SJamey Sharp             for inst in self.block_ranges.get(block.index()) {
1659a0318f36SChris Fallin                 writeln!(
1660a0318f36SChris Fallin                     f,
1661a0318f36SChris Fallin                     "  Inst {}: {}",
1662a0318f36SChris Fallin                     inst,
16637d703191SJamey Sharp                     self.insts[inst].pretty_print_inst(&mut state)
1664a0318f36SChris Fallin                 )?;
1665e20b4244SNick Fitzgerald                 if let Some(user_stack_map) = self.get_user_stack_map(InsnIndex::new(inst)) {
1666e20b4244SNick Fitzgerald                     writeln!(f, "    {user_stack_map:?}")?;
1667e20b4244SNick Fitzgerald                 }
1668d8357426SChris Fallin             }
16693aa32064SJamey Sharp         }
1670d8357426SChris Fallin 
1671d8357426SChris Fallin         writeln!(f, "}}")?;
1672d8357426SChris Fallin         Ok(())
1673d8357426SChris Fallin     }
1674d8357426SChris Fallin }
1675d8357426SChris Fallin 
1676d94173eaSTrevor Elliott /// This structure manages VReg allocation during the lifetime of the VCodeBuilder.
1677d94173eaSTrevor Elliott pub struct VRegAllocator<I> {
1678d94173eaSTrevor Elliott     /// VReg IR-level types.
1679d94173eaSTrevor Elliott     vreg_types: Vec<Type>,
1680d94173eaSTrevor Elliott 
16813aa32064SJamey Sharp     /// VReg aliases. When the final VCode is built we rewrite all
16823aa32064SJamey Sharp     /// uses of the keys in this table to their replacement values.
16833aa32064SJamey Sharp     ///
16843aa32064SJamey Sharp     /// We use these aliases to rename an instruction's expected
16853aa32064SJamey Sharp     /// result vregs to the returned vregs from lowering, which are
16863aa32064SJamey Sharp     /// usually freshly-allocated temps.
16873aa32064SJamey Sharp     vreg_aliases: FxHashMap<regalloc2::VReg, regalloc2::VReg>,
16883aa32064SJamey Sharp 
168917eeba0eSChris Fallin     /// A deferred error, to be bubbled up to the top level of the
169017eeba0eSChris Fallin     /// lowering algorithm. We take this approach because we cannot
169117eeba0eSChris Fallin     /// currently propagate a `Result` upward through ISLE code (the
169217eeba0eSChris Fallin     /// lowering rules) or some ABI code.
169317eeba0eSChris Fallin     deferred_error: Option<CodegenError>,
169417eeba0eSChris Fallin 
1695d94173eaSTrevor Elliott     /// The type of instruction that this allocator makes registers for.
1696d94173eaSTrevor Elliott     _inst: core::marker::PhantomData<I>,
1697d94173eaSTrevor Elliott }
1698d94173eaSTrevor Elliott 
1699d94173eaSTrevor Elliott impl<I: VCodeInst> VRegAllocator<I> {
1700d94173eaSTrevor Elliott     /// Make a new VRegAllocator.
with_capacity(capacity: usize) -> Self17013aa32064SJamey Sharp     pub fn with_capacity(capacity: usize) -> Self {
17023aa32064SJamey Sharp         let capacity = first_user_vreg_index() + capacity;
17033aa32064SJamey Sharp         let mut vreg_types = Vec::with_capacity(capacity);
17043aa32064SJamey Sharp         vreg_types.resize(first_user_vreg_index(), types::INVALID);
1705d94173eaSTrevor Elliott         Self {
17063aa32064SJamey Sharp             vreg_types,
17073aa32064SJamey Sharp             vreg_aliases: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
170817eeba0eSChris Fallin             deferred_error: None,
1709d94173eaSTrevor Elliott             _inst: core::marker::PhantomData::default(),
1710d94173eaSTrevor Elliott         }
1711d94173eaSTrevor Elliott     }
1712d94173eaSTrevor Elliott 
1713d94173eaSTrevor Elliott     /// Allocate a fresh ValueRegs.
alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>>1714d94173eaSTrevor Elliott     pub fn alloc(&mut self, ty: Type) -> CodegenResult<ValueRegs<Reg>> {
171517eeba0eSChris Fallin         if self.deferred_error.is_some() {
171617eeba0eSChris Fallin             return Err(CodegenError::CodeTooLarge);
171717eeba0eSChris Fallin         }
1718b1307638SJamey Sharp         let v = self.vreg_types.len();
1719d94173eaSTrevor Elliott         let (regclasses, tys) = I::rc_for_type(ty)?;
1720*b5d2ff5dSChris Fallin 
1721*b5d2ff5dSChris Fallin         // Check that new indices are in-bounds for regalloc2's
1722*b5d2ff5dSChris Fallin         // VReg/Operand representation.
1723*b5d2ff5dSChris Fallin         if v + regclasses.len() > VReg::MAX {
1724d94173eaSTrevor Elliott             return Err(CodegenError::CodeTooLarge);
1725d94173eaSTrevor Elliott         }
1726d94173eaSTrevor Elliott 
1727*b5d2ff5dSChris Fallin         // Check that new indices are in-bounds for our Reg
1728*b5d2ff5dSChris Fallin         // bit-packing on top of the RA2 types, which represents
1729*b5d2ff5dSChris Fallin         // spillslots as well.
1730*b5d2ff5dSChris Fallin         let check = |vreg: regalloc2::VReg| -> CodegenResult<Reg> {
1731*b5d2ff5dSChris Fallin             Reg::from_virtual_reg_checked(vreg).ok_or(CodegenError::CodeTooLarge)
1732*b5d2ff5dSChris Fallin         };
1733*b5d2ff5dSChris Fallin 
1734d94173eaSTrevor Elliott         let regs: ValueRegs<Reg> = match regclasses {
1735*b5d2ff5dSChris Fallin             &[rc0] => ValueRegs::one(check(VReg::new(v, rc0))?),
1736*b5d2ff5dSChris Fallin             &[rc0, rc1] => ValueRegs::two(check(VReg::new(v, rc0))?, check(VReg::new(v + 1, rc1))?),
1737d94173eaSTrevor Elliott             // We can extend this if/when we support 32-bit targets; e.g.,
1738d94173eaSTrevor Elliott             // an i128 on a 32-bit machine will need up to four machine regs
1739d94173eaSTrevor Elliott             // for a `Value`.
1740d94173eaSTrevor Elliott             _ => panic!("Value must reside in 1 or 2 registers"),
1741d94173eaSTrevor Elliott         };
1742d94173eaSTrevor Elliott         for (&reg_ty, &reg) in tys.iter().zip(regs.regs().iter()) {
1743b1307638SJamey Sharp             let vreg = reg.to_virtual_reg().unwrap();
1744b1307638SJamey Sharp             debug_assert_eq!(self.vreg_types.len(), vreg.index());
1745b1307638SJamey Sharp             self.vreg_types.push(reg_ty);
1746d94173eaSTrevor Elliott         }
1747f466aa26SChris Fallin 
1748d94173eaSTrevor Elliott         Ok(regs)
1749d94173eaSTrevor Elliott     }
1750d94173eaSTrevor Elliott 
175117eeba0eSChris Fallin     /// Allocate a fresh ValueRegs, deferring any out-of-vregs
175217eeba0eSChris Fallin     /// errors. This is useful in places where we cannot bubble a
175317eeba0eSChris Fallin     /// `CodegenResult` upward easily, and which are known to be
175417eeba0eSChris Fallin     /// invoked from within the lowering loop that checks the deferred
175517eeba0eSChris Fallin     /// error status below.
alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg>175617eeba0eSChris Fallin     pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs<Reg> {
175717eeba0eSChris Fallin         match self.alloc(ty) {
175817eeba0eSChris Fallin             Ok(x) => x,
175917eeba0eSChris Fallin             Err(e) => {
176017eeba0eSChris Fallin                 self.deferred_error = Some(e);
176117eeba0eSChris Fallin                 self.bogus_for_deferred_error(ty)
176217eeba0eSChris Fallin             }
176317eeba0eSChris Fallin         }
176417eeba0eSChris Fallin     }
176517eeba0eSChris Fallin 
176617eeba0eSChris Fallin     /// Take any deferred error that was accumulated by `alloc_with_deferred_error`.
take_deferred_error(&mut self) -> Option<CodegenError>176717eeba0eSChris Fallin     pub fn take_deferred_error(&mut self) -> Option<CodegenError> {
176817eeba0eSChris Fallin         self.deferred_error.take()
176917eeba0eSChris Fallin     }
177017eeba0eSChris Fallin 
177117eeba0eSChris Fallin     /// Produce an bogus VReg placeholder with the proper number of
177217eeba0eSChris Fallin     /// registers for the given type. This is meant to be used with
177317eeba0eSChris Fallin     /// deferred allocation errors (see `Lower::alloc_tmp()`).
bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg>177417eeba0eSChris Fallin     fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs<Reg> {
177517eeba0eSChris Fallin         let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type");
177617eeba0eSChris Fallin         match regclasses {
177717eeba0eSChris Fallin             &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()),
177817eeba0eSChris Fallin             &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()),
177917eeba0eSChris Fallin             _ => panic!("Value must reside in 1 or 2 registers"),
178017eeba0eSChris Fallin         }
178117eeba0eSChris Fallin     }
178217eeba0eSChris Fallin 
17833aa32064SJamey Sharp     /// Rewrite any mention of `from` into `to`.
set_vreg_alias(&mut self, from: Reg, to: Reg)17843aa32064SJamey Sharp     pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) {
17853aa32064SJamey Sharp         let from = from.into();
17863aa32064SJamey Sharp         let resolved_to = self.resolve_vreg_alias(to.into());
17873aa32064SJamey Sharp         // Disallow cycles (see below).
17883aa32064SJamey Sharp         assert_ne!(resolved_to, from);
17893aa32064SJamey Sharp 
17903aa32064SJamey Sharp         let old_alias = self.vreg_aliases.insert(from, resolved_to);
17913aa32064SJamey Sharp         debug_assert_eq!(old_alias, None);
17923aa32064SJamey Sharp     }
17933aa32064SJamey Sharp 
resolve_vreg_alias(&self, mut vreg: regalloc2::VReg) -> regalloc2::VReg17943aa32064SJamey Sharp     fn resolve_vreg_alias(&self, mut vreg: regalloc2::VReg) -> regalloc2::VReg {
17953aa32064SJamey Sharp         // We prevent cycles from existing by resolving targets of
17963aa32064SJamey Sharp         // aliases eagerly before setting them. If the target resolves
17973aa32064SJamey Sharp         // to the origin of the alias, then a cycle would be created
17983aa32064SJamey Sharp         // and the alias is disallowed. Because of the structure of
17993aa32064SJamey Sharp         // SSA code (one instruction can refer to another's defs but
18003aa32064SJamey Sharp         // not vice-versa, except indirectly through
18013aa32064SJamey Sharp         // phis/blockparams), cycles should not occur as we use
18023aa32064SJamey Sharp         // aliases to redirect vregs to the temps that actually define
18033aa32064SJamey Sharp         // them.
18043aa32064SJamey Sharp         while let Some(to) = self.vreg_aliases.get(&vreg) {
18053aa32064SJamey Sharp             vreg = *to;
18063aa32064SJamey Sharp         }
18073aa32064SJamey Sharp         vreg
18083aa32064SJamey Sharp     }
18093aa32064SJamey Sharp 
18103aa32064SJamey Sharp     #[inline]
debug_assert_no_vreg_aliases(&self, mut list: impl Iterator<Item = VReg>)18113aa32064SJamey Sharp     fn debug_assert_no_vreg_aliases(&self, mut list: impl Iterator<Item = VReg>) {
18123aa32064SJamey Sharp         debug_assert!(list.all(|vreg| !self.vreg_aliases.contains_key(&vreg)));
18133aa32064SJamey Sharp     }
1814d94173eaSTrevor Elliott }
1815d94173eaSTrevor Elliott 
181683f182b3SAndrew Brown /// This structure tracks the large constants used in VCode that will be emitted separately by the
181783f182b3SAndrew Brown /// [MachBuffer].
181883f182b3SAndrew Brown ///
181983f182b3SAndrew Brown /// First, during the lowering phase, constants are inserted using
1820d38d387aSAlex Crichton /// [VCodeConstants.insert]; an intermediate handle, `VCodeConstant`, tracks what constants are
182183f182b3SAndrew Brown /// used in this phase. Some deduplication is performed, when possible, as constant
182283f182b3SAndrew Brown /// values are inserted.
182383f182b3SAndrew Brown ///
182483f182b3SAndrew Brown /// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the
182583f182b3SAndrew Brown /// constants so that instructions can refer to the value's memory location. The [MachBuffer]
182683f182b3SAndrew Brown /// then writes the constant values to the buffer.
182783f182b3SAndrew Brown #[derive(Default)]
182883f182b3SAndrew Brown pub struct VCodeConstants {
182983f182b3SAndrew Brown     constants: PrimaryMap<VCodeConstant, VCodeConstantData>,
183083f182b3SAndrew Brown     pool_uses: HashMap<Constant, VCodeConstant>,
183183f182b3SAndrew Brown     well_known_uses: HashMap<*const [u8], VCodeConstant>,
1832eb435f30SChris Fallin     u64s: HashMap<[u8; 8], VCodeConstant>,
183383f182b3SAndrew Brown }
183483f182b3SAndrew Brown impl VCodeConstants {
183583f182b3SAndrew Brown     /// Initialize the structure with the expected number of constants.
with_capacity(expected_num_constants: usize) -> Self183683f182b3SAndrew Brown     pub fn with_capacity(expected_num_constants: usize) -> Self {
183783f182b3SAndrew Brown         Self {
183883f182b3SAndrew Brown             constants: PrimaryMap::with_capacity(expected_num_constants),
183983f182b3SAndrew Brown             pool_uses: HashMap::with_capacity(expected_num_constants),
184083f182b3SAndrew Brown             well_known_uses: HashMap::new(),
1841eb435f30SChris Fallin             u64s: HashMap::new(),
184283f182b3SAndrew Brown         }
184383f182b3SAndrew Brown     }
184483f182b3SAndrew Brown 
184583f182b3SAndrew Brown     /// Insert a constant; using this method indicates that a constant value will be used and thus
184683f182b3SAndrew Brown     /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants
184783f182b3SAndrew Brown     /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not
184883f182b3SAndrew Brown     /// [VCodeConstantData::Generated].
insert(&mut self, data: VCodeConstantData) -> VCodeConstant184983f182b3SAndrew Brown     pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant {
185083f182b3SAndrew Brown         match data {
185183f182b3SAndrew Brown             VCodeConstantData::Generated(_) => self.constants.push(data),
185283f182b3SAndrew Brown             VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) {
185383f182b3SAndrew Brown                 None => {
185483f182b3SAndrew Brown                     let vcode_constant = self.constants.push(data);
185583f182b3SAndrew Brown                     self.pool_uses.insert(constant, vcode_constant);
185683f182b3SAndrew Brown                     vcode_constant
185783f182b3SAndrew Brown                 }
185883f182b3SAndrew Brown                 Some(&vcode_constant) => vcode_constant,
185983f182b3SAndrew Brown             },
186083f182b3SAndrew Brown             VCodeConstantData::WellKnown(data_ref) => {
1861eb435f30SChris Fallin                 match self.well_known_uses.entry(data_ref as *const [u8]) {
1862eb435f30SChris Fallin                     Entry::Vacant(v) => {
186383f182b3SAndrew Brown                         let vcode_constant = self.constants.push(data);
1864eb435f30SChris Fallin                         v.insert(vcode_constant);
186583f182b3SAndrew Brown                         vcode_constant
186683f182b3SAndrew Brown                     }
1867eb435f30SChris Fallin                     Entry::Occupied(o) => *o.get(),
186883f182b3SAndrew Brown                 }
186983f182b3SAndrew Brown             }
1870eb435f30SChris Fallin             VCodeConstantData::U64(value) => match self.u64s.entry(value) {
1871eb435f30SChris Fallin                 Entry::Vacant(v) => {
1872eb435f30SChris Fallin                     let vcode_constant = self.constants.push(data);
1873eb435f30SChris Fallin                     v.insert(vcode_constant);
1874eb435f30SChris Fallin                     vcode_constant
1875eb435f30SChris Fallin                 }
1876eb435f30SChris Fallin                 Entry::Occupied(o) => *o.get(),
1877eb435f30SChris Fallin             },
187883f182b3SAndrew Brown         }
187983f182b3SAndrew Brown     }
188083f182b3SAndrew Brown 
188183f182b3SAndrew Brown     /// Return the number of constants inserted.
len(&self) -> usize188283f182b3SAndrew Brown     pub fn len(&self) -> usize {
188383f182b3SAndrew Brown         self.constants.len()
188483f182b3SAndrew Brown     }
188583f182b3SAndrew Brown 
1886d38d387aSAlex Crichton     /// Iterate over the `VCodeConstant` keys inserted in this structure.
keys(&self) -> Keys<VCodeConstant>188783f182b3SAndrew Brown     pub fn keys(&self) -> Keys<VCodeConstant> {
188883f182b3SAndrew Brown         self.constants.keys()
188983f182b3SAndrew Brown     }
189083f182b3SAndrew Brown 
1891d38d387aSAlex Crichton     /// Iterate over the `VCodeConstant` keys and the data (as a byte slice) inserted in this
189283f182b3SAndrew Brown     /// structure.
iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)>189383f182b3SAndrew Brown     pub fn iter(&self) -> impl Iterator<Item = (VCodeConstant, &VCodeConstantData)> {
189483f182b3SAndrew Brown         self.constants.iter()
189583f182b3SAndrew Brown     }
189649dd8fd7SAlex Crichton 
189749dd8fd7SAlex Crichton     /// Returns the data associated with the specified constant.
get(&self, c: VCodeConstant) -> &VCodeConstantData189849dd8fd7SAlex Crichton     pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData {
189949dd8fd7SAlex Crichton         &self.constants[c]
190049dd8fd7SAlex Crichton     }
190197f6a8b3SSaúl Cabrera 
190297f6a8b3SSaúl Cabrera     /// Checks if the given [VCodeConstantData] is registered as
190397f6a8b3SSaúl Cabrera     /// used by the pool.
pool_uses(&self, constant: &VCodeConstantData) -> bool190497f6a8b3SSaúl Cabrera     pub fn pool_uses(&self, constant: &VCodeConstantData) -> bool {
190597f6a8b3SSaúl Cabrera         match constant {
190697f6a8b3SSaúl Cabrera             VCodeConstantData::Pool(c, _) => self.pool_uses.contains_key(c),
190797f6a8b3SSaúl Cabrera             _ => false,
190897f6a8b3SSaúl Cabrera         }
190997f6a8b3SSaúl Cabrera     }
191083f182b3SAndrew Brown }
191183f182b3SAndrew Brown 
191283f182b3SAndrew Brown /// A use of a constant by one or more VCode instructions; see [VCodeConstants].
191383f182b3SAndrew Brown #[derive(Clone, Copy, Debug, PartialEq, Eq)]
191483f182b3SAndrew Brown pub struct VCodeConstant(u32);
191583f182b3SAndrew Brown entity_impl!(VCodeConstant);
191683f182b3SAndrew Brown 
191783f182b3SAndrew Brown /// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking
191883f182b3SAndrew Brown /// these separately instead of as raw byte buffers allows us to avoid some duplication.
191983f182b3SAndrew Brown pub enum VCodeConstantData {
192083f182b3SAndrew Brown     /// A constant already present in the Cranelift IR
192183f182b3SAndrew Brown     /// [ConstantPool](crate::ir::constant::ConstantPool).
192283f182b3SAndrew Brown     Pool(Constant, ConstantData),
192383f182b3SAndrew Brown     /// A reference to a well-known constant value that is statically encoded within the compiler.
192483f182b3SAndrew Brown     WellKnown(&'static [u8]),
192583f182b3SAndrew Brown     /// A constant value generated during lowering; the value may depend on the instruction context
192683f182b3SAndrew Brown     /// which makes it difficult to de-duplicate--if possible, use other variants.
192783f182b3SAndrew Brown     Generated(ConstantData),
1928eb435f30SChris Fallin     /// A constant of at most 64 bits. These are deduplicated as
1929eb435f30SChris Fallin     /// well. Stored as a fixed-size array of `u8` so that we do not
1930eb435f30SChris Fallin     /// encounter endianness problems when cross-compiling.
1931eb435f30SChris Fallin     U64([u8; 8]),
193283f182b3SAndrew Brown }
193383f182b3SAndrew Brown impl VCodeConstantData {
193483f182b3SAndrew Brown     /// Retrieve the constant data as a byte slice.
as_slice(&self) -> &[u8]193583f182b3SAndrew Brown     pub fn as_slice(&self) -> &[u8] {
193683f182b3SAndrew Brown         match self {
193783f182b3SAndrew Brown             VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(),
193883f182b3SAndrew Brown             VCodeConstantData::WellKnown(d) => d,
1939eb435f30SChris Fallin             VCodeConstantData::U64(value) => &value[..],
194083f182b3SAndrew Brown         }
194183f182b3SAndrew Brown     }
194283f182b3SAndrew Brown 
194383f182b3SAndrew Brown     /// Calculate the alignment of the constant data.
alignment(&self) -> u32194483f182b3SAndrew Brown     pub fn alignment(&self) -> u32 {
194590ac295eSAlex Crichton         if self.as_slice().len() <= 8 { 8 } else { 16 }
194683f182b3SAndrew Brown     }
194783f182b3SAndrew Brown }
194883f182b3SAndrew Brown 
194983f182b3SAndrew Brown #[cfg(test)]
195083f182b3SAndrew Brown mod test {
195183f182b3SAndrew Brown     use super::*;
19520889323aSSSD     use core::mem::size_of;
195383f182b3SAndrew Brown 
195483f182b3SAndrew Brown     #[test]
size_of_constant_structs()195583f182b3SAndrew Brown     fn size_of_constant_structs() {
195683f182b3SAndrew Brown         assert_eq!(size_of::<Constant>(), 4);
195783f182b3SAndrew Brown         assert_eq!(size_of::<VCodeConstant>(), 4);
195848f4621fSAlex Crichton         assert_eq!(size_of::<ConstantData>(), 3 * size_of::<usize>());
195948f4621fSAlex Crichton         assert_eq!(size_of::<VCodeConstantData>(), 4 * size_of::<usize>());
196083f182b3SAndrew Brown         assert_eq!(
196183f182b3SAndrew Brown             size_of::<PrimaryMap<VCodeConstant, VCodeConstantData>>(),
196248f4621fSAlex Crichton             3 * size_of::<usize>()
196383f182b3SAndrew Brown         );
19645e5e5206SChris Fallin         // TODO The VCodeConstants structure's memory size could be further optimized.
19655e5e5206SChris Fallin         // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at
19665e5e5206SChris Fallin         // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes.
196783f182b3SAndrew Brown     }
196883f182b3SAndrew Brown }
1969