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