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::binemit::CodeOffset; 7747ad3c4Slazypassion use crate::entity::{PrimaryMap, SecondaryMap}; 8747ad3c4Slazypassion use crate::ir; 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 }; 14f7e9f86bSPeter Huene use crate::ir::{BlockOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations}; 15832666c4SRyan Hunt use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature}; 16747ad3c4Slazypassion use crate::ir::{JumpTableOffsets, JumpTables}; 17747ad3c4Slazypassion use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa}; 18bb87f1a5SNicolas B. Pierron use crate::regalloc::{EntryRegDiversions, RegDiversions}; 198f95c517SYury Delendik use crate::value_label::ValueLabelsRanges; 20747ad3c4Slazypassion use crate::write::write_function; 21f7e9f86bSPeter Huene use alloc::vec::Vec; 22747ad3c4Slazypassion use core::fmt; 23747ad3c4Slazypassion 24*2fc964eaSbjorn3 #[cfg(feature = "enable-serde")] 25*2fc964eaSbjorn3 use serde::{Deserialize, Serialize}; 26*2fc964eaSbjorn3 27747ad3c4Slazypassion /// A function. 28747ad3c4Slazypassion /// 29747ad3c4Slazypassion /// Functions can be cloned, but it is not a very fast operation. 30747ad3c4Slazypassion /// The clone will have all the same entity numbers as the original. 31747ad3c4Slazypassion #[derive(Clone)] 32*2fc964eaSbjorn3 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 33747ad3c4Slazypassion pub struct Function { 34747ad3c4Slazypassion /// Name of this function. Mostly used by `.clif` files. 35747ad3c4Slazypassion pub name: ExternalName, 36747ad3c4Slazypassion 37747ad3c4Slazypassion /// Signature of this function. 38747ad3c4Slazypassion pub signature: Signature, 39747ad3c4Slazypassion 40a4948340SNick Fitzgerald /// The old signature of this function, before the most recent legalization, 41a4948340SNick Fitzgerald /// if any. 42a4948340SNick Fitzgerald pub old_signature: Option<Signature>, 43a4948340SNick Fitzgerald 44747ad3c4Slazypassion /// Stack slots allocated in this function. 45747ad3c4Slazypassion pub stack_slots: StackSlots, 46747ad3c4Slazypassion 47747ad3c4Slazypassion /// Global values referenced. 48747ad3c4Slazypassion pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>, 49747ad3c4Slazypassion 50747ad3c4Slazypassion /// Heaps referenced. 51747ad3c4Slazypassion pub heaps: PrimaryMap<ir::Heap, ir::HeapData>, 52747ad3c4Slazypassion 53747ad3c4Slazypassion /// Tables referenced. 54747ad3c4Slazypassion pub tables: PrimaryMap<ir::Table, ir::TableData>, 55747ad3c4Slazypassion 56747ad3c4Slazypassion /// Jump tables used in this function. 57747ad3c4Slazypassion pub jump_tables: JumpTables, 58747ad3c4Slazypassion 59832666c4SRyan Hunt /// Data flow graph containing the primary definition of all instructions, blocks and values. 60747ad3c4Slazypassion pub dfg: DataFlowGraph, 61747ad3c4Slazypassion 62832666c4SRyan Hunt /// Layout of blocks and instructions in the function body. 63747ad3c4Slazypassion pub layout: Layout, 64747ad3c4Slazypassion 65747ad3c4Slazypassion /// Encoding recipe and bits for the legal instructions. 66747ad3c4Slazypassion /// Illegal instructions have the `Encoding::default()` value. 67747ad3c4Slazypassion pub encodings: InstEncodings, 68747ad3c4Slazypassion 69747ad3c4Slazypassion /// Location assigned to every value. 70747ad3c4Slazypassion pub locations: ValueLocations, 71747ad3c4Slazypassion 72bb87f1a5SNicolas B. Pierron /// Non-default locations assigned to value at the entry of basic blocks. 73bb87f1a5SNicolas B. Pierron /// 74bb87f1a5SNicolas B. Pierron /// At the entry of each basic block, we might have values which are not in their default 75bb87f1a5SNicolas B. Pierron /// ValueLocation. This field records these register-to-register moves as Diversions. 76bb87f1a5SNicolas B. Pierron pub entry_diversions: EntryRegDiversions, 77bb87f1a5SNicolas B. Pierron 78832666c4SRyan Hunt /// Code offsets of the block headers. 79747ad3c4Slazypassion /// 80747ad3c4Slazypassion /// This information is only transiently available after the `binemit::relax_branches` function 81747ad3c4Slazypassion /// computes it, and it can easily be recomputed by calling that function. It is not included 82747ad3c4Slazypassion /// in the textual IR format. 83832666c4SRyan Hunt pub offsets: BlockOffsets, 84747ad3c4Slazypassion 85747ad3c4Slazypassion /// Code offsets of Jump Table headers. 86747ad3c4Slazypassion pub jt_offsets: JumpTableOffsets, 87747ad3c4Slazypassion 88747ad3c4Slazypassion /// Source locations. 89747ad3c4Slazypassion /// 90747ad3c4Slazypassion /// Track the original source location for each instruction. The source locations are not 91747ad3c4Slazypassion /// interpreted by Cranelift, only preserved. 92747ad3c4Slazypassion pub srclocs: SourceLocs, 938923bac7SPeter Huene 948923bac7SPeter Huene /// Instruction that marks the end (inclusive) of the function's prologue. 958923bac7SPeter Huene /// 96f7e9f86bSPeter Huene /// This is used for some ABIs to generate unwind information. 978923bac7SPeter Huene pub prologue_end: Option<Inst>, 98d804ab8bSiximeow 99f7e9f86bSPeter Huene /// The instructions that mark the start (inclusive) of an epilogue in the function. 100d804ab8bSiximeow /// 101f7e9f86bSPeter Huene /// This is used for some ABIs to generate unwind information. 1023c688458SYury Delendik pub epilogues_start: Vec<(Inst, Block)>, 103c9a0ba81SAlex Crichton 104c9a0ba81SAlex Crichton /// An optional global value which represents an expression evaluating to 105c9a0ba81SAlex Crichton /// the stack limit for this function. This `GlobalValue` will be 106c9a0ba81SAlex Crichton /// interpreted in the prologue, if necessary, to insert a stack check to 107c9a0ba81SAlex Crichton /// ensure that a trap happens if the stack pointer goes below the 108c9a0ba81SAlex Crichton /// threshold specified here. 109c9a0ba81SAlex Crichton pub stack_limit: Option<ir::GlobalValue>, 110747ad3c4Slazypassion } 111747ad3c4Slazypassion 112747ad3c4Slazypassion impl Function { 113747ad3c4Slazypassion /// Create a function with the given name and signature. 114747ad3c4Slazypassion pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self { 115747ad3c4Slazypassion Self { 116747ad3c4Slazypassion name, 117747ad3c4Slazypassion signature: sig, 118a4948340SNick Fitzgerald old_signature: None, 119747ad3c4Slazypassion stack_slots: StackSlots::new(), 120747ad3c4Slazypassion global_values: PrimaryMap::new(), 121747ad3c4Slazypassion heaps: PrimaryMap::new(), 122747ad3c4Slazypassion tables: PrimaryMap::new(), 123747ad3c4Slazypassion jump_tables: PrimaryMap::new(), 124747ad3c4Slazypassion dfg: DataFlowGraph::new(), 125747ad3c4Slazypassion layout: Layout::new(), 126747ad3c4Slazypassion encodings: SecondaryMap::new(), 127747ad3c4Slazypassion locations: SecondaryMap::new(), 128bb87f1a5SNicolas B. Pierron entry_diversions: EntryRegDiversions::new(), 129747ad3c4Slazypassion offsets: SecondaryMap::new(), 130747ad3c4Slazypassion jt_offsets: SecondaryMap::new(), 131747ad3c4Slazypassion srclocs: SecondaryMap::new(), 1328923bac7SPeter Huene prologue_end: None, 133f7e9f86bSPeter Huene epilogues_start: Vec::new(), 134c9a0ba81SAlex Crichton stack_limit: None, 135747ad3c4Slazypassion } 136747ad3c4Slazypassion } 137747ad3c4Slazypassion 138747ad3c4Slazypassion /// Clear all data structures in this function. 139747ad3c4Slazypassion pub fn clear(&mut self) { 140747ad3c4Slazypassion self.signature.clear(CallConv::Fast); 141747ad3c4Slazypassion self.stack_slots.clear(); 142747ad3c4Slazypassion self.global_values.clear(); 143747ad3c4Slazypassion self.heaps.clear(); 144747ad3c4Slazypassion self.tables.clear(); 145747ad3c4Slazypassion self.jump_tables.clear(); 146747ad3c4Slazypassion self.dfg.clear(); 147747ad3c4Slazypassion self.layout.clear(); 148747ad3c4Slazypassion self.encodings.clear(); 149747ad3c4Slazypassion self.locations.clear(); 150bb87f1a5SNicolas B. Pierron self.entry_diversions.clear(); 151747ad3c4Slazypassion self.offsets.clear(); 152ea9ee202SAndrew Brown self.jt_offsets.clear(); 153747ad3c4Slazypassion self.srclocs.clear(); 1548923bac7SPeter Huene self.prologue_end = None; 155f7e9f86bSPeter Huene self.epilogues_start.clear(); 156c9a0ba81SAlex Crichton self.stack_limit = None; 157747ad3c4Slazypassion } 158747ad3c4Slazypassion 159747ad3c4Slazypassion /// Create a new empty, anonymous function with a Fast calling convention. 160747ad3c4Slazypassion pub fn new() -> Self { 161747ad3c4Slazypassion Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast)) 162747ad3c4Slazypassion } 163747ad3c4Slazypassion 164747ad3c4Slazypassion /// Creates a jump table in the function, to be used by `br_table` instructions. 165747ad3c4Slazypassion pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { 166747ad3c4Slazypassion self.jump_tables.push(data) 167747ad3c4Slazypassion } 168747ad3c4Slazypassion 169747ad3c4Slazypassion /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and 170747ad3c4Slazypassion /// `stack_addr` instructions. 171747ad3c4Slazypassion pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot { 172747ad3c4Slazypassion self.stack_slots.push(data) 173747ad3c4Slazypassion } 174747ad3c4Slazypassion 175747ad3c4Slazypassion /// Adds a signature which can later be used to declare an external function import. 176747ad3c4Slazypassion pub fn import_signature(&mut self, signature: Signature) -> SigRef { 177747ad3c4Slazypassion self.dfg.signatures.push(signature) 178747ad3c4Slazypassion } 179747ad3c4Slazypassion 180747ad3c4Slazypassion /// Declare an external function import. 181747ad3c4Slazypassion pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { 182747ad3c4Slazypassion self.dfg.ext_funcs.push(data) 183747ad3c4Slazypassion } 184747ad3c4Slazypassion 185747ad3c4Slazypassion /// Declares a global value accessible to the function. 186747ad3c4Slazypassion pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { 187747ad3c4Slazypassion self.global_values.push(data) 188747ad3c4Slazypassion } 189747ad3c4Slazypassion 190747ad3c4Slazypassion /// Declares a heap accessible to the function. 191747ad3c4Slazypassion pub fn create_heap(&mut self, data: HeapData) -> Heap { 192747ad3c4Slazypassion self.heaps.push(data) 193747ad3c4Slazypassion } 194747ad3c4Slazypassion 195747ad3c4Slazypassion /// Declares a table accessible to the function. 196747ad3c4Slazypassion pub fn create_table(&mut self, data: TableData) -> Table { 197747ad3c4Slazypassion self.tables.push(data) 198747ad3c4Slazypassion } 199747ad3c4Slazypassion 200747ad3c4Slazypassion /// Return an object that can display this function with correct ISA-specific annotations. 201d7d48d5cSBenjamin Bouvier pub fn display<'a, I: Into<Option<&'a dyn TargetIsa>>>( 202d7d48d5cSBenjamin Bouvier &'a self, 203d7d48d5cSBenjamin Bouvier isa: I, 204d7d48d5cSBenjamin Bouvier ) -> DisplayFunction<'a> { 2058f95c517SYury Delendik DisplayFunction(self, isa.into().into()) 2068f95c517SYury Delendik } 2078f95c517SYury Delendik 2088f95c517SYury Delendik /// Return an object that can display this function with correct ISA-specific annotations. 2098f95c517SYury Delendik pub fn display_with<'a>( 2108f95c517SYury Delendik &'a self, 2118f95c517SYury Delendik annotations: DisplayFunctionAnnotations<'a>, 2128f95c517SYury Delendik ) -> DisplayFunction<'a> { 2138f95c517SYury Delendik DisplayFunction(self, annotations) 214747ad3c4Slazypassion } 215747ad3c4Slazypassion 216747ad3c4Slazypassion /// Find a presumed unique special-purpose function parameter value. 217747ad3c4Slazypassion /// 218747ad3c4Slazypassion /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists. 219747ad3c4Slazypassion pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { 220747ad3c4Slazypassion let entry = self.layout.entry_block().expect("Function is empty"); 221747ad3c4Slazypassion self.signature 222747ad3c4Slazypassion .special_param_index(purpose) 223832666c4SRyan Hunt .map(|i| self.dfg.block_params(entry)[i]) 224747ad3c4Slazypassion } 225747ad3c4Slazypassion 226832666c4SRyan Hunt /// Get an iterator over the instructions in `block`, including offsets and encoded instruction 227747ad3c4Slazypassion /// sizes. 228747ad3c4Slazypassion /// 229747ad3c4Slazypassion /// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes 230747ad3c4Slazypassion /// from the beginning of the function to the instruction, and `size` is the size of the 231747ad3c4Slazypassion /// instruction in bytes, or 0 for unencoded instructions. 232747ad3c4Slazypassion /// 233747ad3c4Slazypassion /// This function can only be used after the code layout has been computed by the 234747ad3c4Slazypassion /// `binemit::relax_branches()` function. 235832666c4SRyan Hunt pub fn inst_offsets<'a>(&'a self, block: Block, encinfo: &EncInfo) -> InstOffsetIter<'a> { 236747ad3c4Slazypassion assert!( 237747ad3c4Slazypassion !self.offsets.is_empty(), 238747ad3c4Slazypassion "Code layout must be computed first" 239747ad3c4Slazypassion ); 240bb87f1a5SNicolas B. Pierron let mut divert = RegDiversions::new(); 241832666c4SRyan Hunt divert.at_block(&self.entry_diversions, block); 242747ad3c4Slazypassion InstOffsetIter { 243747ad3c4Slazypassion encinfo: encinfo.clone(), 244747ad3c4Slazypassion func: self, 245bb87f1a5SNicolas B. Pierron divert, 246747ad3c4Slazypassion encodings: &self.encodings, 247832666c4SRyan Hunt offset: self.offsets[block], 248832666c4SRyan Hunt iter: self.layout.block_insts(block), 249747ad3c4Slazypassion } 250747ad3c4Slazypassion } 251747ad3c4Slazypassion 252747ad3c4Slazypassion /// Wrapper around `encode` which assigns `inst` the resulting encoding. 253d7d48d5cSBenjamin Bouvier pub fn update_encoding(&mut self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<(), Legalize> { 25460990aeaSChris Fallin if isa.get_mach_backend().is_some() { 25560990aeaSChris Fallin Ok(()) 25660990aeaSChris Fallin } else { 257747ad3c4Slazypassion self.encode(inst, isa).map(|e| self.encodings[inst] = e) 258747ad3c4Slazypassion } 25960990aeaSChris Fallin } 260747ad3c4Slazypassion 261747ad3c4Slazypassion /// Wrapper around `TargetIsa::encode` for encoding an existing instruction 262747ad3c4Slazypassion /// in the `Function`. 263d7d48d5cSBenjamin Bouvier pub fn encode(&self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<Encoding, Legalize> { 26460990aeaSChris Fallin if isa.get_mach_backend().is_some() { 26560990aeaSChris Fallin Ok(Encoding::new(0, 0)) 26660990aeaSChris Fallin } else { 267747ad3c4Slazypassion isa.encode(&self, &self.dfg[inst], self.dfg.ctrl_typevar(inst)) 268747ad3c4Slazypassion } 26960990aeaSChris Fallin } 2708f95c517SYury Delendik 2718f95c517SYury Delendik /// Starts collection of debug information. 2728f95c517SYury Delendik pub fn collect_debug_info(&mut self) { 2738f95c517SYury Delendik self.dfg.collect_debug_info(); 2748f95c517SYury Delendik } 2758efaeec5SSean Stangl 276c7b4b98cSSean Stangl /// Changes the destination of a jump or branch instruction. 277c7b4b98cSSean Stangl /// Does nothing if called with a non-jump or non-branch instruction. 278855a6374SY-Nak /// 279855a6374SY-Nak /// Note that this method ignores multi-destination branches like `br_table`. 280832666c4SRyan Hunt pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) { 281c7b4b98cSSean Stangl match self.dfg[inst].branch_destination_mut() { 282c7b4b98cSSean Stangl None => (), 283c7b4b98cSSean Stangl Some(inst_dest) => *inst_dest = new_dest, 284c7b4b98cSSean Stangl } 285c7b4b98cSSean Stangl } 286c7b4b98cSSean Stangl 287855a6374SY-Nak /// Rewrite the branch destination to `new_dest` if the destination matches `old_dest`. 288855a6374SY-Nak /// Does nothing if called with a non-jump or non-branch instruction. 289855a6374SY-Nak /// 290855a6374SY-Nak /// Unlike [change_branch_destination](Function::change_branch_destination), this method rewrite the destinations of 291855a6374SY-Nak /// multi-destination branches like `br_table`. 292855a6374SY-Nak pub fn rewrite_branch_destination(&mut self, inst: Inst, old_dest: Block, new_dest: Block) { 293855a6374SY-Nak match self.dfg.analyze_branch(inst) { 294855a6374SY-Nak BranchInfo::SingleDest(dest, ..) => { 295855a6374SY-Nak if dest == old_dest { 296855a6374SY-Nak self.change_branch_destination(inst, new_dest); 297855a6374SY-Nak } 298855a6374SY-Nak } 299855a6374SY-Nak 300855a6374SY-Nak BranchInfo::Table(table, default_dest) => { 301855a6374SY-Nak self.jump_tables[table].iter_mut().for_each(|entry| { 302855a6374SY-Nak if *entry == old_dest { 303855a6374SY-Nak *entry = new_dest; 304855a6374SY-Nak } 305855a6374SY-Nak }); 306855a6374SY-Nak 307855a6374SY-Nak if default_dest == Some(old_dest) { 308855a6374SY-Nak match &mut self.dfg[inst] { 309855a6374SY-Nak InstructionData::BranchTable { destination, .. } => { 310855a6374SY-Nak *destination = new_dest; 311855a6374SY-Nak } 312855a6374SY-Nak _ => panic!( 313855a6374SY-Nak "Unexpected instruction {} having default destination", 314855a6374SY-Nak self.dfg.display_inst(inst, None) 315855a6374SY-Nak ), 316855a6374SY-Nak } 317855a6374SY-Nak } 318855a6374SY-Nak } 319855a6374SY-Nak 320855a6374SY-Nak BranchInfo::NotABranch => {} 321855a6374SY-Nak } 322855a6374SY-Nak } 323855a6374SY-Nak 324832666c4SRyan Hunt /// Checks that the specified block can be encoded as a basic block. 3258efaeec5SSean Stangl /// 3268efaeec5SSean Stangl /// On error, returns the first invalid instruction and an error message. 327832666c4SRyan Hunt pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { 3288efaeec5SSean Stangl let dfg = &self.dfg; 329832666c4SRyan Hunt let inst_iter = self.layout.block_insts(block); 3308efaeec5SSean Stangl 3318efaeec5SSean Stangl // Ignore all instructions prior to the first branch. 3328efaeec5SSean Stangl let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch()); 3338efaeec5SSean Stangl 3348efaeec5SSean Stangl // A conditional branch is permitted in a basic block only when followed 3358efaeec5SSean Stangl // by a terminal jump or fallthrough instruction. 3368efaeec5SSean Stangl if let Some(_branch) = inst_iter.next() { 3378efaeec5SSean Stangl if let Some(next) = inst_iter.next() { 3388efaeec5SSean Stangl match dfg[next].opcode() { 3398efaeec5SSean Stangl Opcode::Fallthrough | Opcode::Jump => (), 3408efaeec5SSean Stangl _ => return Err((next, "post-branch instruction not fallthrough or jump")), 3418efaeec5SSean Stangl } 3428efaeec5SSean Stangl } 3438efaeec5SSean Stangl } 3448efaeec5SSean Stangl 3458efaeec5SSean Stangl Ok(()) 3468efaeec5SSean Stangl } 347143cb014SBenjamin Bouvier 348143cb014SBenjamin Bouvier /// Returns true if the function is function that doesn't call any other functions. This is not 349143cb014SBenjamin Bouvier /// to be confused with a "leaf function" in Windows terminology. 350143cb014SBenjamin Bouvier pub fn is_leaf(&self) -> bool { 351143cb014SBenjamin Bouvier // Conservative result: if there's at least one function signature referenced in this 35258e5a62cSY-Nak // function, assume it is not a leaf. 35358e5a62cSY-Nak self.dfg.signatures.is_empty() 354143cb014SBenjamin Bouvier } 355090d1c2dSNick Fitzgerald 356090d1c2dSNick Fitzgerald /// Replace the `dst` instruction's data with the `src` instruction's data 357090d1c2dSNick Fitzgerald /// and then remove `src`. 358090d1c2dSNick Fitzgerald /// 359090d1c2dSNick Fitzgerald /// `src` and its result values should not be used at all, as any uses would 360090d1c2dSNick Fitzgerald /// be left dangling after calling this method. 361090d1c2dSNick Fitzgerald /// 362090d1c2dSNick Fitzgerald /// `src` and `dst` must have the same number of resulting values, and 363090d1c2dSNick Fitzgerald /// `src`'s i^th value must have the same type as `dst`'s i^th value. 364090d1c2dSNick Fitzgerald pub fn transplant_inst(&mut self, dst: Inst, src: Inst) { 365090d1c2dSNick Fitzgerald debug_assert_eq!( 366090d1c2dSNick Fitzgerald self.dfg.inst_results(dst).len(), 367090d1c2dSNick Fitzgerald self.dfg.inst_results(src).len() 368090d1c2dSNick Fitzgerald ); 369090d1c2dSNick Fitzgerald debug_assert!(self 370090d1c2dSNick Fitzgerald .dfg 371090d1c2dSNick Fitzgerald .inst_results(dst) 372090d1c2dSNick Fitzgerald .iter() 373090d1c2dSNick Fitzgerald .zip(self.dfg.inst_results(src)) 374090d1c2dSNick Fitzgerald .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b))); 375090d1c2dSNick Fitzgerald 376090d1c2dSNick Fitzgerald self.dfg[dst] = self.dfg[src].clone(); 377090d1c2dSNick Fitzgerald self.layout.remove_inst(src); 378090d1c2dSNick Fitzgerald } 3798f95c517SYury Delendik } 3808f95c517SYury Delendik 3818f95c517SYury Delendik /// Additional annotations for function display. 382f856b124SMark McCaskey #[derive(Default)] 3838f95c517SYury Delendik pub struct DisplayFunctionAnnotations<'a> { 3848f95c517SYury Delendik /// Enable ISA annotations. 385d7d48d5cSBenjamin Bouvier pub isa: Option<&'a dyn TargetIsa>, 3868f95c517SYury Delendik 3878f95c517SYury Delendik /// Enable value labels annotations. 3888f95c517SYury Delendik pub value_ranges: Option<&'a ValueLabelsRanges>, 3898f95c517SYury Delendik } 3908f95c517SYury Delendik 391d7d48d5cSBenjamin Bouvier impl<'a> From<Option<&'a dyn TargetIsa>> for DisplayFunctionAnnotations<'a> { 392d7d48d5cSBenjamin Bouvier fn from(isa: Option<&'a dyn TargetIsa>) -> DisplayFunctionAnnotations { 3938f95c517SYury Delendik DisplayFunctionAnnotations { 3948f95c517SYury Delendik isa, 3958f95c517SYury Delendik value_ranges: None, 3968f95c517SYury Delendik } 3978f95c517SYury Delendik } 398747ad3c4Slazypassion } 399747ad3c4Slazypassion 400747ad3c4Slazypassion /// Wrapper type capable of displaying a `Function` with correct ISA annotations. 4018f95c517SYury Delendik pub struct DisplayFunction<'a>(&'a Function, DisplayFunctionAnnotations<'a>); 402747ad3c4Slazypassion 403747ad3c4Slazypassion impl<'a> fmt::Display for DisplayFunction<'a> { 404747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 4058f95c517SYury Delendik write_function(fmt, self.0, &self.1) 406747ad3c4Slazypassion } 407747ad3c4Slazypassion } 408747ad3c4Slazypassion 409747ad3c4Slazypassion impl fmt::Display for Function { 410747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 4118f95c517SYury Delendik write_function(fmt, self, &DisplayFunctionAnnotations::default()) 412747ad3c4Slazypassion } 413747ad3c4Slazypassion } 414747ad3c4Slazypassion 415747ad3c4Slazypassion impl fmt::Debug for Function { 416747ad3c4Slazypassion fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 4178f95c517SYury Delendik write_function(fmt, self, &DisplayFunctionAnnotations::default()) 418747ad3c4Slazypassion } 419747ad3c4Slazypassion } 420747ad3c4Slazypassion 421747ad3c4Slazypassion /// Iterator returning instruction offsets and sizes: `(offset, inst, size)`. 422747ad3c4Slazypassion pub struct InstOffsetIter<'a> { 423747ad3c4Slazypassion encinfo: EncInfo, 424747ad3c4Slazypassion divert: RegDiversions, 425747ad3c4Slazypassion func: &'a Function, 426747ad3c4Slazypassion encodings: &'a InstEncodings, 427747ad3c4Slazypassion offset: CodeOffset, 428747ad3c4Slazypassion iter: ir::layout::Insts<'a>, 429747ad3c4Slazypassion } 430747ad3c4Slazypassion 431747ad3c4Slazypassion impl<'a> Iterator for InstOffsetIter<'a> { 432747ad3c4Slazypassion type Item = (CodeOffset, ir::Inst, CodeOffset); 433747ad3c4Slazypassion 434747ad3c4Slazypassion fn next(&mut self) -> Option<Self::Item> { 435747ad3c4Slazypassion self.iter.next().map(|inst| { 436747ad3c4Slazypassion self.divert.apply(&self.func.dfg[inst]); 437747ad3c4Slazypassion let byte_size = 438747ad3c4Slazypassion self.encinfo 439747ad3c4Slazypassion .byte_size(self.encodings[inst], inst, &self.divert, self.func); 440747ad3c4Slazypassion let offset = self.offset; 441747ad3c4Slazypassion self.offset += byte_size; 442747ad3c4Slazypassion (offset, inst, byte_size) 443747ad3c4Slazypassion }) 444747ad3c4Slazypassion } 445747ad3c4Slazypassion } 446