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