1747ad3c4Slazypassion //! Intermediate representation of a function. 2747ad3c4Slazypassion //! 3747ad3c4Slazypassion //! The `Function` struct defined in this module owns all of its extended basic blocks and 4747ad3c4Slazypassion //! instructions. 5747ad3c4Slazypassion 6747ad3c4Slazypassion use crate::binemit::CodeOffset; 7747ad3c4Slazypassion use crate::entity::{PrimaryMap, SecondaryMap}; 8747ad3c4Slazypassion use crate::ir; 9747ad3c4Slazypassion use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature}; 10747ad3c4Slazypassion use crate::ir::{ 11c7b4b98cSSean Stangl Ebb, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable, 12*c360007bSRyan Hunt JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData, 13747ad3c4Slazypassion }; 14d804ab8bSiximeow use crate::ir::{EbbOffsets, FrameLayout, InstEncodings, SourceLocs, StackSlots, ValueLocations}; 15747ad3c4Slazypassion use crate::ir::{JumpTableOffsets, JumpTables}; 16747ad3c4Slazypassion use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa}; 17bb87f1a5SNicolas B. Pierron use crate::regalloc::{EntryRegDiversions, RegDiversions}; 188f95c517SYury Delendik use crate::value_label::ValueLabelsRanges; 19747ad3c4Slazypassion use crate::write::write_function; 20747ad3c4Slazypassion use core::fmt; 21747ad3c4Slazypassion 22747ad3c4Slazypassion /// A function. 23747ad3c4Slazypassion /// 24747ad3c4Slazypassion /// Functions can be cloned, but it is not a very fast operation. 25747ad3c4Slazypassion /// The clone will have all the same entity numbers as the original. 26747ad3c4Slazypassion #[derive(Clone)] 27747ad3c4Slazypassion pub struct Function { 28747ad3c4Slazypassion /// Name of this function. Mostly used by `.clif` files. 29747ad3c4Slazypassion pub name: ExternalName, 30747ad3c4Slazypassion 31747ad3c4Slazypassion /// Signature of this function. 32747ad3c4Slazypassion pub signature: Signature, 33747ad3c4Slazypassion 34a4948340SNick Fitzgerald /// The old signature of this function, before the most recent legalization, 35a4948340SNick Fitzgerald /// if any. 36a4948340SNick Fitzgerald pub old_signature: Option<Signature>, 37a4948340SNick Fitzgerald 38747ad3c4Slazypassion /// Stack slots allocated in this function. 39747ad3c4Slazypassion pub stack_slots: StackSlots, 40747ad3c4Slazypassion 41747ad3c4Slazypassion /// Global values referenced. 42747ad3c4Slazypassion pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>, 43747ad3c4Slazypassion 44747ad3c4Slazypassion /// Heaps referenced. 45747ad3c4Slazypassion pub heaps: PrimaryMap<ir::Heap, ir::HeapData>, 46747ad3c4Slazypassion 47747ad3c4Slazypassion /// Tables referenced. 48747ad3c4Slazypassion pub tables: PrimaryMap<ir::Table, ir::TableData>, 49747ad3c4Slazypassion 50747ad3c4Slazypassion /// Jump tables used in this function. 51747ad3c4Slazypassion pub jump_tables: JumpTables, 52747ad3c4Slazypassion 53747ad3c4Slazypassion /// Data flow graph containing the primary definition of all instructions, EBBs and values. 54747ad3c4Slazypassion pub dfg: DataFlowGraph, 55747ad3c4Slazypassion 56747ad3c4Slazypassion /// Layout of EBBs and instructions in the function body. 57747ad3c4Slazypassion pub layout: Layout, 58747ad3c4Slazypassion 59747ad3c4Slazypassion /// Encoding recipe and bits for the legal instructions. 60747ad3c4Slazypassion /// Illegal instructions have the `Encoding::default()` value. 61747ad3c4Slazypassion pub encodings: InstEncodings, 62747ad3c4Slazypassion 63747ad3c4Slazypassion /// Location assigned to every value. 64747ad3c4Slazypassion pub locations: ValueLocations, 65747ad3c4Slazypassion 66bb87f1a5SNicolas B. Pierron /// Non-default locations assigned to value at the entry of basic blocks. 67bb87f1a5SNicolas B. Pierron /// 68bb87f1a5SNicolas B. Pierron /// At the entry of each basic block, we might have values which are not in their default 69bb87f1a5SNicolas B. Pierron /// ValueLocation. This field records these register-to-register moves as Diversions. 70bb87f1a5SNicolas B. Pierron pub entry_diversions: EntryRegDiversions, 71bb87f1a5SNicolas B. Pierron 72747ad3c4Slazypassion /// Code offsets of the EBB headers. 73747ad3c4Slazypassion /// 74747ad3c4Slazypassion /// This information is only transiently available after the `binemit::relax_branches` function 75747ad3c4Slazypassion /// computes it, and it can easily be recomputed by calling that function. It is not included 76747ad3c4Slazypassion /// in the textual IR format. 77747ad3c4Slazypassion pub offsets: EbbOffsets, 78747ad3c4Slazypassion 79747ad3c4Slazypassion /// Code offsets of Jump Table headers. 80747ad3c4Slazypassion pub jt_offsets: JumpTableOffsets, 81747ad3c4Slazypassion 82747ad3c4Slazypassion /// Source locations. 83747ad3c4Slazypassion /// 84747ad3c4Slazypassion /// Track the original source location for each instruction. The source locations are not 85747ad3c4Slazypassion /// interpreted by Cranelift, only preserved. 86747ad3c4Slazypassion pub srclocs: SourceLocs, 878923bac7SPeter Huene 888923bac7SPeter Huene /// Instruction that marks the end (inclusive) of the function's prologue. 898923bac7SPeter Huene /// 908923bac7SPeter Huene /// This is used for some calling conventions to track the end of unwind information. 918923bac7SPeter Huene pub prologue_end: Option<Inst>, 92d804ab8bSiximeow 93d804ab8bSiximeow /// Frame layout for the instructions. 94d804ab8bSiximeow /// 95d804ab8bSiximeow /// The stack unwinding requires to have information about which registers and where they 96d804ab8bSiximeow /// are saved in the frame. This information is created during the prologue and epilogue 97d804ab8bSiximeow /// passes. 98d804ab8bSiximeow pub frame_layout: Option<FrameLayout>, 99747ad3c4Slazypassion } 100747ad3c4Slazypassion 101747ad3c4Slazypassion impl Function { 102747ad3c4Slazypassion /// Create a function with the given name and signature. 103747ad3c4Slazypassion pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self { 104747ad3c4Slazypassion Self { 105747ad3c4Slazypassion name, 106747ad3c4Slazypassion signature: sig, 107a4948340SNick Fitzgerald old_signature: None, 108747ad3c4Slazypassion stack_slots: StackSlots::new(), 109747ad3c4Slazypassion global_values: PrimaryMap::new(), 110747ad3c4Slazypassion heaps: PrimaryMap::new(), 111747ad3c4Slazypassion tables: PrimaryMap::new(), 112747ad3c4Slazypassion jump_tables: PrimaryMap::new(), 113747ad3c4Slazypassion dfg: DataFlowGraph::new(), 114747ad3c4Slazypassion layout: Layout::new(), 115747ad3c4Slazypassion encodings: SecondaryMap::new(), 116747ad3c4Slazypassion locations: SecondaryMap::new(), 117bb87f1a5SNicolas B. Pierron entry_diversions: EntryRegDiversions::new(), 118747ad3c4Slazypassion offsets: SecondaryMap::new(), 119747ad3c4Slazypassion jt_offsets: SecondaryMap::new(), 120747ad3c4Slazypassion srclocs: SecondaryMap::new(), 1218923bac7SPeter Huene prologue_end: None, 122d804ab8bSiximeow frame_layout: None, 123747ad3c4Slazypassion } 124747ad3c4Slazypassion } 125747ad3c4Slazypassion 126747ad3c4Slazypassion /// Clear all data structures in this function. 127747ad3c4Slazypassion pub fn clear(&mut self) { 128747ad3c4Slazypassion self.signature.clear(CallConv::Fast); 129747ad3c4Slazypassion self.stack_slots.clear(); 130747ad3c4Slazypassion self.global_values.clear(); 131747ad3c4Slazypassion self.heaps.clear(); 132747ad3c4Slazypassion self.tables.clear(); 133747ad3c4Slazypassion self.jump_tables.clear(); 134747ad3c4Slazypassion self.dfg.clear(); 135747ad3c4Slazypassion self.layout.clear(); 136747ad3c4Slazypassion self.encodings.clear(); 137747ad3c4Slazypassion self.locations.clear(); 138bb87f1a5SNicolas B. Pierron self.entry_diversions.clear(); 139747ad3c4Slazypassion self.offsets.clear(); 140ea9ee202SAndrew Brown self.jt_offsets.clear(); 141747ad3c4Slazypassion self.srclocs.clear(); 1428923bac7SPeter Huene self.prologue_end = None; 143d804ab8bSiximeow self.frame_layout = None; 144747ad3c4Slazypassion } 145747ad3c4Slazypassion 146747ad3c4Slazypassion /// Create a new empty, anonymous function with a Fast calling convention. 147747ad3c4Slazypassion pub fn new() -> Self { 148747ad3c4Slazypassion Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast)) 149747ad3c4Slazypassion } 150747ad3c4Slazypassion 151747ad3c4Slazypassion /// Creates a jump table in the function, to be used by `br_table` instructions. 152747ad3c4Slazypassion pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { 153747ad3c4Slazypassion self.jump_tables.push(data) 154747ad3c4Slazypassion } 155747ad3c4Slazypassion 156747ad3c4Slazypassion /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and 157747ad3c4Slazypassion /// `stack_addr` instructions. 158747ad3c4Slazypassion pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot { 159747ad3c4Slazypassion self.stack_slots.push(data) 160747ad3c4Slazypassion } 161747ad3c4Slazypassion 162747ad3c4Slazypassion /// Adds a signature which can later be used to declare an external function import. 163747ad3c4Slazypassion pub fn import_signature(&mut self, signature: Signature) -> SigRef { 164747ad3c4Slazypassion self.dfg.signatures.push(signature) 165747ad3c4Slazypassion } 166747ad3c4Slazypassion 167747ad3c4Slazypassion /// Declare an external function import. 168747ad3c4Slazypassion pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { 169747ad3c4Slazypassion self.dfg.ext_funcs.push(data) 170747ad3c4Slazypassion } 171747ad3c4Slazypassion 172747ad3c4Slazypassion /// Declares a global value accessible to the function. 173747ad3c4Slazypassion pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { 174747ad3c4Slazypassion self.global_values.push(data) 175747ad3c4Slazypassion } 176747ad3c4Slazypassion 177747ad3c4Slazypassion /// Declares a heap accessible to the function. 178747ad3c4Slazypassion pub fn create_heap(&mut self, data: HeapData) -> Heap { 179747ad3c4Slazypassion self.heaps.push(data) 180747ad3c4Slazypassion } 181747ad3c4Slazypassion 182747ad3c4Slazypassion /// Declares a table accessible to the function. 183747ad3c4Slazypassion pub fn create_table(&mut self, data: TableData) -> Table { 184747ad3c4Slazypassion self.tables.push(data) 185747ad3c4Slazypassion } 186747ad3c4Slazypassion 187747ad3c4Slazypassion /// Return an object that can display this function with correct ISA-specific annotations. 188d7d48d5cSBenjamin Bouvier pub fn display<'a, I: Into<Option<&'a dyn TargetIsa>>>( 189d7d48d5cSBenjamin Bouvier &'a self, 190d7d48d5cSBenjamin Bouvier isa: I, 191d7d48d5cSBenjamin Bouvier ) -> DisplayFunction<'a> { 1928f95c517SYury Delendik DisplayFunction(self, isa.into().into()) 1938f95c517SYury Delendik } 1948f95c517SYury Delendik 1958f95c517SYury Delendik /// Return an object that can display this function with correct ISA-specific annotations. 1968f95c517SYury Delendik pub fn display_with<'a>( 1978f95c517SYury Delendik &'a self, 1988f95c517SYury Delendik annotations: DisplayFunctionAnnotations<'a>, 1998f95c517SYury Delendik ) -> DisplayFunction<'a> { 2008f95c517SYury Delendik DisplayFunction(self, annotations) 201747ad3c4Slazypassion } 202747ad3c4Slazypassion 203747ad3c4Slazypassion /// Find a presumed unique special-purpose function parameter value. 204747ad3c4Slazypassion /// 205747ad3c4Slazypassion /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists. 206747ad3c4Slazypassion pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { 207747ad3c4Slazypassion let entry = self.layout.entry_block().expect("Function is empty"); 208747ad3c4Slazypassion self.signature 209747ad3c4Slazypassion .special_param_index(purpose) 210747ad3c4Slazypassion .map(|i| self.dfg.ebb_params(entry)[i]) 211747ad3c4Slazypassion } 212747ad3c4Slazypassion 213747ad3c4Slazypassion /// Get an iterator over the instructions in `ebb`, including offsets and encoded instruction 214747ad3c4Slazypassion /// sizes. 215747ad3c4Slazypassion /// 216747ad3c4Slazypassion /// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes 217747ad3c4Slazypassion /// from the beginning of the function to the instruction, and `size` is the size of the 218747ad3c4Slazypassion /// instruction in bytes, or 0 for unencoded instructions. 219747ad3c4Slazypassion /// 220747ad3c4Slazypassion /// This function can only be used after the code layout has been computed by the 221747ad3c4Slazypassion /// `binemit::relax_branches()` function. 222747ad3c4Slazypassion pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> { 223747ad3c4Slazypassion assert!( 224747ad3c4Slazypassion !self.offsets.is_empty(), 225747ad3c4Slazypassion "Code layout must be computed first" 226747ad3c4Slazypassion ); 227bb87f1a5SNicolas B. Pierron let mut divert = RegDiversions::new(); 228bb87f1a5SNicolas B. Pierron divert.at_ebb(&self.entry_diversions, ebb); 229747ad3c4Slazypassion InstOffsetIter { 230747ad3c4Slazypassion encinfo: encinfo.clone(), 231747ad3c4Slazypassion func: self, 232bb87f1a5SNicolas B. Pierron divert, 233747ad3c4Slazypassion encodings: &self.encodings, 234747ad3c4Slazypassion offset: self.offsets[ebb], 235747ad3c4Slazypassion iter: self.layout.ebb_insts(ebb), 236747ad3c4Slazypassion } 237747ad3c4Slazypassion } 238747ad3c4Slazypassion 239747ad3c4Slazypassion /// Wrapper around `encode` which assigns `inst` the resulting encoding. 240d7d48d5cSBenjamin Bouvier pub fn update_encoding(&mut self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<(), Legalize> { 241747ad3c4Slazypassion self.encode(inst, isa).map(|e| self.encodings[inst] = e) 242747ad3c4Slazypassion } 243747ad3c4Slazypassion 244747ad3c4Slazypassion /// Wrapper around `TargetIsa::encode` for encoding an existing instruction 245747ad3c4Slazypassion /// in the `Function`. 246d7d48d5cSBenjamin Bouvier pub fn encode(&self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<Encoding, Legalize> { 247747ad3c4Slazypassion isa.encode(&self, &self.dfg[inst], self.dfg.ctrl_typevar(inst)) 248747ad3c4Slazypassion } 2498f95c517SYury Delendik 2508f95c517SYury Delendik /// Starts collection of debug information. 2518f95c517SYury Delendik pub fn collect_debug_info(&mut self) { 2528f95c517SYury Delendik self.dfg.collect_debug_info(); 253bd881554SYury Delendik self.collect_frame_layout_info(); 254bd881554SYury Delendik } 255bd881554SYury Delendik 256bd881554SYury Delendik /// Starts collection of frame layout information. 257bd881554SYury Delendik pub fn collect_frame_layout_info(&mut self) { 258d804ab8bSiximeow self.frame_layout = Some(FrameLayout::new()); 2598f95c517SYury Delendik } 2608efaeec5SSean Stangl 261c7b4b98cSSean Stangl /// Changes the destination of a jump or branch instruction. 262c7b4b98cSSean Stangl /// Does nothing if called with a non-jump or non-branch instruction. 263c7b4b98cSSean Stangl pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Ebb) { 264c7b4b98cSSean Stangl match self.dfg[inst].branch_destination_mut() { 265c7b4b98cSSean Stangl None => (), 266c7b4b98cSSean Stangl Some(inst_dest) => *inst_dest = new_dest, 267c7b4b98cSSean Stangl } 268c7b4b98cSSean Stangl } 269c7b4b98cSSean Stangl 2708efaeec5SSean Stangl /// Checks that the specified EBB can be encoded as a basic block. 2718efaeec5SSean Stangl /// 2728efaeec5SSean Stangl /// On error, returns the first invalid instruction and an error message. 2738efaeec5SSean Stangl pub fn is_ebb_basic(&self, ebb: Ebb) -> Result<(), (Inst, &'static str)> { 2748efaeec5SSean Stangl let dfg = &self.dfg; 2758efaeec5SSean Stangl let inst_iter = self.layout.ebb_insts(ebb); 2768efaeec5SSean Stangl 2778efaeec5SSean Stangl // Ignore all instructions prior to the first branch. 2788efaeec5SSean Stangl let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch()); 2798efaeec5SSean Stangl 2808efaeec5SSean Stangl // A conditional branch is permitted in a basic block only when followed 2818efaeec5SSean Stangl // by a terminal jump or fallthrough instruction. 2828efaeec5SSean Stangl if let Some(_branch) = inst_iter.next() { 2838efaeec5SSean Stangl if let Some(next) = inst_iter.next() { 2848efaeec5SSean Stangl match dfg[next].opcode() { 2858efaeec5SSean Stangl Opcode::Fallthrough | Opcode::Jump => (), 2868efaeec5SSean Stangl _ => return Err((next, "post-branch instruction not fallthrough or jump")), 2878efaeec5SSean Stangl } 2888efaeec5SSean Stangl } 2898efaeec5SSean Stangl } 2908efaeec5SSean Stangl 2918efaeec5SSean Stangl Ok(()) 2928efaeec5SSean Stangl } 293143cb014SBenjamin Bouvier 294143cb014SBenjamin Bouvier /// Returns true if the function is function that doesn't call any other functions. This is not 295143cb014SBenjamin Bouvier /// to be confused with a "leaf function" in Windows terminology. 296143cb014SBenjamin Bouvier pub fn is_leaf(&self) -> bool { 297143cb014SBenjamin Bouvier // Conservative result: if there's at least one function signature referenced in this 298143cb014SBenjamin Bouvier // function, assume it may call. 299143cb014SBenjamin Bouvier !self.dfg.signatures.is_empty() 300143cb014SBenjamin Bouvier } 3018f95c517SYury Delendik } 3028f95c517SYury Delendik 3038f95c517SYury Delendik /// Additional annotations for function display. 304f856b124SMark McCaskey #[derive(Default)] 3058f95c517SYury Delendik pub struct DisplayFunctionAnnotations<'a> { 3068f95c517SYury Delendik /// Enable ISA annotations. 307d7d48d5cSBenjamin Bouvier pub isa: Option<&'a dyn TargetIsa>, 3088f95c517SYury Delendik 3098f95c517SYury Delendik /// Enable value labels annotations. 3108f95c517SYury Delendik pub value_ranges: Option<&'a ValueLabelsRanges>, 3118f95c517SYury Delendik } 3128f95c517SYury Delendik 313d7d48d5cSBenjamin Bouvier impl<'a> From<Option<&'a dyn TargetIsa>> for DisplayFunctionAnnotations<'a> { 314d7d48d5cSBenjamin Bouvier fn from(isa: Option<&'a dyn TargetIsa>) -> DisplayFunctionAnnotations { 3158f95c517SYury Delendik DisplayFunctionAnnotations { 3168f95c517SYury Delendik isa, 3178f95c517SYury Delendik value_ranges: None, 3188f95c517SYury Delendik } 3198f95c517SYury Delendik } 320747ad3c4Slazypassion } 321747ad3c4Slazypassion 322747ad3c4Slazypassion /// Wrapper type capable of displaying a `Function` with correct ISA annotations. 3238f95c517SYury Delendik pub struct DisplayFunction<'a>(&'a Function, DisplayFunctionAnnotations<'a>); 324747ad3c4Slazypassion 325747ad3c4Slazypassion impl<'a> fmt::Display for DisplayFunction<'a> { 326747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 3278f95c517SYury Delendik write_function(fmt, self.0, &self.1) 328747ad3c4Slazypassion } 329747ad3c4Slazypassion } 330747ad3c4Slazypassion 331747ad3c4Slazypassion impl fmt::Display for Function { 332747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 3338f95c517SYury Delendik write_function(fmt, self, &DisplayFunctionAnnotations::default()) 334747ad3c4Slazypassion } 335747ad3c4Slazypassion } 336747ad3c4Slazypassion 337747ad3c4Slazypassion impl fmt::Debug for Function { 338747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 3398f95c517SYury Delendik write_function(fmt, self, &DisplayFunctionAnnotations::default()) 340747ad3c4Slazypassion } 341747ad3c4Slazypassion } 342747ad3c4Slazypassion 343747ad3c4Slazypassion /// Iterator returning instruction offsets and sizes: `(offset, inst, size)`. 344747ad3c4Slazypassion pub struct InstOffsetIter<'a> { 345747ad3c4Slazypassion encinfo: EncInfo, 346747ad3c4Slazypassion divert: RegDiversions, 347747ad3c4Slazypassion func: &'a Function, 348747ad3c4Slazypassion encodings: &'a InstEncodings, 349747ad3c4Slazypassion offset: CodeOffset, 350747ad3c4Slazypassion iter: ir::layout::Insts<'a>, 351747ad3c4Slazypassion } 352747ad3c4Slazypassion 353747ad3c4Slazypassion impl<'a> Iterator for InstOffsetIter<'a> { 354747ad3c4Slazypassion type Item = (CodeOffset, ir::Inst, CodeOffset); 355747ad3c4Slazypassion 356747ad3c4Slazypassion fn next(&mut self) -> Option<Self::Item> { 357747ad3c4Slazypassion self.iter.next().map(|inst| { 358747ad3c4Slazypassion self.divert.apply(&self.func.dfg[inst]); 359747ad3c4Slazypassion let byte_size = 360747ad3c4Slazypassion self.encinfo 361747ad3c4Slazypassion .byte_size(self.encodings[inst], inst, &self.divert, self.func); 362747ad3c4Slazypassion let offset = self.offset; 363747ad3c4Slazypassion self.offset += byte_size; 364747ad3c4Slazypassion (offset, inst, byte_size) 365747ad3c4Slazypassion }) 366747ad3c4Slazypassion } 367747ad3c4Slazypassion } 368