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