1747ad3c4Slazypassion //! Intermediate representation of a function. 2747ad3c4Slazypassion //! 3832666c4SRyan Hunt //! The `Function` struct defined in this module owns all of its basic blocks and 4747ad3c4Slazypassion //! instructions. 5747ad3c4Slazypassion 6747ad3c4Slazypassion use crate::entity::{PrimaryMap, SecondaryMap}; 7747ad3c4Slazypassion use crate::ir; 82db3b5b9Sbjorn3 use crate::ir::JumpTables; 9747ad3c4Slazypassion use crate::ir::{ 10855a6374SY-Nak instructions::BranchInfo, Block, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, 11855a6374SY-Nak HeapData, Inst, InstructionData, JumpTable, JumpTableData, Opcode, SigRef, StackSlot, 12855a6374SY-Nak StackSlotData, Table, TableData, 13747ad3c4Slazypassion }; 14832666c4SRyan Hunt use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature}; 152db3b5b9Sbjorn3 use crate::ir::{SourceLocs, StackSlots}; 1643a86f14SBenjamin Bouvier use crate::isa::CallConv; 178f95c517SYury Delendik use crate::value_label::ValueLabelsRanges; 18747ad3c4Slazypassion use crate::write::write_function; 19a0c2276eSbjorn3 #[cfg(feature = "enable-serde")] 20a0c2276eSbjorn3 use alloc::string::String; 21747ad3c4Slazypassion use core::fmt; 22747ad3c4Slazypassion 232fc964eaSbjorn3 #[cfg(feature = "enable-serde")] 24a0c2276eSbjorn3 use serde::de::{Deserializer, Error}; 25a0c2276eSbjorn3 #[cfg(feature = "enable-serde")] 26a0c2276eSbjorn3 use serde::ser::Serializer; 27a0c2276eSbjorn3 #[cfg(feature = "enable-serde")] 282fc964eaSbjorn3 use serde::{Deserialize, Serialize}; 292fc964eaSbjorn3 30a0c2276eSbjorn3 /// A version marker used to ensure that serialized clif ir is never deserialized with a 31a0c2276eSbjorn3 /// different version of Cranelift. 32a0c2276eSbjorn3 #[derive(Copy, Clone, Debug)] 33a0c2276eSbjorn3 pub struct VersionMarker; 34a0c2276eSbjorn3 35a0c2276eSbjorn3 #[cfg(feature = "enable-serde")] 36a0c2276eSbjorn3 impl Serialize for VersionMarker { 37a0c2276eSbjorn3 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 38a0c2276eSbjorn3 where 39a0c2276eSbjorn3 S: Serializer, 40a0c2276eSbjorn3 { 41a0c2276eSbjorn3 crate::VERSION.serialize(serializer) 42a0c2276eSbjorn3 } 43a0c2276eSbjorn3 } 44a0c2276eSbjorn3 45a0c2276eSbjorn3 #[cfg(feature = "enable-serde")] 46a0c2276eSbjorn3 impl<'de> Deserialize<'de> for VersionMarker { 47a0c2276eSbjorn3 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 48a0c2276eSbjorn3 where 49a0c2276eSbjorn3 D: Deserializer<'de>, 50a0c2276eSbjorn3 { 51a0c2276eSbjorn3 let version = String::deserialize(deserializer)?; 52a0c2276eSbjorn3 if version != crate::VERSION { 53a0c2276eSbjorn3 return Err(D::Error::custom(&format!( 54a0c2276eSbjorn3 "Expected a clif ir function for version {}, found one for version {}", 55a0c2276eSbjorn3 crate::VERSION, 56a0c2276eSbjorn3 version, 57a0c2276eSbjorn3 ))); 58a0c2276eSbjorn3 } 59a0c2276eSbjorn3 Ok(VersionMarker) 60a0c2276eSbjorn3 } 61a0c2276eSbjorn3 } 62a0c2276eSbjorn3 63747ad3c4Slazypassion /// 64747ad3c4Slazypassion /// Functions can be cloned, but it is not a very fast operation. 65747ad3c4Slazypassion /// The clone will have all the same entity numbers as the original. 66747ad3c4Slazypassion #[derive(Clone)] 672fc964eaSbjorn3 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 68747ad3c4Slazypassion pub struct Function { 69a0c2276eSbjorn3 /// A version marker used to ensure that serialized clif ir is never deserialized with a 70a0c2276eSbjorn3 /// different version of Cranelift. 71a0c2276eSbjorn3 // Note: This must be the first field to ensure that Serde will deserialize it before 72a0c2276eSbjorn3 // attempting to deserialize other fields that are potentially changed between versions. 73a0c2276eSbjorn3 pub version_marker: VersionMarker, 74a0c2276eSbjorn3 75747ad3c4Slazypassion /// Name of this function. Mostly used by `.clif` files. 76747ad3c4Slazypassion pub name: ExternalName, 77747ad3c4Slazypassion 78747ad3c4Slazypassion /// Signature of this function. 79747ad3c4Slazypassion pub signature: Signature, 80747ad3c4Slazypassion 81747ad3c4Slazypassion /// Stack slots allocated in this function. 82747ad3c4Slazypassion pub stack_slots: StackSlots, 83747ad3c4Slazypassion 84747ad3c4Slazypassion /// Global values referenced. 85747ad3c4Slazypassion pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>, 86747ad3c4Slazypassion 87747ad3c4Slazypassion /// Heaps referenced. 88747ad3c4Slazypassion pub heaps: PrimaryMap<ir::Heap, ir::HeapData>, 89747ad3c4Slazypassion 90747ad3c4Slazypassion /// Tables referenced. 91747ad3c4Slazypassion pub tables: PrimaryMap<ir::Table, ir::TableData>, 92747ad3c4Slazypassion 93747ad3c4Slazypassion /// Jump tables used in this function. 94747ad3c4Slazypassion pub jump_tables: JumpTables, 95747ad3c4Slazypassion 96832666c4SRyan Hunt /// Data flow graph containing the primary definition of all instructions, blocks and values. 97747ad3c4Slazypassion pub dfg: DataFlowGraph, 98747ad3c4Slazypassion 99832666c4SRyan Hunt /// Layout of blocks and instructions in the function body. 100747ad3c4Slazypassion pub layout: Layout, 101747ad3c4Slazypassion 102747ad3c4Slazypassion /// Source locations. 103747ad3c4Slazypassion /// 104747ad3c4Slazypassion /// Track the original source location for each instruction. The source locations are not 105747ad3c4Slazypassion /// interpreted by Cranelift, only preserved. 106747ad3c4Slazypassion pub srclocs: SourceLocs, 1078923bac7SPeter Huene 108c9a0ba81SAlex Crichton /// An optional global value which represents an expression evaluating to 109c9a0ba81SAlex Crichton /// the stack limit for this function. This `GlobalValue` will be 110c9a0ba81SAlex Crichton /// interpreted in the prologue, if necessary, to insert a stack check to 111c9a0ba81SAlex Crichton /// ensure that a trap happens if the stack pointer goes below the 112c9a0ba81SAlex Crichton /// threshold specified here. 113c9a0ba81SAlex Crichton pub stack_limit: Option<ir::GlobalValue>, 114747ad3c4Slazypassion } 115747ad3c4Slazypassion 116747ad3c4Slazypassion impl Function { 117747ad3c4Slazypassion /// Create a function with the given name and signature. 118747ad3c4Slazypassion pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self { 119747ad3c4Slazypassion Self { 120a0c2276eSbjorn3 version_marker: VersionMarker, 121747ad3c4Slazypassion name, 122747ad3c4Slazypassion signature: sig, 123747ad3c4Slazypassion stack_slots: StackSlots::new(), 124747ad3c4Slazypassion global_values: PrimaryMap::new(), 125747ad3c4Slazypassion heaps: PrimaryMap::new(), 126747ad3c4Slazypassion tables: PrimaryMap::new(), 127747ad3c4Slazypassion jump_tables: PrimaryMap::new(), 128747ad3c4Slazypassion dfg: DataFlowGraph::new(), 129747ad3c4Slazypassion layout: Layout::new(), 130747ad3c4Slazypassion srclocs: SecondaryMap::new(), 131c9a0ba81SAlex Crichton stack_limit: None, 132747ad3c4Slazypassion } 133747ad3c4Slazypassion } 134747ad3c4Slazypassion 135747ad3c4Slazypassion /// Clear all data structures in this function. 136747ad3c4Slazypassion pub fn clear(&mut self) { 137747ad3c4Slazypassion self.signature.clear(CallConv::Fast); 138747ad3c4Slazypassion self.stack_slots.clear(); 139747ad3c4Slazypassion self.global_values.clear(); 140747ad3c4Slazypassion self.heaps.clear(); 141747ad3c4Slazypassion self.tables.clear(); 142747ad3c4Slazypassion self.jump_tables.clear(); 143747ad3c4Slazypassion self.dfg.clear(); 144747ad3c4Slazypassion self.layout.clear(); 145747ad3c4Slazypassion self.srclocs.clear(); 146c9a0ba81SAlex Crichton self.stack_limit = None; 147747ad3c4Slazypassion } 148747ad3c4Slazypassion 149747ad3c4Slazypassion /// Create a new empty, anonymous function with a Fast calling convention. 150747ad3c4Slazypassion pub fn new() -> Self { 151747ad3c4Slazypassion Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast)) 152747ad3c4Slazypassion } 153747ad3c4Slazypassion 154747ad3c4Slazypassion /// Creates a jump table in the function, to be used by `br_table` instructions. 155747ad3c4Slazypassion pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { 156747ad3c4Slazypassion self.jump_tables.push(data) 157747ad3c4Slazypassion } 158747ad3c4Slazypassion 159747ad3c4Slazypassion /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and 160747ad3c4Slazypassion /// `stack_addr` instructions. 161747ad3c4Slazypassion pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot { 162747ad3c4Slazypassion self.stack_slots.push(data) 163747ad3c4Slazypassion } 164747ad3c4Slazypassion 165747ad3c4Slazypassion /// Adds a signature which can later be used to declare an external function import. 166747ad3c4Slazypassion pub fn import_signature(&mut self, signature: Signature) -> SigRef { 167747ad3c4Slazypassion self.dfg.signatures.push(signature) 168747ad3c4Slazypassion } 169747ad3c4Slazypassion 170747ad3c4Slazypassion /// Declare an external function import. 171747ad3c4Slazypassion pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { 172747ad3c4Slazypassion self.dfg.ext_funcs.push(data) 173747ad3c4Slazypassion } 174747ad3c4Slazypassion 175747ad3c4Slazypassion /// Declares a global value accessible to the function. 176747ad3c4Slazypassion pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { 177747ad3c4Slazypassion self.global_values.push(data) 178747ad3c4Slazypassion } 179747ad3c4Slazypassion 180747ad3c4Slazypassion /// Declares a heap accessible to the function. 181747ad3c4Slazypassion pub fn create_heap(&mut self, data: HeapData) -> Heap { 182747ad3c4Slazypassion self.heaps.push(data) 183747ad3c4Slazypassion } 184747ad3c4Slazypassion 185747ad3c4Slazypassion /// Declares a table accessible to the function. 186747ad3c4Slazypassion pub fn create_table(&mut self, data: TableData) -> Table { 187747ad3c4Slazypassion self.tables.push(data) 188747ad3c4Slazypassion } 189747ad3c4Slazypassion 190747ad3c4Slazypassion /// Return an object that can display this function with correct ISA-specific annotations. 19143a86f14SBenjamin Bouvier pub fn display(&self) -> DisplayFunction<'_> { 19243a86f14SBenjamin Bouvier DisplayFunction(self, Default::default()) 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) 210832666c4SRyan Hunt .map(|i| self.dfg.block_params(entry)[i]) 211747ad3c4Slazypassion } 212747ad3c4Slazypassion 2138f95c517SYury Delendik /// Starts collection of debug information. 2148f95c517SYury Delendik pub fn collect_debug_info(&mut self) { 2158f95c517SYury Delendik self.dfg.collect_debug_info(); 2168f95c517SYury Delendik } 2178efaeec5SSean Stangl 218c7b4b98cSSean Stangl /// Changes the destination of a jump or branch instruction. 219c7b4b98cSSean Stangl /// Does nothing if called with a non-jump or non-branch instruction. 220855a6374SY-Nak /// 221855a6374SY-Nak /// Note that this method ignores multi-destination branches like `br_table`. 222832666c4SRyan Hunt pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) { 223c7b4b98cSSean Stangl match self.dfg[inst].branch_destination_mut() { 224c7b4b98cSSean Stangl None => (), 225c7b4b98cSSean Stangl Some(inst_dest) => *inst_dest = new_dest, 226c7b4b98cSSean Stangl } 227c7b4b98cSSean Stangl } 228c7b4b98cSSean Stangl 229855a6374SY-Nak /// Rewrite the branch destination to `new_dest` if the destination matches `old_dest`. 230855a6374SY-Nak /// Does nothing if called with a non-jump or non-branch instruction. 231855a6374SY-Nak /// 232855a6374SY-Nak /// Unlike [change_branch_destination](Function::change_branch_destination), this method rewrite the destinations of 233855a6374SY-Nak /// multi-destination branches like `br_table`. 234855a6374SY-Nak pub fn rewrite_branch_destination(&mut self, inst: Inst, old_dest: Block, new_dest: Block) { 235855a6374SY-Nak match self.dfg.analyze_branch(inst) { 236855a6374SY-Nak BranchInfo::SingleDest(dest, ..) => { 237855a6374SY-Nak if dest == old_dest { 238855a6374SY-Nak self.change_branch_destination(inst, new_dest); 239855a6374SY-Nak } 240855a6374SY-Nak } 241855a6374SY-Nak 242855a6374SY-Nak BranchInfo::Table(table, default_dest) => { 243855a6374SY-Nak self.jump_tables[table].iter_mut().for_each(|entry| { 244855a6374SY-Nak if *entry == old_dest { 245855a6374SY-Nak *entry = new_dest; 246855a6374SY-Nak } 247855a6374SY-Nak }); 248855a6374SY-Nak 249855a6374SY-Nak if default_dest == Some(old_dest) { 250855a6374SY-Nak match &mut self.dfg[inst] { 251855a6374SY-Nak InstructionData::BranchTable { destination, .. } => { 252855a6374SY-Nak *destination = new_dest; 253855a6374SY-Nak } 254855a6374SY-Nak _ => panic!( 255855a6374SY-Nak "Unexpected instruction {} having default destination", 25643a86f14SBenjamin Bouvier self.dfg.display_inst(inst) 257855a6374SY-Nak ), 258855a6374SY-Nak } 259855a6374SY-Nak } 260855a6374SY-Nak } 261855a6374SY-Nak 262855a6374SY-Nak BranchInfo::NotABranch => {} 263855a6374SY-Nak } 264855a6374SY-Nak } 265855a6374SY-Nak 266832666c4SRyan Hunt /// Checks that the specified block can be encoded as a basic block. 2678efaeec5SSean Stangl /// 2688efaeec5SSean Stangl /// On error, returns the first invalid instruction and an error message. 269832666c4SRyan Hunt pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { 2708efaeec5SSean Stangl let dfg = &self.dfg; 271832666c4SRyan Hunt let inst_iter = self.layout.block_insts(block); 2728efaeec5SSean Stangl 2738efaeec5SSean Stangl // Ignore all instructions prior to the first branch. 2748efaeec5SSean Stangl let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch()); 2758efaeec5SSean Stangl 2768efaeec5SSean Stangl // A conditional branch is permitted in a basic block only when followed 277*1fd491daSbjorn3 // by a terminal jump instruction. 2788efaeec5SSean Stangl if let Some(_branch) = inst_iter.next() { 2798efaeec5SSean Stangl if let Some(next) = inst_iter.next() { 2808efaeec5SSean Stangl match dfg[next].opcode() { 281*1fd491daSbjorn3 Opcode::Jump => (), 282*1fd491daSbjorn3 _ => return Err((next, "post-branch instruction not jump")), 2838efaeec5SSean Stangl } 2848efaeec5SSean Stangl } 2858efaeec5SSean Stangl } 2868efaeec5SSean Stangl 2878efaeec5SSean Stangl Ok(()) 2888efaeec5SSean Stangl } 289143cb014SBenjamin Bouvier 290143cb014SBenjamin Bouvier /// Returns true if the function is function that doesn't call any other functions. This is not 291143cb014SBenjamin Bouvier /// to be confused with a "leaf function" in Windows terminology. 292143cb014SBenjamin Bouvier pub fn is_leaf(&self) -> bool { 293143cb014SBenjamin Bouvier // Conservative result: if there's at least one function signature referenced in this 29458e5a62cSY-Nak // function, assume it is not a leaf. 29558e5a62cSY-Nak self.dfg.signatures.is_empty() 296143cb014SBenjamin Bouvier } 297090d1c2dSNick Fitzgerald 298090d1c2dSNick Fitzgerald /// Replace the `dst` instruction's data with the `src` instruction's data 299090d1c2dSNick Fitzgerald /// and then remove `src`. 300090d1c2dSNick Fitzgerald /// 301090d1c2dSNick Fitzgerald /// `src` and its result values should not be used at all, as any uses would 302090d1c2dSNick Fitzgerald /// be left dangling after calling this method. 303090d1c2dSNick Fitzgerald /// 304090d1c2dSNick Fitzgerald /// `src` and `dst` must have the same number of resulting values, and 305090d1c2dSNick Fitzgerald /// `src`'s i^th value must have the same type as `dst`'s i^th value. 306090d1c2dSNick Fitzgerald pub fn transplant_inst(&mut self, dst: Inst, src: Inst) { 307090d1c2dSNick Fitzgerald debug_assert_eq!( 308090d1c2dSNick Fitzgerald self.dfg.inst_results(dst).len(), 309090d1c2dSNick Fitzgerald self.dfg.inst_results(src).len() 310090d1c2dSNick Fitzgerald ); 311090d1c2dSNick Fitzgerald debug_assert!(self 312090d1c2dSNick Fitzgerald .dfg 313090d1c2dSNick Fitzgerald .inst_results(dst) 314090d1c2dSNick Fitzgerald .iter() 315090d1c2dSNick Fitzgerald .zip(self.dfg.inst_results(src)) 316090d1c2dSNick Fitzgerald .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b))); 317090d1c2dSNick Fitzgerald 318090d1c2dSNick Fitzgerald self.dfg[dst] = self.dfg[src].clone(); 319090d1c2dSNick Fitzgerald self.layout.remove_inst(src); 320090d1c2dSNick Fitzgerald } 3212776074dSAfonso Bordado 3222776074dSAfonso Bordado /// Size occupied by all stack slots associated with this function. 3232776074dSAfonso Bordado /// 3242776074dSAfonso Bordado /// Does not include any padding necessary due to offsets 3252776074dSAfonso Bordado pub fn stack_size(&self) -> u32 { 3262776074dSAfonso Bordado self.stack_slots.values().map(|ss| ss.size).sum() 3272776074dSAfonso Bordado } 3288f95c517SYury Delendik } 3298f95c517SYury Delendik 3308f95c517SYury Delendik /// Additional annotations for function display. 331f856b124SMark McCaskey #[derive(Default)] 3328f95c517SYury Delendik pub struct DisplayFunctionAnnotations<'a> { 3338f95c517SYury Delendik /// Enable value labels annotations. 3348f95c517SYury Delendik pub value_ranges: Option<&'a ValueLabelsRanges>, 3358f95c517SYury Delendik } 3368f95c517SYury Delendik 337747ad3c4Slazypassion /// Wrapper type capable of displaying a `Function` with correct ISA annotations. 3388f95c517SYury Delendik pub struct DisplayFunction<'a>(&'a Function, DisplayFunctionAnnotations<'a>); 339747ad3c4Slazypassion 340747ad3c4Slazypassion impl<'a> fmt::Display for DisplayFunction<'a> { 341747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 34243a86f14SBenjamin Bouvier write_function(fmt, self.0) 343747ad3c4Slazypassion } 344747ad3c4Slazypassion } 345747ad3c4Slazypassion 346747ad3c4Slazypassion impl fmt::Display for Function { 347747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 34843a86f14SBenjamin Bouvier write_function(fmt, self) 349747ad3c4Slazypassion } 350747ad3c4Slazypassion } 351747ad3c4Slazypassion 352747ad3c4Slazypassion impl fmt::Debug for Function { 353747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 35443a86f14SBenjamin Bouvier write_function(fmt, self) 355747ad3c4Slazypassion } 356747ad3c4Slazypassion } 357