1747ad3c4Slazypassion //! Converting Cranelift IR to text. 2747ad3c4Slazypassion //! 3747ad3c4Slazypassion //! The `write` module provides the `write_function` function which converts an IR `Function` to an 4747ad3c4Slazypassion //! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate. 5747ad3c4Slazypassion 6747ad3c4Slazypassion use crate::entity::SecondaryMap; 7747ad3c4Slazypassion use crate::ir::entities::AnyEntity; 8cd426cb7SAndrew Brown use crate::ir::immediates::V128Imm; 98f95c517SYury Delendik use crate::ir::{ 108f95c517SYury Delendik DataFlowGraph, DisplayFunctionAnnotations, Ebb, Function, Inst, SigRef, Type, Value, ValueDef, 118f95c517SYury Delendik ValueLoc, 128f95c517SYury Delendik }; 13747ad3c4Slazypassion use crate::isa::{RegInfo, TargetIsa}; 14747ad3c4Slazypassion use crate::packed_option::ReservedValue; 158f95c517SYury Delendik use crate::value_label::ValueLabelsRanges; 16a1f6457eSJoshua Nelson use crate::HashSet; 1710e226f9Sbjorn3 use alloc::string::String; 1810e226f9Sbjorn3 use alloc::vec::Vec; 19*bb8fa40eSbjorn3 use core::fmt::{self, Write}; 20747ad3c4Slazypassion 21747ad3c4Slazypassion /// A `FuncWriter` used to decorate functions during printing. 22747ad3c4Slazypassion pub trait FuncWriter { 23747ad3c4Slazypassion /// Write the extended basic block header for the current function. 24747ad3c4Slazypassion fn write_ebb_header( 25747ad3c4Slazypassion &mut self, 26d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 27747ad3c4Slazypassion func: &Function, 28d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 29747ad3c4Slazypassion ebb: Ebb, 30747ad3c4Slazypassion indent: usize, 31747ad3c4Slazypassion ) -> fmt::Result; 32747ad3c4Slazypassion 33747ad3c4Slazypassion /// Write the given `inst` to `w`. 34747ad3c4Slazypassion fn write_instruction( 35747ad3c4Slazypassion &mut self, 36d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 37747ad3c4Slazypassion func: &Function, 38747ad3c4Slazypassion aliases: &SecondaryMap<Value, Vec<Value>>, 39d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 40747ad3c4Slazypassion inst: Inst, 41747ad3c4Slazypassion indent: usize, 42747ad3c4Slazypassion ) -> fmt::Result; 43747ad3c4Slazypassion 44747ad3c4Slazypassion /// Write the preamble to `w`. By default, this uses `write_entity_definition`. 45747ad3c4Slazypassion fn write_preamble( 46747ad3c4Slazypassion &mut self, 47d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 48747ad3c4Slazypassion func: &Function, 49747ad3c4Slazypassion regs: Option<&RegInfo>, 50747ad3c4Slazypassion ) -> Result<bool, fmt::Error> { 51747ad3c4Slazypassion self.super_preamble(w, func, regs) 52747ad3c4Slazypassion } 53747ad3c4Slazypassion 54747ad3c4Slazypassion /// Default impl of `write_preamble` 55747ad3c4Slazypassion fn super_preamble( 56747ad3c4Slazypassion &mut self, 57d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 58747ad3c4Slazypassion func: &Function, 59747ad3c4Slazypassion regs: Option<&RegInfo>, 60747ad3c4Slazypassion ) -> Result<bool, fmt::Error> { 61747ad3c4Slazypassion let mut any = false; 62747ad3c4Slazypassion 63747ad3c4Slazypassion for (ss, slot) in func.stack_slots.iter() { 64747ad3c4Slazypassion any = true; 65747ad3c4Slazypassion self.write_entity_definition(w, func, ss.into(), slot)?; 66747ad3c4Slazypassion } 67747ad3c4Slazypassion 68747ad3c4Slazypassion for (gv, gv_data) in &func.global_values { 69747ad3c4Slazypassion any = true; 70747ad3c4Slazypassion self.write_entity_definition(w, func, gv.into(), gv_data)?; 71747ad3c4Slazypassion } 72747ad3c4Slazypassion 73747ad3c4Slazypassion for (heap, heap_data) in &func.heaps { 74747ad3c4Slazypassion if !heap_data.index_type.is_invalid() { 75747ad3c4Slazypassion any = true; 76747ad3c4Slazypassion self.write_entity_definition(w, func, heap.into(), heap_data)?; 77747ad3c4Slazypassion } 78747ad3c4Slazypassion } 79747ad3c4Slazypassion 80747ad3c4Slazypassion for (table, table_data) in &func.tables { 81747ad3c4Slazypassion if !table_data.index_type.is_invalid() { 82747ad3c4Slazypassion any = true; 83747ad3c4Slazypassion self.write_entity_definition(w, func, table.into(), table_data)?; 84747ad3c4Slazypassion } 85747ad3c4Slazypassion } 86747ad3c4Slazypassion 87747ad3c4Slazypassion // Write out all signatures before functions since function declarations can refer to 88747ad3c4Slazypassion // signatures. 89747ad3c4Slazypassion for (sig, sig_data) in &func.dfg.signatures { 90747ad3c4Slazypassion any = true; 91747ad3c4Slazypassion self.write_entity_definition(w, func, sig.into(), &sig_data.display(regs))?; 92747ad3c4Slazypassion } 93747ad3c4Slazypassion 94747ad3c4Slazypassion for (fnref, ext_func) in &func.dfg.ext_funcs { 95747ad3c4Slazypassion if ext_func.signature != SigRef::reserved_value() { 96747ad3c4Slazypassion any = true; 97747ad3c4Slazypassion self.write_entity_definition(w, func, fnref.into(), ext_func)?; 98747ad3c4Slazypassion } 99747ad3c4Slazypassion } 100747ad3c4Slazypassion 101747ad3c4Slazypassion for (jt, jt_data) in &func.jump_tables { 102747ad3c4Slazypassion any = true; 103747ad3c4Slazypassion self.write_entity_definition(w, func, jt.into(), jt_data)?; 104747ad3c4Slazypassion } 105747ad3c4Slazypassion 106747ad3c4Slazypassion Ok(any) 107747ad3c4Slazypassion } 108747ad3c4Slazypassion 109747ad3c4Slazypassion /// Write an entity definition defined in the preamble to `w`. 110747ad3c4Slazypassion fn write_entity_definition( 111747ad3c4Slazypassion &mut self, 112d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 113747ad3c4Slazypassion func: &Function, 114747ad3c4Slazypassion entity: AnyEntity, 115d7d48d5cSBenjamin Bouvier value: &dyn fmt::Display, 116747ad3c4Slazypassion ) -> fmt::Result { 117747ad3c4Slazypassion self.super_entity_definition(w, func, entity, value) 118747ad3c4Slazypassion } 119747ad3c4Slazypassion 120747ad3c4Slazypassion /// Default impl of `write_entity_definition` 121747ad3c4Slazypassion #[allow(unused_variables)] 122747ad3c4Slazypassion fn super_entity_definition( 123747ad3c4Slazypassion &mut self, 124d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 125747ad3c4Slazypassion func: &Function, 126747ad3c4Slazypassion entity: AnyEntity, 127d7d48d5cSBenjamin Bouvier value: &dyn fmt::Display, 128747ad3c4Slazypassion ) -> fmt::Result { 129747ad3c4Slazypassion writeln!(w, " {} = {}", entity, value) 130747ad3c4Slazypassion } 131747ad3c4Slazypassion } 132747ad3c4Slazypassion 133747ad3c4Slazypassion /// A `PlainWriter` that doesn't decorate the function. 134747ad3c4Slazypassion pub struct PlainWriter; 135747ad3c4Slazypassion 136747ad3c4Slazypassion impl FuncWriter for PlainWriter { 137747ad3c4Slazypassion fn write_instruction( 138747ad3c4Slazypassion &mut self, 139d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 140747ad3c4Slazypassion func: &Function, 141747ad3c4Slazypassion aliases: &SecondaryMap<Value, Vec<Value>>, 142d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 143747ad3c4Slazypassion inst: Inst, 144747ad3c4Slazypassion indent: usize, 145747ad3c4Slazypassion ) -> fmt::Result { 146747ad3c4Slazypassion write_instruction(w, func, aliases, isa, inst, indent) 147747ad3c4Slazypassion } 148747ad3c4Slazypassion 149747ad3c4Slazypassion fn write_ebb_header( 150747ad3c4Slazypassion &mut self, 151d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 152747ad3c4Slazypassion func: &Function, 153d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 154747ad3c4Slazypassion ebb: Ebb, 155747ad3c4Slazypassion indent: usize, 156747ad3c4Slazypassion ) -> fmt::Result { 157747ad3c4Slazypassion write_ebb_header(w, func, isa, ebb, indent) 158747ad3c4Slazypassion } 159747ad3c4Slazypassion } 160747ad3c4Slazypassion 161747ad3c4Slazypassion /// Write `func` to `w` as equivalent text. 162747ad3c4Slazypassion /// Use `isa` to emit ISA-dependent annotations. 1638f95c517SYury Delendik pub fn write_function( 164d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 1658f95c517SYury Delendik func: &Function, 1668f95c517SYury Delendik annotations: &DisplayFunctionAnnotations, 1678f95c517SYury Delendik ) -> fmt::Result { 1688f95c517SYury Delendik decorate_function(&mut PlainWriter, w, func, annotations) 169747ad3c4Slazypassion } 170747ad3c4Slazypassion 171747ad3c4Slazypassion /// Create a reverse-alias map from a value to all aliases having that value as a direct target 172747ad3c4Slazypassion fn alias_map(func: &Function) -> SecondaryMap<Value, Vec<Value>> { 173747ad3c4Slazypassion let mut aliases = SecondaryMap::<_, Vec<_>>::new(); 174747ad3c4Slazypassion for v in func.dfg.values() { 175747ad3c4Slazypassion // VADFS returns the immediate target of an alias 176747ad3c4Slazypassion if let Some(k) = func.dfg.value_alias_dest_for_serialization(v) { 177747ad3c4Slazypassion aliases[k].push(v); 178747ad3c4Slazypassion } 179747ad3c4Slazypassion } 180747ad3c4Slazypassion aliases 181747ad3c4Slazypassion } 182747ad3c4Slazypassion 183747ad3c4Slazypassion /// Writes `func` to `w` as text. 184747ad3c4Slazypassion /// write_function_plain is passed as 'closure' to print instructions as text. 185747ad3c4Slazypassion /// pretty_function_error is passed as 'closure' to add error decoration. 186747ad3c4Slazypassion pub fn decorate_function<FW: FuncWriter>( 187747ad3c4Slazypassion func_w: &mut FW, 188d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 189747ad3c4Slazypassion func: &Function, 1908f95c517SYury Delendik annotations: &DisplayFunctionAnnotations, 191747ad3c4Slazypassion ) -> fmt::Result { 1928f95c517SYury Delendik let regs = annotations.isa.map(TargetIsa::register_info); 193747ad3c4Slazypassion let regs = regs.as_ref(); 194747ad3c4Slazypassion 195747ad3c4Slazypassion write!(w, "function ")?; 196747ad3c4Slazypassion write_spec(w, func, regs)?; 197747ad3c4Slazypassion writeln!(w, " {{")?; 198747ad3c4Slazypassion let aliases = alias_map(func); 199747ad3c4Slazypassion let mut any = func_w.write_preamble(w, func, regs)?; 200747ad3c4Slazypassion for ebb in &func.layout { 201747ad3c4Slazypassion if any { 202747ad3c4Slazypassion writeln!(w)?; 203747ad3c4Slazypassion } 2048f95c517SYury Delendik decorate_ebb(func_w, w, func, &aliases, annotations, ebb)?; 205747ad3c4Slazypassion any = true; 206747ad3c4Slazypassion } 207747ad3c4Slazypassion writeln!(w, "}}") 208747ad3c4Slazypassion } 209747ad3c4Slazypassion 210747ad3c4Slazypassion //---------------------------------------------------------------------- 211747ad3c4Slazypassion // 212747ad3c4Slazypassion // Function spec. 213747ad3c4Slazypassion 214d7d48d5cSBenjamin Bouvier fn write_spec(w: &mut dyn Write, func: &Function, regs: Option<&RegInfo>) -> fmt::Result { 215747ad3c4Slazypassion write!(w, "{}{}", func.name, func.signature.display(regs)) 216747ad3c4Slazypassion } 217747ad3c4Slazypassion 218747ad3c4Slazypassion //---------------------------------------------------------------------- 219747ad3c4Slazypassion // 220747ad3c4Slazypassion // Basic blocks 221747ad3c4Slazypassion 222d7d48d5cSBenjamin Bouvier fn write_arg( 223d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 224d7d48d5cSBenjamin Bouvier func: &Function, 225d7d48d5cSBenjamin Bouvier regs: Option<&RegInfo>, 226d7d48d5cSBenjamin Bouvier arg: Value, 227d7d48d5cSBenjamin Bouvier ) -> fmt::Result { 228747ad3c4Slazypassion write!(w, "{}: {}", arg, func.dfg.value_type(arg))?; 229747ad3c4Slazypassion let loc = func.locations[arg]; 230747ad3c4Slazypassion if loc.is_assigned() { 231747ad3c4Slazypassion write!(w, " [{}]", loc.display(regs))? 232747ad3c4Slazypassion } 233747ad3c4Slazypassion 234747ad3c4Slazypassion Ok(()) 235747ad3c4Slazypassion } 236747ad3c4Slazypassion 237747ad3c4Slazypassion /// Write out the basic block header, outdented: 238747ad3c4Slazypassion /// 239747ad3c4Slazypassion /// ebb1: 240747ad3c4Slazypassion /// ebb1(v1: i32): 241747ad3c4Slazypassion /// ebb10(v4: f64, v5: b1): 242747ad3c4Slazypassion /// 243747ad3c4Slazypassion pub fn write_ebb_header( 244d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 245747ad3c4Slazypassion func: &Function, 246d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 247747ad3c4Slazypassion ebb: Ebb, 248747ad3c4Slazypassion indent: usize, 249747ad3c4Slazypassion ) -> fmt::Result { 250747ad3c4Slazypassion // The `indent` is the instruction indentation. EBB headers are 4 spaces out from that. 251747ad3c4Slazypassion write!(w, "{1:0$}{2}", indent - 4, "", ebb)?; 252747ad3c4Slazypassion 253747ad3c4Slazypassion let regs = isa.map(TargetIsa::register_info); 254747ad3c4Slazypassion let regs = regs.as_ref(); 255747ad3c4Slazypassion 256747ad3c4Slazypassion let mut args = func.dfg.ebb_params(ebb).iter().cloned(); 257747ad3c4Slazypassion match args.next() { 258747ad3c4Slazypassion None => return writeln!(w, ":"), 259747ad3c4Slazypassion Some(arg) => { 260747ad3c4Slazypassion write!(w, "(")?; 261747ad3c4Slazypassion write_arg(w, func, regs, arg)?; 262747ad3c4Slazypassion } 263747ad3c4Slazypassion } 264747ad3c4Slazypassion // Remaining arguments. 265747ad3c4Slazypassion for arg in args { 266747ad3c4Slazypassion write!(w, ", ")?; 267747ad3c4Slazypassion write_arg(w, func, regs, arg)?; 268747ad3c4Slazypassion } 269747ad3c4Slazypassion writeln!(w, "):") 270747ad3c4Slazypassion } 271747ad3c4Slazypassion 272d7d48d5cSBenjamin Bouvier fn write_valueloc(w: &mut dyn Write, loc: &ValueLoc, regs: &RegInfo) -> fmt::Result { 2738f95c517SYury Delendik match loc { 2748f95c517SYury Delendik ValueLoc::Reg(r) => write!(w, "{}", regs.display_regunit(*r)), 2758f95c517SYury Delendik ValueLoc::Stack(ss) => write!(w, "{}", ss), 2768f95c517SYury Delendik ValueLoc::Unassigned => write!(w, "?"), 2778f95c517SYury Delendik } 2788f95c517SYury Delendik } 2798f95c517SYury Delendik 2808f95c517SYury Delendik fn write_value_range_markers( 281d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 2828f95c517SYury Delendik val_ranges: &ValueLabelsRanges, 2838f95c517SYury Delendik regs: &RegInfo, 2848f95c517SYury Delendik offset: u32, 2858f95c517SYury Delendik indent: usize, 2868f95c517SYury Delendik ) -> fmt::Result { 2878f95c517SYury Delendik let mut result = String::new(); 2888f95c517SYury Delendik let mut shown = HashSet::new(); 2898f95c517SYury Delendik for (val, rng) in val_ranges { 2908f95c517SYury Delendik for i in (0..rng.len()).rev() { 2918f95c517SYury Delendik if rng[i].start == offset { 2928f95c517SYury Delendik write!(&mut result, " {}@", val)?; 2938f95c517SYury Delendik write_valueloc(&mut result, &rng[i].loc, regs)?; 2948f95c517SYury Delendik shown.insert(val); 2958f95c517SYury Delendik break; 2968f95c517SYury Delendik } 2978f95c517SYury Delendik } 2988f95c517SYury Delendik } 2998f95c517SYury Delendik for (val, rng) in val_ranges { 3008f95c517SYury Delendik for i in (0..rng.len()).rev() { 3018f95c517SYury Delendik if rng[i].end == offset && !shown.contains(val) { 3028f95c517SYury Delendik write!(&mut result, " {}\u{2620}", val)?; 3038f95c517SYury Delendik break; 3048f95c517SYury Delendik } 3058f95c517SYury Delendik } 3068f95c517SYury Delendik } 3078f95c517SYury Delendik if result.len() > 0 { 3088f95c517SYury Delendik writeln!(w, ";{1:0$}; {2}", indent + 24, "", result)?; 3098f95c517SYury Delendik } 3108f95c517SYury Delendik Ok(()) 3118f95c517SYury Delendik } 3128f95c517SYury Delendik 313747ad3c4Slazypassion fn decorate_ebb<FW: FuncWriter>( 314747ad3c4Slazypassion func_w: &mut FW, 315d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 316747ad3c4Slazypassion func: &Function, 317747ad3c4Slazypassion aliases: &SecondaryMap<Value, Vec<Value>>, 3188f95c517SYury Delendik annotations: &DisplayFunctionAnnotations, 319747ad3c4Slazypassion ebb: Ebb, 320747ad3c4Slazypassion ) -> fmt::Result { 321747ad3c4Slazypassion // Indent all instructions if any encodings are present. 322747ad3c4Slazypassion let indent = if func.encodings.is_empty() && func.srclocs.is_empty() { 323747ad3c4Slazypassion 4 324747ad3c4Slazypassion } else { 325747ad3c4Slazypassion 36 326747ad3c4Slazypassion }; 3278f95c517SYury Delendik let isa = annotations.isa; 328747ad3c4Slazypassion 329747ad3c4Slazypassion func_w.write_ebb_header(w, func, isa, ebb, indent)?; 330747ad3c4Slazypassion for a in func.dfg.ebb_params(ebb).iter().cloned() { 331747ad3c4Slazypassion write_value_aliases(w, aliases, a, indent)?; 332747ad3c4Slazypassion } 3338f95c517SYury Delendik 3348f95c517SYury Delendik if isa.is_some() && !func.offsets.is_empty() { 3358f95c517SYury Delendik let encinfo = isa.unwrap().encoding_info(); 3368f95c517SYury Delendik let regs = &isa.unwrap().register_info(); 3378f95c517SYury Delendik for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) { 3388f95c517SYury Delendik func_w.write_instruction(w, func, aliases, isa, inst, indent)?; 3398f95c517SYury Delendik if size > 0 { 3408f95c517SYury Delendik if let Some(val_ranges) = annotations.value_ranges { 3418f95c517SYury Delendik write_value_range_markers(w, val_ranges, regs, offset + size, indent)?; 3428f95c517SYury Delendik } 3438f95c517SYury Delendik } 3448f95c517SYury Delendik } 3458f95c517SYury Delendik } else { 346747ad3c4Slazypassion for inst in func.layout.ebb_insts(ebb) { 347747ad3c4Slazypassion func_w.write_instruction(w, func, aliases, isa, inst, indent)?; 348747ad3c4Slazypassion } 3498f95c517SYury Delendik } 350747ad3c4Slazypassion 351747ad3c4Slazypassion Ok(()) 352747ad3c4Slazypassion } 353747ad3c4Slazypassion 354747ad3c4Slazypassion //---------------------------------------------------------------------- 355747ad3c4Slazypassion // 356747ad3c4Slazypassion // Instructions 357747ad3c4Slazypassion 358747ad3c4Slazypassion // Should `inst` be printed with a type suffix? 359747ad3c4Slazypassion // 360747ad3c4Slazypassion // Polymorphic instructions may need a suffix indicating the value of the controlling type variable 361747ad3c4Slazypassion // if it can't be trivially inferred. 362747ad3c4Slazypassion // 363747ad3c4Slazypassion fn type_suffix(func: &Function, inst: Inst) -> Option<Type> { 364747ad3c4Slazypassion let inst_data = &func.dfg[inst]; 365747ad3c4Slazypassion let constraints = inst_data.opcode().constraints(); 366747ad3c4Slazypassion 367747ad3c4Slazypassion if !constraints.is_polymorphic() { 368747ad3c4Slazypassion return None; 369747ad3c4Slazypassion } 370747ad3c4Slazypassion 371747ad3c4Slazypassion // If the controlling type variable can be inferred from the type of the designated value input 372747ad3c4Slazypassion // operand, we don't need the type suffix. 373747ad3c4Slazypassion if constraints.use_typevar_operand() { 374747ad3c4Slazypassion let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap(); 375747ad3c4Slazypassion let def_ebb = match func.dfg.value_def(ctrl_var) { 376747ad3c4Slazypassion ValueDef::Result(instr, _) => func.layout.inst_ebb(instr), 377747ad3c4Slazypassion ValueDef::Param(ebb, _) => Some(ebb), 378747ad3c4Slazypassion }; 379747ad3c4Slazypassion if def_ebb.is_some() && def_ebb == func.layout.inst_ebb(inst) { 380747ad3c4Slazypassion return None; 381747ad3c4Slazypassion } 382747ad3c4Slazypassion } 383747ad3c4Slazypassion 384747ad3c4Slazypassion let rtype = func.dfg.ctrl_typevar(inst); 385747ad3c4Slazypassion assert!( 386747ad3c4Slazypassion !rtype.is_invalid(), 387747ad3c4Slazypassion "Polymorphic instruction must produce a result" 388747ad3c4Slazypassion ); 389747ad3c4Slazypassion Some(rtype) 390747ad3c4Slazypassion } 391747ad3c4Slazypassion 392747ad3c4Slazypassion /// Write out any aliases to the given target, including indirect aliases 393747ad3c4Slazypassion fn write_value_aliases( 394d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 395747ad3c4Slazypassion aliases: &SecondaryMap<Value, Vec<Value>>, 396747ad3c4Slazypassion target: Value, 397747ad3c4Slazypassion indent: usize, 398747ad3c4Slazypassion ) -> fmt::Result { 399747ad3c4Slazypassion let mut todo_stack = vec![target]; 400747ad3c4Slazypassion while let Some(target) = todo_stack.pop() { 401747ad3c4Slazypassion for &a in &aliases[target] { 402747ad3c4Slazypassion writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?; 403747ad3c4Slazypassion todo_stack.push(a); 404747ad3c4Slazypassion } 405747ad3c4Slazypassion } 406747ad3c4Slazypassion 407747ad3c4Slazypassion Ok(()) 408747ad3c4Slazypassion } 409747ad3c4Slazypassion 410747ad3c4Slazypassion fn write_instruction( 411d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 412747ad3c4Slazypassion func: &Function, 413747ad3c4Slazypassion aliases: &SecondaryMap<Value, Vec<Value>>, 414d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 415747ad3c4Slazypassion inst: Inst, 416747ad3c4Slazypassion indent: usize, 417747ad3c4Slazypassion ) -> fmt::Result { 418747ad3c4Slazypassion // Prefix containing source location, encoding, and value locations. 419747ad3c4Slazypassion let mut s = String::with_capacity(16); 420747ad3c4Slazypassion 421747ad3c4Slazypassion // Source location goes first. 422747ad3c4Slazypassion let srcloc = func.srclocs[inst]; 423747ad3c4Slazypassion if !srcloc.is_default() { 424747ad3c4Slazypassion write!(s, "{} ", srcloc)?; 425747ad3c4Slazypassion } 426747ad3c4Slazypassion 427747ad3c4Slazypassion // Write out encoding info. 428747ad3c4Slazypassion if let Some(enc) = func.encodings.get(inst).cloned() { 429747ad3c4Slazypassion if let Some(isa) = isa { 430747ad3c4Slazypassion write!(s, "[{}", isa.encoding_info().display(enc))?; 431747ad3c4Slazypassion // Write value locations, if we have them. 432747ad3c4Slazypassion if !func.locations.is_empty() { 433747ad3c4Slazypassion let regs = isa.register_info(); 434747ad3c4Slazypassion for &r in func.dfg.inst_results(inst) { 435747ad3c4Slazypassion write!(s, ",{}", func.locations[r].display(®s))? 436747ad3c4Slazypassion } 437747ad3c4Slazypassion } 438747ad3c4Slazypassion write!(s, "] ")?; 439747ad3c4Slazypassion } else { 440747ad3c4Slazypassion write!(s, "[{}] ", enc)?; 441747ad3c4Slazypassion } 442747ad3c4Slazypassion } 443747ad3c4Slazypassion 444747ad3c4Slazypassion // Write out prefix and indent the instruction. 445747ad3c4Slazypassion write!(w, "{1:0$}", indent, s)?; 446747ad3c4Slazypassion 447747ad3c4Slazypassion // Write out the result values, if any. 448747ad3c4Slazypassion let mut has_results = false; 449747ad3c4Slazypassion for r in func.dfg.inst_results(inst) { 450747ad3c4Slazypassion if !has_results { 451747ad3c4Slazypassion has_results = true; 452747ad3c4Slazypassion write!(w, "{}", r)?; 453747ad3c4Slazypassion } else { 454747ad3c4Slazypassion write!(w, ", {}", r)?; 455747ad3c4Slazypassion } 456747ad3c4Slazypassion } 457747ad3c4Slazypassion if has_results { 458747ad3c4Slazypassion write!(w, " = ")?; 459747ad3c4Slazypassion } 460747ad3c4Slazypassion 461747ad3c4Slazypassion // Then the opcode, possibly with a '.type' suffix. 462747ad3c4Slazypassion let opcode = func.dfg[inst].opcode(); 463747ad3c4Slazypassion 464747ad3c4Slazypassion match type_suffix(func, inst) { 465747ad3c4Slazypassion Some(suf) => write!(w, "{}.{}", opcode, suf)?, 466747ad3c4Slazypassion None => write!(w, "{}", opcode)?, 467747ad3c4Slazypassion } 468747ad3c4Slazypassion 469747ad3c4Slazypassion write_operands(w, &func.dfg, isa, inst)?; 470747ad3c4Slazypassion writeln!(w)?; 471747ad3c4Slazypassion 472747ad3c4Slazypassion // Value aliases come out on lines after the instruction defining the referent. 473747ad3c4Slazypassion for r in func.dfg.inst_results(inst) { 474747ad3c4Slazypassion write_value_aliases(w, aliases, *r, indent)?; 475747ad3c4Slazypassion } 476747ad3c4Slazypassion Ok(()) 477747ad3c4Slazypassion } 478747ad3c4Slazypassion 479747ad3c4Slazypassion /// Write the operands of `inst` to `w` with a prepended space. 480747ad3c4Slazypassion pub fn write_operands( 481d7d48d5cSBenjamin Bouvier w: &mut dyn Write, 482747ad3c4Slazypassion dfg: &DataFlowGraph, 483d7d48d5cSBenjamin Bouvier isa: Option<&dyn TargetIsa>, 484747ad3c4Slazypassion inst: Inst, 485747ad3c4Slazypassion ) -> fmt::Result { 486747ad3c4Slazypassion let pool = &dfg.value_lists; 487747ad3c4Slazypassion use crate::ir::instructions::InstructionData::*; 488747ad3c4Slazypassion match dfg[inst] { 489747ad3c4Slazypassion Unary { arg, .. } => write!(w, " {}", arg), 490747ad3c4Slazypassion UnaryImm { imm, .. } => write!(w, " {}", imm), 491747ad3c4Slazypassion UnaryIeee32 { imm, .. } => write!(w, " {}", imm), 492747ad3c4Slazypassion UnaryIeee64 { imm, .. } => write!(w, " {}", imm), 493747ad3c4Slazypassion UnaryBool { imm, .. } => write!(w, " {}", imm), 494747ad3c4Slazypassion UnaryGlobalValue { global_value, .. } => write!(w, " {}", global_value), 495747ad3c4Slazypassion Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]), 496747ad3c4Slazypassion BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm), 497747ad3c4Slazypassion Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]), 498747ad3c4Slazypassion MultiAry { ref args, .. } => { 499747ad3c4Slazypassion if args.is_empty() { 500747ad3c4Slazypassion write!(w, "") 501747ad3c4Slazypassion } else { 502747ad3c4Slazypassion write!(w, " {}", DisplayValues(args.as_slice(pool))) 503747ad3c4Slazypassion } 504747ad3c4Slazypassion } 505747ad3c4Slazypassion NullAry { .. } => write!(w, " "), 506747ad3c4Slazypassion InsertLane { lane, args, .. } => write!(w, " {}, {}, {}", args[0], lane, args[1]), 507747ad3c4Slazypassion ExtractLane { lane, arg, .. } => write!(w, " {}, {}", arg, lane), 508af1499ceSAndrew Brown UnaryConst { 509af1499ceSAndrew Brown constant_handle, .. 510af1499ceSAndrew Brown } => { 511af1499ceSAndrew Brown let data = dfg.constants.get(constant_handle); 512cd426cb7SAndrew Brown let v128 = V128Imm::from(&data[..]); 513cd426cb7SAndrew Brown write!(w, " {}", v128) 514af1499ceSAndrew Brown } 515af1499ceSAndrew Brown Shuffle { mask, args, .. } => { 516af1499ceSAndrew Brown let data = dfg.immediates.get(mask).expect( 517af1499ceSAndrew Brown "Expected the shuffle mask to already be inserted into the immediates table", 518af1499ceSAndrew Brown ); 519cd426cb7SAndrew Brown let v128 = V128Imm::from(&data[..]); 520cd426cb7SAndrew Brown write!(w, " {}, {}, {}", args[0], args[1], v128) 521af1499ceSAndrew Brown } 522747ad3c4Slazypassion IntCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]), 523747ad3c4Slazypassion IntCompareImm { cond, arg, imm, .. } => write!(w, " {} {}, {}", cond, arg, imm), 524747ad3c4Slazypassion IntCond { cond, arg, .. } => write!(w, " {} {}", cond, arg), 525747ad3c4Slazypassion FloatCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]), 526747ad3c4Slazypassion FloatCond { cond, arg, .. } => write!(w, " {} {}", cond, arg), 527747ad3c4Slazypassion IntSelect { cond, args, .. } => { 528747ad3c4Slazypassion write!(w, " {} {}, {}, {}", cond, args[0], args[1], args[2]) 529747ad3c4Slazypassion } 530747ad3c4Slazypassion Jump { 531747ad3c4Slazypassion destination, 532747ad3c4Slazypassion ref args, 533747ad3c4Slazypassion .. 534747ad3c4Slazypassion } => { 535747ad3c4Slazypassion write!(w, " {}", destination)?; 536747ad3c4Slazypassion write_ebb_args(w, args.as_slice(pool)) 537747ad3c4Slazypassion } 538747ad3c4Slazypassion Branch { 539747ad3c4Slazypassion destination, 540747ad3c4Slazypassion ref args, 541747ad3c4Slazypassion .. 542747ad3c4Slazypassion } => { 543747ad3c4Slazypassion let args = args.as_slice(pool); 544747ad3c4Slazypassion write!(w, " {}, {}", args[0], destination)?; 545747ad3c4Slazypassion write_ebb_args(w, &args[1..]) 546747ad3c4Slazypassion } 547747ad3c4Slazypassion BranchInt { 548747ad3c4Slazypassion cond, 549747ad3c4Slazypassion destination, 550747ad3c4Slazypassion ref args, 551747ad3c4Slazypassion .. 552747ad3c4Slazypassion } => { 553747ad3c4Slazypassion let args = args.as_slice(pool); 554747ad3c4Slazypassion write!(w, " {} {}, {}", cond, args[0], destination)?; 555747ad3c4Slazypassion write_ebb_args(w, &args[1..]) 556747ad3c4Slazypassion } 557747ad3c4Slazypassion BranchFloat { 558747ad3c4Slazypassion cond, 559747ad3c4Slazypassion destination, 560747ad3c4Slazypassion ref args, 561747ad3c4Slazypassion .. 562747ad3c4Slazypassion } => { 563747ad3c4Slazypassion let args = args.as_slice(pool); 564747ad3c4Slazypassion write!(w, " {} {}, {}", cond, args[0], destination)?; 565747ad3c4Slazypassion write_ebb_args(w, &args[1..]) 566747ad3c4Slazypassion } 567747ad3c4Slazypassion BranchIcmp { 568747ad3c4Slazypassion cond, 569747ad3c4Slazypassion destination, 570747ad3c4Slazypassion ref args, 571747ad3c4Slazypassion .. 572747ad3c4Slazypassion } => { 573747ad3c4Slazypassion let args = args.as_slice(pool); 574747ad3c4Slazypassion write!(w, " {} {}, {}, {}", cond, args[0], args[1], destination)?; 575747ad3c4Slazypassion write_ebb_args(w, &args[2..]) 576747ad3c4Slazypassion } 577747ad3c4Slazypassion BranchTable { 578747ad3c4Slazypassion arg, 579747ad3c4Slazypassion destination, 580747ad3c4Slazypassion table, 581747ad3c4Slazypassion .. 582747ad3c4Slazypassion } => write!(w, " {}, {}, {}", arg, destination, table), 583747ad3c4Slazypassion BranchTableBase { table, .. } => write!(w, " {}", table), 584747ad3c4Slazypassion BranchTableEntry { 585747ad3c4Slazypassion args, imm, table, .. 586747ad3c4Slazypassion } => write!(w, " {}, {}, {}, {}", args[0], args[1], imm, table), 587747ad3c4Slazypassion IndirectJump { arg, table, .. } => write!(w, " {}, {}", arg, table), 588747ad3c4Slazypassion Call { 589747ad3c4Slazypassion func_ref, ref args, .. 590747ad3c4Slazypassion } => write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool))), 591747ad3c4Slazypassion CallIndirect { 592747ad3c4Slazypassion sig_ref, ref args, .. 593747ad3c4Slazypassion } => { 594747ad3c4Slazypassion let args = args.as_slice(pool); 595747ad3c4Slazypassion write!( 596747ad3c4Slazypassion w, 597747ad3c4Slazypassion " {}, {}({})", 598747ad3c4Slazypassion sig_ref, 599747ad3c4Slazypassion args[0], 600747ad3c4Slazypassion DisplayValues(&args[1..]) 601747ad3c4Slazypassion ) 602747ad3c4Slazypassion } 603747ad3c4Slazypassion FuncAddr { func_ref, .. } => write!(w, " {}", func_ref), 604747ad3c4Slazypassion StackLoad { 605747ad3c4Slazypassion stack_slot, offset, .. 606747ad3c4Slazypassion } => write!(w, " {}{}", stack_slot, offset), 607747ad3c4Slazypassion StackStore { 608747ad3c4Slazypassion arg, 609747ad3c4Slazypassion stack_slot, 610747ad3c4Slazypassion offset, 611747ad3c4Slazypassion .. 612747ad3c4Slazypassion } => write!(w, " {}, {}{}", arg, stack_slot, offset), 613747ad3c4Slazypassion HeapAddr { heap, arg, imm, .. } => write!(w, " {}, {}, {}", heap, arg, imm), 614747ad3c4Slazypassion TableAddr { table, arg, .. } => write!(w, " {}, {}", table, arg), 615747ad3c4Slazypassion Load { 616747ad3c4Slazypassion flags, arg, offset, .. 617747ad3c4Slazypassion } => write!(w, "{} {}{}", flags, arg, offset), 618747ad3c4Slazypassion LoadComplex { 619747ad3c4Slazypassion flags, 620747ad3c4Slazypassion ref args, 621747ad3c4Slazypassion offset, 622747ad3c4Slazypassion .. 623747ad3c4Slazypassion } => { 624747ad3c4Slazypassion let args = args.as_slice(pool); 625747ad3c4Slazypassion write!( 626747ad3c4Slazypassion w, 627747ad3c4Slazypassion "{} {}{}", 628747ad3c4Slazypassion flags, 629747ad3c4Slazypassion DisplayValuesWithDelimiter(&args, '+'), 630747ad3c4Slazypassion offset 631747ad3c4Slazypassion ) 632747ad3c4Slazypassion } 633747ad3c4Slazypassion Store { 634747ad3c4Slazypassion flags, 635747ad3c4Slazypassion args, 636747ad3c4Slazypassion offset, 637747ad3c4Slazypassion .. 638747ad3c4Slazypassion } => write!(w, "{} {}, {}{}", flags, args[0], args[1], offset), 639747ad3c4Slazypassion StoreComplex { 640747ad3c4Slazypassion flags, 641747ad3c4Slazypassion ref args, 642747ad3c4Slazypassion offset, 643747ad3c4Slazypassion .. 644747ad3c4Slazypassion } => { 645747ad3c4Slazypassion let args = args.as_slice(pool); 646747ad3c4Slazypassion write!( 647747ad3c4Slazypassion w, 648747ad3c4Slazypassion "{} {}, {}{}", 649747ad3c4Slazypassion flags, 650747ad3c4Slazypassion args[0], 651747ad3c4Slazypassion DisplayValuesWithDelimiter(&args[1..], '+'), 652747ad3c4Slazypassion offset 653747ad3c4Slazypassion ) 654747ad3c4Slazypassion } 655747ad3c4Slazypassion RegMove { arg, src, dst, .. } => { 656747ad3c4Slazypassion if let Some(isa) = isa { 657747ad3c4Slazypassion let regs = isa.register_info(); 658747ad3c4Slazypassion write!( 659747ad3c4Slazypassion w, 660747ad3c4Slazypassion " {}, {} -> {}", 661747ad3c4Slazypassion arg, 662747ad3c4Slazypassion regs.display_regunit(src), 663747ad3c4Slazypassion regs.display_regunit(dst) 664747ad3c4Slazypassion ) 665747ad3c4Slazypassion } else { 666747ad3c4Slazypassion write!(w, " {}, %{} -> %{}", arg, src, dst) 667747ad3c4Slazypassion } 668747ad3c4Slazypassion } 669747ad3c4Slazypassion CopySpecial { src, dst, .. } => { 670747ad3c4Slazypassion if let Some(isa) = isa { 671747ad3c4Slazypassion let regs = isa.register_info(); 672747ad3c4Slazypassion write!( 673747ad3c4Slazypassion w, 674747ad3c4Slazypassion " {} -> {}", 675747ad3c4Slazypassion regs.display_regunit(src), 676747ad3c4Slazypassion regs.display_regunit(dst) 677747ad3c4Slazypassion ) 678747ad3c4Slazypassion } else { 679747ad3c4Slazypassion write!(w, " %{} -> %{}", src, dst) 680747ad3c4Slazypassion } 681747ad3c4Slazypassion } 682b8fb5244Sjulian-seward1 CopyToSsa { src, .. } => { 683b8fb5244Sjulian-seward1 if let Some(isa) = isa { 684b8fb5244Sjulian-seward1 let regs = isa.register_info(); 685b8fb5244Sjulian-seward1 write!(w, " {}", regs.display_regunit(src)) 686b8fb5244Sjulian-seward1 } else { 687b8fb5244Sjulian-seward1 write!(w, " %{}", src) 688b8fb5244Sjulian-seward1 } 689b8fb5244Sjulian-seward1 } 690747ad3c4Slazypassion RegSpill { arg, src, dst, .. } => { 691747ad3c4Slazypassion if let Some(isa) = isa { 692747ad3c4Slazypassion let regs = isa.register_info(); 693747ad3c4Slazypassion write!(w, " {}, {} -> {}", arg, regs.display_regunit(src), dst) 694747ad3c4Slazypassion } else { 695747ad3c4Slazypassion write!(w, " {}, %{} -> {}", arg, src, dst) 696747ad3c4Slazypassion } 697747ad3c4Slazypassion } 698747ad3c4Slazypassion RegFill { arg, src, dst, .. } => { 699747ad3c4Slazypassion if let Some(isa) = isa { 700747ad3c4Slazypassion let regs = isa.register_info(); 701747ad3c4Slazypassion write!(w, " {}, {} -> {}", arg, src, regs.display_regunit(dst)) 702747ad3c4Slazypassion } else { 703747ad3c4Slazypassion write!(w, " {}, {} -> %{}", arg, src, dst) 704747ad3c4Slazypassion } 705747ad3c4Slazypassion } 706747ad3c4Slazypassion Trap { code, .. } => write!(w, " {}", code), 707747ad3c4Slazypassion CondTrap { arg, code, .. } => write!(w, " {}, {}", arg, code), 708747ad3c4Slazypassion IntCondTrap { 709747ad3c4Slazypassion cond, arg, code, .. 710747ad3c4Slazypassion } => write!(w, " {} {}, {}", cond, arg, code), 711747ad3c4Slazypassion FloatCondTrap { 712747ad3c4Slazypassion cond, arg, code, .. 713747ad3c4Slazypassion } => write!(w, " {} {}, {}", cond, arg, code), 714747ad3c4Slazypassion } 715747ad3c4Slazypassion } 716747ad3c4Slazypassion 717747ad3c4Slazypassion /// Write EBB args using optional parantheses. 718d7d48d5cSBenjamin Bouvier fn write_ebb_args(w: &mut dyn Write, args: &[Value]) -> fmt::Result { 719747ad3c4Slazypassion if args.is_empty() { 720747ad3c4Slazypassion Ok(()) 721747ad3c4Slazypassion } else { 722747ad3c4Slazypassion write!(w, "({})", DisplayValues(args)) 723747ad3c4Slazypassion } 724747ad3c4Slazypassion } 725747ad3c4Slazypassion 726747ad3c4Slazypassion /// Displayable slice of values. 727747ad3c4Slazypassion struct DisplayValues<'a>(&'a [Value]); 728747ad3c4Slazypassion 729747ad3c4Slazypassion impl<'a> fmt::Display for DisplayValues<'a> { 730747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 731747ad3c4Slazypassion for (i, val) in self.0.iter().enumerate() { 732747ad3c4Slazypassion if i == 0 { 733747ad3c4Slazypassion write!(f, "{}", val)?; 734747ad3c4Slazypassion } else { 735747ad3c4Slazypassion write!(f, ", {}", val)?; 736747ad3c4Slazypassion } 737747ad3c4Slazypassion } 738747ad3c4Slazypassion Ok(()) 739747ad3c4Slazypassion } 740747ad3c4Slazypassion } 741747ad3c4Slazypassion 742747ad3c4Slazypassion struct DisplayValuesWithDelimiter<'a>(&'a [Value], char); 743747ad3c4Slazypassion 744747ad3c4Slazypassion impl<'a> fmt::Display for DisplayValuesWithDelimiter<'a> { 745747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 746747ad3c4Slazypassion for (i, val) in self.0.iter().enumerate() { 747747ad3c4Slazypassion if i == 0 { 748747ad3c4Slazypassion write!(f, "{}", val)?; 749747ad3c4Slazypassion } else { 750747ad3c4Slazypassion write!(f, "{}{}", self.1, val)?; 751747ad3c4Slazypassion } 752747ad3c4Slazypassion } 753747ad3c4Slazypassion Ok(()) 754747ad3c4Slazypassion } 755747ad3c4Slazypassion } 756747ad3c4Slazypassion 757747ad3c4Slazypassion #[cfg(test)] 758747ad3c4Slazypassion mod tests { 759747ad3c4Slazypassion use crate::cursor::{Cursor, CursorPosition, FuncCursor}; 760747ad3c4Slazypassion use crate::ir::types; 761747ad3c4Slazypassion use crate::ir::{ExternalName, Function, InstBuilder, StackSlotData, StackSlotKind}; 76210e226f9Sbjorn3 use alloc::string::ToString; 763747ad3c4Slazypassion 764747ad3c4Slazypassion #[test] 765747ad3c4Slazypassion fn basic() { 766747ad3c4Slazypassion let mut f = Function::new(); 767747ad3c4Slazypassion assert_eq!(f.to_string(), "function u0:0() fast {\n}\n"); 768747ad3c4Slazypassion 769747ad3c4Slazypassion f.name = ExternalName::testcase("foo"); 770747ad3c4Slazypassion assert_eq!(f.to_string(), "function %foo() fast {\n}\n"); 771747ad3c4Slazypassion 772747ad3c4Slazypassion f.create_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4)); 773747ad3c4Slazypassion assert_eq!( 774747ad3c4Slazypassion f.to_string(), 775747ad3c4Slazypassion "function %foo() fast {\n ss0 = explicit_slot 4\n}\n" 776747ad3c4Slazypassion ); 777747ad3c4Slazypassion 778747ad3c4Slazypassion let ebb = f.dfg.make_ebb(); 779747ad3c4Slazypassion f.layout.append_ebb(ebb); 780747ad3c4Slazypassion assert_eq!( 781747ad3c4Slazypassion f.to_string(), 782747ad3c4Slazypassion "function %foo() fast {\n ss0 = explicit_slot 4\n\nebb0:\n}\n" 783747ad3c4Slazypassion ); 784747ad3c4Slazypassion 785747ad3c4Slazypassion f.dfg.append_ebb_param(ebb, types::I8); 786747ad3c4Slazypassion assert_eq!( 787747ad3c4Slazypassion f.to_string(), 788747ad3c4Slazypassion "function %foo() fast {\n ss0 = explicit_slot 4\n\nebb0(v0: i8):\n}\n" 789747ad3c4Slazypassion ); 790747ad3c4Slazypassion 791747ad3c4Slazypassion f.dfg.append_ebb_param(ebb, types::F32.by(4).unwrap()); 792747ad3c4Slazypassion assert_eq!( 793747ad3c4Slazypassion f.to_string(), 794747ad3c4Slazypassion "function %foo() fast {\n ss0 = explicit_slot 4\n\nebb0(v0: i8, v1: f32x4):\n}\n" 795747ad3c4Slazypassion ); 796747ad3c4Slazypassion 797747ad3c4Slazypassion { 798747ad3c4Slazypassion let mut cursor = FuncCursor::new(&mut f); 799747ad3c4Slazypassion cursor.set_position(CursorPosition::After(ebb)); 800747ad3c4Slazypassion cursor.ins().return_(&[]) 801747ad3c4Slazypassion }; 802747ad3c4Slazypassion assert_eq!( 803747ad3c4Slazypassion f.to_string(), 804747ad3c4Slazypassion "function %foo() fast {\n ss0 = explicit_slot 4\n\nebb0(v0: i8, v1: f32x4):\n return\n}\n" 805747ad3c4Slazypassion ); 806747ad3c4Slazypassion } 807747ad3c4Slazypassion 808747ad3c4Slazypassion #[test] 809747ad3c4Slazypassion fn aliases() { 810747ad3c4Slazypassion use crate::ir::InstBuilder; 811747ad3c4Slazypassion 812747ad3c4Slazypassion let mut func = Function::new(); 813747ad3c4Slazypassion { 814747ad3c4Slazypassion let ebb0 = func.dfg.make_ebb(); 815747ad3c4Slazypassion let mut pos = FuncCursor::new(&mut func); 816747ad3c4Slazypassion pos.insert_ebb(ebb0); 817747ad3c4Slazypassion 818747ad3c4Slazypassion // make some detached values for change_to_alias 819747ad3c4Slazypassion let v0 = pos.func.dfg.append_ebb_param(ebb0, types::I32); 820747ad3c4Slazypassion let v1 = pos.func.dfg.append_ebb_param(ebb0, types::I32); 821747ad3c4Slazypassion let v2 = pos.func.dfg.append_ebb_param(ebb0, types::I32); 822747ad3c4Slazypassion pos.func.dfg.detach_ebb_params(ebb0); 823747ad3c4Slazypassion 824747ad3c4Slazypassion // alias to a param--will be printed at beginning of ebb defining param 825747ad3c4Slazypassion let v3 = pos.func.dfg.append_ebb_param(ebb0, types::I32); 826747ad3c4Slazypassion pos.func.dfg.change_to_alias(v0, v3); 827747ad3c4Slazypassion 828747ad3c4Slazypassion // alias to an alias--should print attached to alias, not ultimate target 829747ad3c4Slazypassion pos.func.dfg.make_value_alias_for_serialization(v0, v2); // v0 <- v2 830747ad3c4Slazypassion 831747ad3c4Slazypassion // alias to a result--will be printed after instruction producing result 832747ad3c4Slazypassion let _dummy0 = pos.ins().iconst(types::I32, 42); 833747ad3c4Slazypassion let v4 = pos.ins().iadd(v0, v0); 834747ad3c4Slazypassion pos.func.dfg.change_to_alias(v1, v4); 835747ad3c4Slazypassion let _dummy1 = pos.ins().iconst(types::I32, 23); 836747ad3c4Slazypassion let _v7 = pos.ins().iadd(v1, v1); 837747ad3c4Slazypassion } 838747ad3c4Slazypassion assert_eq!( 839747ad3c4Slazypassion func.to_string(), 840747ad3c4Slazypassion "function u0:0() fast {\nebb0(v3: i32):\n v0 -> v3\n v2 -> v0\n v4 = iconst.i32 42\n v5 = iadd v0, v0\n v1 -> v5\n v6 = iconst.i32 23\n v7 = iadd v1, v1\n}\n" 841747ad3c4Slazypassion ); 842747ad3c4Slazypassion } 843747ad3c4Slazypassion } 844