1 //! Intermediate representation of a function. 2 //! 3 //! The `Function` struct defined in this module owns all of its basic blocks and 4 //! instructions. 5 6 use crate::binemit::CodeOffset; 7 use crate::entity::{PrimaryMap, SecondaryMap}; 8 use crate::ir; 9 use crate::ir::{ 10 Block, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable, 11 JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData, 12 }; 13 use crate::ir::{BlockOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations}; 14 use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature}; 15 use crate::ir::{JumpTableOffsets, JumpTables}; 16 use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa}; 17 use crate::regalloc::{EntryRegDiversions, RegDiversions}; 18 use crate::value_label::ValueLabelsRanges; 19 use crate::write::write_function; 20 use alloc::vec::Vec; 21 use core::fmt; 22 23 /// A function. 24 /// 25 /// Functions can be cloned, but it is not a very fast operation. 26 /// The clone will have all the same entity numbers as the original. 27 #[derive(Clone)] 28 pub struct Function { 29 /// Name of this function. Mostly used by `.clif` files. 30 pub name: ExternalName, 31 32 /// Signature of this function. 33 pub signature: Signature, 34 35 /// The old signature of this function, before the most recent legalization, 36 /// if any. 37 pub old_signature: Option<Signature>, 38 39 /// Stack slots allocated in this function. 40 pub stack_slots: StackSlots, 41 42 /// Global values referenced. 43 pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>, 44 45 /// Heaps referenced. 46 pub heaps: PrimaryMap<ir::Heap, ir::HeapData>, 47 48 /// Tables referenced. 49 pub tables: PrimaryMap<ir::Table, ir::TableData>, 50 51 /// Jump tables used in this function. 52 pub jump_tables: JumpTables, 53 54 /// Data flow graph containing the primary definition of all instructions, blocks and values. 55 pub dfg: DataFlowGraph, 56 57 /// Layout of blocks and instructions in the function body. 58 pub layout: Layout, 59 60 /// Encoding recipe and bits for the legal instructions. 61 /// Illegal instructions have the `Encoding::default()` value. 62 pub encodings: InstEncodings, 63 64 /// Location assigned to every value. 65 pub locations: ValueLocations, 66 67 /// Non-default locations assigned to value at the entry of basic blocks. 68 /// 69 /// At the entry of each basic block, we might have values which are not in their default 70 /// ValueLocation. This field records these register-to-register moves as Diversions. 71 pub entry_diversions: EntryRegDiversions, 72 73 /// Code offsets of the block headers. 74 /// 75 /// This information is only transiently available after the `binemit::relax_branches` function 76 /// computes it, and it can easily be recomputed by calling that function. It is not included 77 /// in the textual IR format. 78 pub offsets: BlockOffsets, 79 80 /// Code offsets of Jump Table headers. 81 pub jt_offsets: JumpTableOffsets, 82 83 /// Source locations. 84 /// 85 /// Track the original source location for each instruction. The source locations are not 86 /// interpreted by Cranelift, only preserved. 87 pub srclocs: SourceLocs, 88 89 /// Instruction that marks the end (inclusive) of the function's prologue. 90 /// 91 /// This is used for some ABIs to generate unwind information. 92 pub prologue_end: Option<Inst>, 93 94 /// The instructions that mark the start (inclusive) of an epilogue in the function. 95 /// 96 /// This is used for some ABIs to generate unwind information. 97 pub epilogues_start: Vec<Inst>, 98 99 /// An optional global value which represents an expression evaluating to 100 /// the stack limit for this function. This `GlobalValue` will be 101 /// interpreted in the prologue, if necessary, to insert a stack check to 102 /// ensure that a trap happens if the stack pointer goes below the 103 /// threshold specified here. 104 pub stack_limit: Option<ir::GlobalValue>, 105 } 106 107 impl Function { 108 /// Create a function with the given name and signature. 109 pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self { 110 Self { 111 name, 112 signature: sig, 113 old_signature: None, 114 stack_slots: StackSlots::new(), 115 global_values: PrimaryMap::new(), 116 heaps: PrimaryMap::new(), 117 tables: PrimaryMap::new(), 118 jump_tables: PrimaryMap::new(), 119 dfg: DataFlowGraph::new(), 120 layout: Layout::new(), 121 encodings: SecondaryMap::new(), 122 locations: SecondaryMap::new(), 123 entry_diversions: EntryRegDiversions::new(), 124 offsets: SecondaryMap::new(), 125 jt_offsets: SecondaryMap::new(), 126 srclocs: SecondaryMap::new(), 127 prologue_end: None, 128 epilogues_start: Vec::new(), 129 stack_limit: None, 130 } 131 } 132 133 /// Clear all data structures in this function. 134 pub fn clear(&mut self) { 135 self.signature.clear(CallConv::Fast); 136 self.stack_slots.clear(); 137 self.global_values.clear(); 138 self.heaps.clear(); 139 self.tables.clear(); 140 self.jump_tables.clear(); 141 self.dfg.clear(); 142 self.layout.clear(); 143 self.encodings.clear(); 144 self.locations.clear(); 145 self.entry_diversions.clear(); 146 self.offsets.clear(); 147 self.jt_offsets.clear(); 148 self.srclocs.clear(); 149 self.prologue_end = None; 150 self.epilogues_start.clear(); 151 self.stack_limit = None; 152 } 153 154 /// Create a new empty, anonymous function with a Fast calling convention. 155 pub fn new() -> Self { 156 Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast)) 157 } 158 159 /// Creates a jump table in the function, to be used by `br_table` instructions. 160 pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { 161 self.jump_tables.push(data) 162 } 163 164 /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and 165 /// `stack_addr` instructions. 166 pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot { 167 self.stack_slots.push(data) 168 } 169 170 /// Adds a signature which can later be used to declare an external function import. 171 pub fn import_signature(&mut self, signature: Signature) -> SigRef { 172 self.dfg.signatures.push(signature) 173 } 174 175 /// Declare an external function import. 176 pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { 177 self.dfg.ext_funcs.push(data) 178 } 179 180 /// Declares a global value accessible to the function. 181 pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { 182 self.global_values.push(data) 183 } 184 185 /// Declares a heap accessible to the function. 186 pub fn create_heap(&mut self, data: HeapData) -> Heap { 187 self.heaps.push(data) 188 } 189 190 /// Declares a table accessible to the function. 191 pub fn create_table(&mut self, data: TableData) -> Table { 192 self.tables.push(data) 193 } 194 195 /// Return an object that can display this function with correct ISA-specific annotations. 196 pub fn display<'a, I: Into<Option<&'a dyn TargetIsa>>>( 197 &'a self, 198 isa: I, 199 ) -> DisplayFunction<'a> { 200 DisplayFunction(self, isa.into().into()) 201 } 202 203 /// Return an object that can display this function with correct ISA-specific annotations. 204 pub fn display_with<'a>( 205 &'a self, 206 annotations: DisplayFunctionAnnotations<'a>, 207 ) -> DisplayFunction<'a> { 208 DisplayFunction(self, annotations) 209 } 210 211 /// Find a presumed unique special-purpose function parameter value. 212 /// 213 /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists. 214 pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { 215 let entry = self.layout.entry_block().expect("Function is empty"); 216 self.signature 217 .special_param_index(purpose) 218 .map(|i| self.dfg.block_params(entry)[i]) 219 } 220 221 /// Get an iterator over the instructions in `block`, including offsets and encoded instruction 222 /// sizes. 223 /// 224 /// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes 225 /// from the beginning of the function to the instruction, and `size` is the size of the 226 /// instruction in bytes, or 0 for unencoded instructions. 227 /// 228 /// This function can only be used after the code layout has been computed by the 229 /// `binemit::relax_branches()` function. 230 pub fn inst_offsets<'a>(&'a self, block: Block, encinfo: &EncInfo) -> InstOffsetIter<'a> { 231 assert!( 232 !self.offsets.is_empty(), 233 "Code layout must be computed first" 234 ); 235 let mut divert = RegDiversions::new(); 236 divert.at_block(&self.entry_diversions, block); 237 InstOffsetIter { 238 encinfo: encinfo.clone(), 239 func: self, 240 divert, 241 encodings: &self.encodings, 242 offset: self.offsets[block], 243 iter: self.layout.block_insts(block), 244 } 245 } 246 247 /// Wrapper around `encode` which assigns `inst` the resulting encoding. 248 pub fn update_encoding(&mut self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<(), Legalize> { 249 if isa.get_mach_backend().is_some() { 250 Ok(()) 251 } else { 252 self.encode(inst, isa).map(|e| self.encodings[inst] = e) 253 } 254 } 255 256 /// Wrapper around `TargetIsa::encode` for encoding an existing instruction 257 /// in the `Function`. 258 pub fn encode(&self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<Encoding, Legalize> { 259 if isa.get_mach_backend().is_some() { 260 Ok(Encoding::new(0, 0)) 261 } else { 262 isa.encode(&self, &self.dfg[inst], self.dfg.ctrl_typevar(inst)) 263 } 264 } 265 266 /// Starts collection of debug information. 267 pub fn collect_debug_info(&mut self) { 268 self.dfg.collect_debug_info(); 269 } 270 271 /// Changes the destination of a jump or branch instruction. 272 /// Does nothing if called with a non-jump or non-branch instruction. 273 pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) { 274 match self.dfg[inst].branch_destination_mut() { 275 None => (), 276 Some(inst_dest) => *inst_dest = new_dest, 277 } 278 } 279 280 /// Checks that the specified block can be encoded as a basic block. 281 /// 282 /// On error, returns the first invalid instruction and an error message. 283 pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { 284 let dfg = &self.dfg; 285 let inst_iter = self.layout.block_insts(block); 286 287 // Ignore all instructions prior to the first branch. 288 let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch()); 289 290 // A conditional branch is permitted in a basic block only when followed 291 // by a terminal jump or fallthrough instruction. 292 if let Some(_branch) = inst_iter.next() { 293 if let Some(next) = inst_iter.next() { 294 match dfg[next].opcode() { 295 Opcode::Fallthrough | Opcode::Jump => (), 296 _ => return Err((next, "post-branch instruction not fallthrough or jump")), 297 } 298 } 299 } 300 301 Ok(()) 302 } 303 304 /// Returns true if the function is function that doesn't call any other functions. This is not 305 /// to be confused with a "leaf function" in Windows terminology. 306 pub fn is_leaf(&self) -> bool { 307 // Conservative result: if there's at least one function signature referenced in this 308 // function, assume it is not a leaf. 309 self.dfg.signatures.is_empty() 310 } 311 312 /// Replace the `dst` instruction's data with the `src` instruction's data 313 /// and then remove `src`. 314 /// 315 /// `src` and its result values should not be used at all, as any uses would 316 /// be left dangling after calling this method. 317 /// 318 /// `src` and `dst` must have the same number of resulting values, and 319 /// `src`'s i^th value must have the same type as `dst`'s i^th value. 320 pub fn transplant_inst(&mut self, dst: Inst, src: Inst) { 321 debug_assert_eq!( 322 self.dfg.inst_results(dst).len(), 323 self.dfg.inst_results(src).len() 324 ); 325 debug_assert!(self 326 .dfg 327 .inst_results(dst) 328 .iter() 329 .zip(self.dfg.inst_results(src)) 330 .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b))); 331 332 self.dfg[dst] = self.dfg[src].clone(); 333 self.layout.remove_inst(src); 334 } 335 } 336 337 /// Additional annotations for function display. 338 #[derive(Default)] 339 pub struct DisplayFunctionAnnotations<'a> { 340 /// Enable ISA annotations. 341 pub isa: Option<&'a dyn TargetIsa>, 342 343 /// Enable value labels annotations. 344 pub value_ranges: Option<&'a ValueLabelsRanges>, 345 } 346 347 impl<'a> From<Option<&'a dyn TargetIsa>> for DisplayFunctionAnnotations<'a> { 348 fn from(isa: Option<&'a dyn TargetIsa>) -> DisplayFunctionAnnotations { 349 DisplayFunctionAnnotations { 350 isa, 351 value_ranges: None, 352 } 353 } 354 } 355 356 /// Wrapper type capable of displaying a `Function` with correct ISA annotations. 357 pub struct DisplayFunction<'a>(&'a Function, DisplayFunctionAnnotations<'a>); 358 359 impl<'a> fmt::Display for DisplayFunction<'a> { 360 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 361 write_function(fmt, self.0, &self.1) 362 } 363 } 364 365 impl fmt::Display for Function { 366 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 367 write_function(fmt, self, &DisplayFunctionAnnotations::default()) 368 } 369 } 370 371 impl fmt::Debug for Function { 372 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 373 write_function(fmt, self, &DisplayFunctionAnnotations::default()) 374 } 375 } 376 377 /// Iterator returning instruction offsets and sizes: `(offset, inst, size)`. 378 pub struct InstOffsetIter<'a> { 379 encinfo: EncInfo, 380 divert: RegDiversions, 381 func: &'a Function, 382 encodings: &'a InstEncodings, 383 offset: CodeOffset, 384 iter: ir::layout::Insts<'a>, 385 } 386 387 impl<'a> Iterator for InstOffsetIter<'a> { 388 type Item = (CodeOffset, ir::Inst, CodeOffset); 389 390 fn next(&mut self) -> Option<Self::Item> { 391 self.iter.next().map(|inst| { 392 self.divert.apply(&self.func.dfg[inst]); 393 let byte_size = 394 self.encinfo 395 .byte_size(self.encodings[inst], inst, &self.divert, self.func); 396 let offset = self.offset; 397 self.offset += byte_size; 398 (offset, inst, byte_size) 399 }) 400 } 401 } 402