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(&regs))?
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