1 //! This module exposes the machine-specific backend definition pieces.
2 //!
3 //! The MachInst infrastructure is the compiler backend, from CLIF
4 //! (ir::Function) to machine code. The purpose of this infrastructure is, at a
5 //! high level, to do instruction selection/lowering (to machine instructions),
6 //! register allocation, and then perform all the fixups to branches, constant
7 //! data references, etc., needed to actually generate machine code.
8 //!
9 //! The container for machine instructions, at various stages of construction,
10 //! is the `VCode` struct. We refer to a sequence of machine instructions organized
11 //! into basic blocks as "vcode". This is short for "virtual-register code", though
12 //! it's a bit of a misnomer because near the end of the pipeline, vcode has all
13 //! real registers. Nevertheless, the name is catchy and we like it.
14 //!
15 //! The compilation pipeline, from an `ir::Function` (already optimized as much as
16 //! you like by machine-independent optimization passes) onward, is as follows.
17 //! (N.B.: though we show the VCode separately at each stage, the passes
18 //! mutate the VCode in place; these are not separate copies of the code.)
19 //!
20 //! ```plain
21 //!
22 //!     ir::Function                (SSA IR, machine-independent opcodes)
23 //!         |
24 //!         |  [lower]
25 //!         |
26 //!     VCode<arch_backend::Inst>   (machine instructions:
27 //!         |                        - mostly virtual registers.
28 //!         |                        - cond branches in two-target form.
29 //!         |                        - branch targets are block indices.
30 //!         |                        - in-memory constants held by insns,
31 //!         |                          with unknown offsets.
32 //!         |                        - critical edges (actually all edges)
33 //!         |                          are split.)
34 //!         | [regalloc]
35 //!         |
36 //!     VCode<arch_backend::Inst>   (machine instructions:
37 //!         |                        - all real registers.
38 //!         |                        - new instruction sequence returned
39 //!         |                          out-of-band in RegAllocResult.
40 //!         |                        - instruction sequence has spills,
41 //!         |                          reloads, and moves inserted.
42 //!         |                        - other invariants same as above.)
43 //!         |
44 //!         | [preamble/postamble]
45 //!         |
46 //!     VCode<arch_backend::Inst>   (machine instructions:
47 //!         |                        - stack-frame size known.
48 //!         |                        - out-of-band instruction sequence
49 //!         |                          has preamble prepended to entry
50 //!         |                          block, and postamble injected before
51 //!         |                          every return instruction.
52 //!         |                        - all symbolic stack references to
53 //!         |                          stackslots and spillslots are resolved
54 //!         |                          to concrete FP-offset mem addresses.)
55 //!         |
56 //!         | [binary emission via MachBuffer
57 //!         |  with streaming branch resolution/simplification]
58 //!         |
59 //!     Vec<u8>                     (machine code!)
60 //!
61 //! ```
62 
63 use crate::binemit::{Addend, CodeInfo, CodeOffset, Reloc, StackMap};
64 use crate::ir::{SourceLoc, StackSlot, Type, ValueLabel};
65 use crate::result::CodegenResult;
66 use crate::settings::Flags;
67 use crate::value_label::ValueLabelsRanges;
68 use alloc::boxed::Box;
69 use alloc::vec::Vec;
70 use core::fmt::Debug;
71 use cranelift_entity::PrimaryMap;
72 use regalloc::RegUsageCollector;
73 use regalloc::{
74     RealReg, RealRegUniverse, Reg, RegClass, RegUsageMapper, SpillSlot, VirtualReg, Writable,
75 };
76 use smallvec::{smallvec, SmallVec};
77 use std::string::String;
78 
79 #[macro_use]
80 pub mod isle;
81 
82 pub mod lower;
83 pub use lower::*;
84 pub mod vcode;
85 pub use vcode::*;
86 pub mod compile;
87 pub use compile::*;
88 pub mod blockorder;
89 pub use blockorder::*;
90 pub mod abi;
91 pub use abi::*;
92 pub mod abi_impl;
93 pub use abi_impl::*;
94 pub mod buffer;
95 pub use buffer::*;
96 pub mod helpers;
97 pub use helpers::*;
98 pub mod inst_common;
99 pub use inst_common::*;
100 pub mod valueregs;
101 pub use valueregs::*;
102 pub mod debug;
103 pub use regmapping::*;
104 pub mod regmapping;
105 
106 /// A machine instruction.
107 pub trait MachInst: Clone + Debug {
108     /// Return the registers referenced by this machine instruction along with
109     /// the modes of reference (use, def, modify).
110     fn get_regs(&self, collector: &mut RegUsageCollector);
111 
112     /// Map virtual registers to physical registers using the given virt->phys
113     /// maps corresponding to the program points prior to, and after, this instruction.
114     fn map_regs<RUM: RegUsageMapper>(&mut self, maps: &RUM);
115 
116     /// If this is a simple move, return the (source, destination) tuple of registers.
117     fn is_move(&self) -> Option<(Writable<Reg>, Reg)>;
118 
119     /// Is this a terminator (branch or ret)? If so, return its type
120     /// (ret/uncond/cond) and target if applicable.
121     fn is_term<'a>(&'a self) -> MachTerminator<'a>;
122 
123     /// Returns true if the instruction is an epilogue placeholder.
124     fn is_epilogue_placeholder(&self) -> bool;
125 
126     /// Should this instruction be included in the clobber-set?
127     fn is_included_in_clobbers(&self) -> bool {
128         true
129     }
130 
131     /// If this is a load or store to the stack, return that info.
132     fn stack_op_info(&self) -> Option<MachInstStackOpInfo> {
133         None
134     }
135 
136     /// Generate a move.
137     fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Self;
138 
139     /// Generate a constant into a reg.
140     fn gen_constant<F: FnMut(Type) -> Writable<Reg>>(
141         to_regs: ValueRegs<Writable<Reg>>,
142         value: u128,
143         ty: Type,
144         alloc_tmp: F,
145     ) -> SmallVec<[Self; 4]>;
146 
147     /// Possibly operate on a value directly in a spill-slot rather than a
148     /// register. Useful if the machine has register-memory instruction forms
149     /// (e.g., add directly from or directly to memory), like x86.
150     fn maybe_direct_reload(&self, reg: VirtualReg, slot: SpillSlot) -> Option<Self>;
151 
152     /// Determine register class(es) to store the given Cranelift type, and the
153     /// Cranelift type actually stored in the underlying register(s).  May return
154     /// an error if the type isn't supported by this backend.
155     ///
156     /// If the type requires multiple registers, then the list of registers is
157     /// returned in little-endian order.
158     ///
159     /// Note that the type actually stored in the register(s) may differ in the
160     /// case that a value is split across registers: for example, on a 32-bit
161     /// target, an I64 may be stored in two registers, each of which holds an
162     /// I32. The actually-stored types are used only to inform the backend when
163     /// generating spills and reloads for individual registers.
164     fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])>;
165 
166     /// Generate a jump to another target. Used during lowering of
167     /// control flow.
168     fn gen_jump(target: MachLabel) -> Self;
169 
170     /// Generate a NOP. The `preferred_size` parameter allows the caller to
171     /// request a NOP of that size, or as close to it as possible. The machine
172     /// backend may return a NOP whose binary encoding is smaller than the
173     /// preferred size, but must not return a NOP that is larger. However,
174     /// the instruction must have a nonzero size if preferred_size is nonzero.
175     fn gen_nop(preferred_size: usize) -> Self;
176 
177     /// Align a basic block offset (from start of function).  By default, no
178     /// alignment occurs.
179     fn align_basic_block(offset: CodeOffset) -> CodeOffset {
180         offset
181     }
182 
183     /// What is the worst-case instruction size emitted by this instruction type?
184     fn worst_case_size() -> CodeOffset;
185 
186     /// What is the register class used for reference types (GC-observable pointers)? Can
187     /// be dependent on compilation flags.
188     fn ref_type_regclass(_flags: &Flags) -> RegClass;
189 
190     /// Does this instruction define a ValueLabel? Returns the `Reg` whose value
191     /// becomes the new value of the `ValueLabel` after this instruction.
192     fn defines_value_label(&self) -> Option<(ValueLabel, Reg)> {
193         None
194     }
195 
196     /// Create a marker instruction that defines a value label.
197     fn gen_value_label_marker(_label: ValueLabel, _reg: Reg) -> Self {
198         Self::gen_nop(0)
199     }
200 
201     /// A label-use kind: a type that describes the types of label references that
202     /// can occur in an instruction.
203     type LabelUse: MachInstLabelUse;
204 }
205 
206 /// A descriptor of a label reference (use) in an instruction set.
207 pub trait MachInstLabelUse: Clone + Copy + Debug + Eq {
208     /// Required alignment for any veneer. Usually the required instruction
209     /// alignment (e.g., 4 for a RISC with 32-bit instructions, or 1 for x86).
210     const ALIGN: CodeOffset;
211 
212     /// What is the maximum PC-relative range (positive)? E.g., if `1024`, a
213     /// label-reference fixup at offset `x` is valid if the label resolves to `x
214     /// + 1024`.
215     fn max_pos_range(self) -> CodeOffset;
216     /// What is the maximum PC-relative range (negative)? This is the absolute
217     /// value; i.e., if `1024`, then a label-reference fixup at offset `x` is
218     /// valid if the label resolves to `x - 1024`.
219     fn max_neg_range(self) -> CodeOffset;
220     /// What is the size of code-buffer slice this label-use needs to patch in
221     /// the label's value?
222     fn patch_size(self) -> CodeOffset;
223     /// Perform a code-patch, given the offset into the buffer of this label use
224     /// and the offset into the buffer of the label's definition.
225     /// It is guaranteed that, given `delta = offset - label_offset`, we will
226     /// have `offset >= -self.max_neg_range()` and `offset <=
227     /// self.max_pos_range()`.
228     fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset);
229     /// Can the label-use be patched to a veneer that supports a longer range?
230     /// Usually valid for jumps (a short-range jump can jump to a longer-range
231     /// jump), but not for e.g. constant pool references, because the constant
232     /// load would require different code (one more level of indirection).
233     fn supports_veneer(self) -> bool;
234     /// How many bytes are needed for a veneer?
235     fn veneer_size(self) -> CodeOffset;
236     /// Generate a veneer. The given code-buffer slice is `self.veneer_size()`
237     /// bytes long at offset `veneer_offset` in the buffer. The original
238     /// label-use will be patched to refer to this veneer's offset.  A new
239     /// (offset, LabelUse) is returned that allows the veneer to use the actual
240     /// label. For veneers to work properly, it is expected that the new veneer
241     /// has a larger range; on most platforms this probably means either a
242     /// "long-range jump" (e.g., on ARM, the 26-bit form), or if already at that
243     /// stage, a jump that supports a full 32-bit range, for example.
244     fn generate_veneer(self, buffer: &mut [u8], veneer_offset: CodeOffset) -> (CodeOffset, Self);
245 
246     /// Returns the corresponding label-use for the relocation specified.
247     ///
248     /// This returns `None` if the relocation doesn't have a corresponding
249     /// representation for the target architecture.
250     fn from_reloc(reloc: Reloc, addend: Addend) -> Option<Self>;
251 }
252 
253 /// Describes a block terminator (not call) in the vcode, when its branches
254 /// have not yet been finalized (so a branch may have two targets).
255 #[derive(Clone, Debug, PartialEq, Eq)]
256 pub enum MachTerminator<'a> {
257     /// Not a terminator.
258     None,
259     /// A return instruction.
260     Ret,
261     /// An unconditional branch to another block.
262     Uncond(MachLabel),
263     /// A conditional branch to one of two other blocks.
264     Cond(MachLabel, MachLabel),
265     /// An indirect branch with known possible targets.
266     Indirect(&'a [MachLabel]),
267 }
268 
269 impl<'a> MachTerminator<'a> {
270     /// Get the successor labels named in a `MachTerminator`.
271     pub fn get_succs(&self) -> SmallVec<[MachLabel; 2]> {
272         let mut ret = smallvec![];
273         match self {
274             &MachTerminator::Uncond(l) => {
275                 ret.push(l);
276             }
277             &MachTerminator::Cond(l1, l2) => {
278                 ret.push(l1);
279                 ret.push(l2);
280             }
281             &MachTerminator::Indirect(ls) => {
282                 ret.extend(ls.iter().cloned());
283             }
284             _ => {}
285         }
286         ret
287     }
288 
289     /// Is this a terminator?
290     pub fn is_term(&self) -> bool {
291         match self {
292             MachTerminator::None => false,
293             _ => true,
294         }
295     }
296 }
297 
298 /// A trait describing the ability to encode a MachInst into binary machine code.
299 pub trait MachInstEmit: MachInst {
300     /// Persistent state carried across `emit` invocations.
301     type State: MachInstEmitState<Self>;
302     /// Constant information used in `emit` invocations.
303     type Info;
304     /// Emit the instruction.
305     fn emit(&self, code: &mut MachBuffer<Self>, info: &Self::Info, state: &mut Self::State);
306     /// Pretty-print the instruction.
307     fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut Self::State) -> String;
308 }
309 
310 /// A trait describing the emission state carried between MachInsts when
311 /// emitting a function body.
312 pub trait MachInstEmitState<I: MachInst>: Default + Clone + Debug {
313     /// Create a new emission state given the ABI object.
314     fn new(abi: &dyn ABICallee<I = I>) -> Self;
315     /// Update the emission state before emitting an instruction that is a
316     /// safepoint.
317     fn pre_safepoint(&mut self, _stack_map: StackMap) {}
318     /// Update the emission state to indicate instructions are associated with a
319     /// particular SourceLoc.
320     fn pre_sourceloc(&mut self, _srcloc: SourceLoc) {}
321 }
322 
323 /// The result of a `MachBackend::compile_function()` call. Contains machine
324 /// code (as bytes) and a disassembly, if requested.
325 pub struct MachCompileResult {
326     /// Machine code.
327     pub buffer: MachBufferFinalized,
328     /// Size of stack frame, in bytes.
329     pub frame_size: u32,
330     /// Disassembly, if requested.
331     pub disasm: Option<String>,
332     /// Debug info: value labels to registers/stackslots at code offsets.
333     pub value_labels_ranges: ValueLabelsRanges,
334     /// Debug info: stackslots to stack pointer offsets.
335     pub stackslot_offsets: PrimaryMap<StackSlot, u32>,
336     /// Basic-block layout info: block start offsets.
337     ///
338     /// This info is generated only if the `machine_code_cfg_info`
339     /// flag is set.
340     pub bb_starts: Vec<CodeOffset>,
341     /// Basic-block layout info: block edges. Each edge is `(from,
342     /// to)`, where `from` and `to` are basic-block start offsets of
343     /// the respective blocks.
344     ///
345     /// This info is generated only if the `machine_code_cfg_info`
346     /// flag is set.
347     pub bb_edges: Vec<(CodeOffset, CodeOffset)>,
348 }
349 
350 impl MachCompileResult {
351     /// Get a `CodeInfo` describing section sizes from this compilation result.
352     pub fn code_info(&self) -> CodeInfo {
353         CodeInfo {
354             total_size: self.buffer.total_size(),
355         }
356     }
357 }
358 
359 /// An object that can be used to create the text section of an executable.
360 ///
361 /// This primarily handles resolving relative relocations at
362 /// text-section-assembly time rather than at load/link time. This
363 /// architecture-specific logic is sort of like a linker, but only for one
364 /// object file at a time.
365 pub trait TextSectionBuilder {
366     /// Appends `data` to the text section with the `align` specified.
367     ///
368     /// If `labeled` is `true` then the offset of the final data is used to
369     /// resolve relocations in `resolve_reloc` in the future.
370     ///
371     /// This function returns the offset at which the data was placed in the
372     /// text section.
373     fn append(&mut self, labeled: bool, data: &[u8], align: u32) -> u64;
374 
375     /// Attempts to resolve a relocation for this function.
376     ///
377     /// The `offset` is the offset of the relocation, within the text section.
378     /// The `reloc` is the kind of relocation.
379     /// The `addend` is the value to add to the relocation.
380     /// The `target` is the labeled function that is the target of this
381     /// relocation.
382     ///
383     /// Labeled functions are created with the `append` function above by
384     /// setting the `labeled` parameter to `true`.
385     ///
386     /// If this builder does not know how to handle `reloc` then this function
387     /// will return `false`. Otherwise this function will return `true` and this
388     /// relocation will be resolved in the final bytes returned by `finish`.
389     fn resolve_reloc(&mut self, offset: u64, reloc: Reloc, addend: Addend, target: u32) -> bool;
390 
391     /// A debug-only option which is used to for
392     fn force_veneers(&mut self);
393 
394     /// Completes this text section, filling out any final details, and returns
395     /// the bytes of the text section.
396     fn finish(&mut self) -> Vec<u8>;
397 }
398 
399 /// Expected unwind info type.
400 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
401 #[non_exhaustive]
402 pub enum UnwindInfoKind {
403     /// No unwind info.
404     None,
405     /// SystemV CIE/FDE unwind info.
406     #[cfg(feature = "unwind")]
407     SystemV,
408     /// Windows X64 Unwind info
409     #[cfg(feature = "unwind")]
410     Windows,
411 }
412 
413 /// Info about an operation that loads or stores from/to the stack.
414 #[derive(Clone, Copy, Debug)]
415 pub enum MachInstStackOpInfo {
416     /// Load from an offset from the nominal stack pointer into the given reg.
417     LoadNomSPOff(Reg, i64),
418     /// Store to an offset from the nominal stack pointer from the given reg.
419     StoreNomSPOff(Reg, i64),
420     /// Adjustment of nominal-SP up or down. This value is added to subsequent
421     /// offsets in loads/stores above to produce real-SP offsets.
422     NomSPAdj(i64),
423 }
424