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;
841eca60bSbeetrees use crate::ir::immediates::Ieee128;
941eca60bSbeetrees use crate::ir::{Block, DataFlowGraph, Function, Inst, Opcode, SigRef, Type, Value, ValueDef};
10747ad3c4Slazypassion use crate::packed_option::ReservedValue;
113629bbbdSJamey Sharp use alloc::string::{String, ToString};
1210e226f9Sbjorn3 use alloc::vec::Vec;
13bb8fa40eSbjorn3 use core::fmt::{self, Write};
14747ad3c4Slazypassion 
15747ad3c4Slazypassion /// A `FuncWriter` used to decorate functions during printing.
16747ad3c4Slazypassion pub trait FuncWriter {
17832666c4SRyan Hunt     /// Write the basic block header for the current function.
write_block_header( &mut self, w: &mut dyn Write, func: &Function, block: Block, indent: usize, ) -> fmt::Result18832666c4SRyan Hunt     fn write_block_header(
19747ad3c4Slazypassion         &mut self,
20d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
21747ad3c4Slazypassion         func: &Function,
22832666c4SRyan Hunt         block: Block,
23747ad3c4Slazypassion         indent: usize,
24747ad3c4Slazypassion     ) -> fmt::Result;
25747ad3c4Slazypassion 
26747ad3c4Slazypassion     /// Write the given `inst` to `w`.
write_instruction( &mut self, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, inst: Inst, indent: usize, ) -> fmt::Result27747ad3c4Slazypassion     fn write_instruction(
28747ad3c4Slazypassion         &mut self,
29d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
30747ad3c4Slazypassion         func: &Function,
31747ad3c4Slazypassion         aliases: &SecondaryMap<Value, Vec<Value>>,
32747ad3c4Slazypassion         inst: Inst,
33747ad3c4Slazypassion         indent: usize,
34747ad3c4Slazypassion     ) -> fmt::Result;
35747ad3c4Slazypassion 
36747ad3c4Slazypassion     /// Write the preamble to `w`. By default, this uses `write_entity_definition`.
write_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error>3743a86f14SBenjamin Bouvier     fn write_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error> {
3843a86f14SBenjamin Bouvier         self.super_preamble(w, func)
39747ad3c4Slazypassion     }
40747ad3c4Slazypassion 
41747ad3c4Slazypassion     /// Default impl of `write_preamble`
super_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error>4243a86f14SBenjamin Bouvier     fn super_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error> {
43747ad3c4Slazypassion         let mut any = false;
44747ad3c4Slazypassion 
459c43749dSSam Parker         for (ss, slot) in func.dynamic_stack_slots.iter() {
469c43749dSSam Parker             any = true;
47*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, ss.into(), slot)?;
489c43749dSSam Parker         }
499c43749dSSam Parker 
509c43749dSSam Parker         for (ss, slot) in func.sized_stack_slots.iter() {
51747ad3c4Slazypassion             any = true;
52*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, ss.into(), slot)?;
53747ad3c4Slazypassion         }
54747ad3c4Slazypassion 
55747ad3c4Slazypassion         for (gv, gv_data) in &func.global_values {
56747ad3c4Slazypassion             any = true;
57*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, gv.into(), gv_data)?;
581ced3e8eSChris Fallin         }
591ced3e8eSChris Fallin 
60747ad3c4Slazypassion         // Write out all signatures before functions since function declarations can refer to
61747ad3c4Slazypassion         // signatures.
62747ad3c4Slazypassion         for (sig, sig_data) in &func.dfg.signatures {
63747ad3c4Slazypassion             any = true;
64*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, sig.into(), &sig_data)?;
65747ad3c4Slazypassion         }
66747ad3c4Slazypassion 
67747ad3c4Slazypassion         for (fnref, ext_func) in &func.dfg.ext_funcs {
68747ad3c4Slazypassion             if ext_func.signature != SigRef::reserved_value() {
69747ad3c4Slazypassion                 any = true;
708a9b1a90SBenjamin Bouvier                 self.write_entity_definition(
718a9b1a90SBenjamin Bouvier                     w,
728a9b1a90SBenjamin Bouvier                     func,
738a9b1a90SBenjamin Bouvier                     fnref.into(),
748a9b1a90SBenjamin Bouvier                     &ext_func.display(Some(&func.params)),
758a9b1a90SBenjamin Bouvier                 )?;
76747ad3c4Slazypassion             }
77747ad3c4Slazypassion         }
78747ad3c4Slazypassion 
790672d1dcSAndrew Brown         for (&cref, cval) in func.dfg.constants.iter() {
800672d1dcSAndrew Brown             any = true;
81*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, cref.into(), cval)?;
820672d1dcSAndrew Brown         }
830672d1dcSAndrew Brown 
84c9a0ba81SAlex Crichton         if let Some(limit) = func.stack_limit {
85c9a0ba81SAlex Crichton             any = true;
86*2f7dbd61SChris Fallin             self.write_entity_definition(w, func, AnyEntity::StackLimit, &limit)?;
87c9a0ba81SAlex Crichton         }
88c9a0ba81SAlex Crichton 
89747ad3c4Slazypassion         Ok(any)
90747ad3c4Slazypassion     }
91747ad3c4Slazypassion 
92747ad3c4Slazypassion     /// Write an entity definition defined in the preamble to `w`.
write_entity_definition( &mut self, w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, ) -> fmt::Result93747ad3c4Slazypassion     fn write_entity_definition(
94747ad3c4Slazypassion         &mut self,
95d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
96747ad3c4Slazypassion         func: &Function,
97747ad3c4Slazypassion         entity: AnyEntity,
98d7d48d5cSBenjamin Bouvier         value: &dyn fmt::Display,
99747ad3c4Slazypassion     ) -> fmt::Result {
100*2f7dbd61SChris Fallin         self.super_entity_definition(w, func, entity, value)
101747ad3c4Slazypassion     }
102747ad3c4Slazypassion 
103747ad3c4Slazypassion     /// Default impl of `write_entity_definition`
super_entity_definition( &mut self, w: &mut dyn Write, _func: &Function, entity: AnyEntity, value: &dyn fmt::Display, ) -> fmt::Result104747ad3c4Slazypassion     fn super_entity_definition(
105747ad3c4Slazypassion         &mut self,
106d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
107099102d9SAlex Crichton         _func: &Function,
108747ad3c4Slazypassion         entity: AnyEntity,
109d7d48d5cSBenjamin Bouvier         value: &dyn fmt::Display,
110747ad3c4Slazypassion     ) -> fmt::Result {
111a0442ea0SHamir Mahal         writeln!(w, "    {entity} = {value}")
112747ad3c4Slazypassion     }
113747ad3c4Slazypassion }
114747ad3c4Slazypassion 
115747ad3c4Slazypassion /// A `PlainWriter` that doesn't decorate the function.
116747ad3c4Slazypassion pub struct PlainWriter;
117747ad3c4Slazypassion 
118747ad3c4Slazypassion impl FuncWriter for PlainWriter {
write_instruction( &mut self, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, inst: Inst, indent: usize, ) -> fmt::Result119747ad3c4Slazypassion     fn write_instruction(
120747ad3c4Slazypassion         &mut self,
121d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
122747ad3c4Slazypassion         func: &Function,
123747ad3c4Slazypassion         aliases: &SecondaryMap<Value, Vec<Value>>,
124747ad3c4Slazypassion         inst: Inst,
125747ad3c4Slazypassion         indent: usize,
126747ad3c4Slazypassion     ) -> fmt::Result {
12743a86f14SBenjamin Bouvier         write_instruction(w, func, aliases, inst, indent)
128747ad3c4Slazypassion     }
129747ad3c4Slazypassion 
write_block_header( &mut self, w: &mut dyn Write, func: &Function, block: Block, indent: usize, ) -> fmt::Result130832666c4SRyan Hunt     fn write_block_header(
131747ad3c4Slazypassion         &mut self,
132d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
133747ad3c4Slazypassion         func: &Function,
134832666c4SRyan Hunt         block: Block,
135747ad3c4Slazypassion         indent: usize,
136747ad3c4Slazypassion     ) -> fmt::Result {
13743a86f14SBenjamin Bouvier         write_block_header(w, func, block, indent)
138747ad3c4Slazypassion     }
139747ad3c4Slazypassion }
140747ad3c4Slazypassion 
141747ad3c4Slazypassion /// Write `func` to `w` as equivalent text.
142747ad3c4Slazypassion /// Use `isa` to emit ISA-dependent annotations.
write_function(w: &mut dyn Write, func: &Function) -> fmt::Result14343a86f14SBenjamin Bouvier pub fn write_function(w: &mut dyn Write, func: &Function) -> fmt::Result {
14443a86f14SBenjamin Bouvier     decorate_function(&mut PlainWriter, w, func)
145747ad3c4Slazypassion }
146747ad3c4Slazypassion 
147747ad3c4Slazypassion /// Create a reverse-alias map from a value to all aliases having that value as a direct target
alias_map(func: &Function) -> SecondaryMap<Value, Vec<Value>>148747ad3c4Slazypassion fn alias_map(func: &Function) -> SecondaryMap<Value, Vec<Value>> {
149747ad3c4Slazypassion     let mut aliases = SecondaryMap::<_, Vec<_>>::new();
150747ad3c4Slazypassion     for v in func.dfg.values() {
151747ad3c4Slazypassion         // VADFS returns the immediate target of an alias
152747ad3c4Slazypassion         if let Some(k) = func.dfg.value_alias_dest_for_serialization(v) {
153747ad3c4Slazypassion             aliases[k].push(v);
154747ad3c4Slazypassion         }
155747ad3c4Slazypassion     }
156747ad3c4Slazypassion     aliases
157747ad3c4Slazypassion }
158747ad3c4Slazypassion 
159747ad3c4Slazypassion /// Writes `func` to `w` as text.
160747ad3c4Slazypassion /// write_function_plain is passed as 'closure' to print instructions as text.
161747ad3c4Slazypassion /// pretty_function_error is passed as 'closure' to add error decoration.
decorate_function<FW: FuncWriter>( func_w: &mut FW, w: &mut dyn Write, func: &Function, ) -> fmt::Result162747ad3c4Slazypassion pub fn decorate_function<FW: FuncWriter>(
163747ad3c4Slazypassion     func_w: &mut FW,
164d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
165747ad3c4Slazypassion     func: &Function,
166747ad3c4Slazypassion ) -> fmt::Result {
167747ad3c4Slazypassion     write!(w, "function ")?;
1683da7fc8eSSingleAccretion     write_function_spec(w, func)?;
169747ad3c4Slazypassion     writeln!(w, " {{")?;
170747ad3c4Slazypassion     let aliases = alias_map(func);
17143a86f14SBenjamin Bouvier     let mut any = func_w.write_preamble(w, func)?;
172832666c4SRyan Hunt     for block in &func.layout {
173747ad3c4Slazypassion         if any {
174747ad3c4Slazypassion             writeln!(w)?;
175747ad3c4Slazypassion         }
17643a86f14SBenjamin Bouvier         decorate_block(func_w, w, func, &aliases, block)?;
177747ad3c4Slazypassion         any = true;
178747ad3c4Slazypassion     }
179747ad3c4Slazypassion     writeln!(w, "}}")
180747ad3c4Slazypassion }
181747ad3c4Slazypassion 
182747ad3c4Slazypassion //----------------------------------------------------------------------
183747ad3c4Slazypassion //
184747ad3c4Slazypassion // Function spec.
185747ad3c4Slazypassion 
1863da7fc8eSSingleAccretion /// Writes the spec (name and signature) of 'func' to 'w' as text.
write_function_spec(w: &mut dyn Write, func: &Function) -> fmt::Result1873da7fc8eSSingleAccretion pub fn write_function_spec(w: &mut dyn Write, func: &Function) -> fmt::Result {
18843a86f14SBenjamin Bouvier     write!(w, "{}{}", func.name, func.signature)
189747ad3c4Slazypassion }
190747ad3c4Slazypassion 
191747ad3c4Slazypassion //----------------------------------------------------------------------
192747ad3c4Slazypassion //
193747ad3c4Slazypassion // Basic blocks
194747ad3c4Slazypassion 
write_arg(w: &mut dyn Write, func: &Function, arg: Value) -> fmt::Result19543a86f14SBenjamin Bouvier fn write_arg(w: &mut dyn Write, func: &Function, arg: Value) -> fmt::Result {
196f466aa26SChris Fallin     let ty = func.dfg.value_type(arg);
197a0442ea0SHamir Mahal     write!(w, "{arg}: {ty}")
198f466aa26SChris Fallin }
199747ad3c4Slazypassion 
200747ad3c4Slazypassion /// Write out the basic block header, outdented:
201747ad3c4Slazypassion ///
202832666c4SRyan Hunt ///    block1:
203832666c4SRyan Hunt ///    block1(v1: i32):
204689f7d48STrevor Elliott ///    block10(v4: f64, v5: i8):
205747ad3c4Slazypassion ///
write_block_header( w: &mut dyn Write, func: &Function, block: Block, indent: usize, ) -> fmt::Result206832666c4SRyan Hunt pub fn write_block_header(
207d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
208747ad3c4Slazypassion     func: &Function,
209832666c4SRyan Hunt     block: Block,
210747ad3c4Slazypassion     indent: usize,
211747ad3c4Slazypassion ) -> fmt::Result {
21251649d56SChris Fallin     let cold = if func.layout.is_cold(block) {
21351649d56SChris Fallin         " cold"
21451649d56SChris Fallin     } else {
21551649d56SChris Fallin         ""
21651649d56SChris Fallin     };
21751649d56SChris Fallin 
218832666c4SRyan Hunt     // The `indent` is the instruction indentation. block headers are 4 spaces out from that.
219832666c4SRyan Hunt     write!(w, "{1:0$}{2}", indent - 4, "", block)?;
220747ad3c4Slazypassion 
221832666c4SRyan Hunt     let mut args = func.dfg.block_params(block).iter().cloned();
222747ad3c4Slazypassion     match args.next() {
223a0442ea0SHamir Mahal         None => return writeln!(w, "{cold}:"),
224747ad3c4Slazypassion         Some(arg) => {
225747ad3c4Slazypassion             write!(w, "(")?;
22643a86f14SBenjamin Bouvier             write_arg(w, func, arg)?;
227747ad3c4Slazypassion         }
228747ad3c4Slazypassion     }
229747ad3c4Slazypassion     // Remaining arguments.
230747ad3c4Slazypassion     for arg in args {
231747ad3c4Slazypassion         write!(w, ", ")?;
23243a86f14SBenjamin Bouvier         write_arg(w, func, arg)?;
233747ad3c4Slazypassion     }
234a0442ea0SHamir Mahal     writeln!(w, "){cold}:")
235747ad3c4Slazypassion }
236747ad3c4Slazypassion 
decorate_block<FW: FuncWriter>( func_w: &mut FW, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, block: Block, ) -> fmt::Result237832666c4SRyan Hunt fn decorate_block<FW: FuncWriter>(
238747ad3c4Slazypassion     func_w: &mut FW,
239d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
240747ad3c4Slazypassion     func: &Function,
241747ad3c4Slazypassion     aliases: &SecondaryMap<Value, Vec<Value>>,
242832666c4SRyan Hunt     block: Block,
243747ad3c4Slazypassion ) -> fmt::Result {
244a3d6e407SChris Fallin     // Indent all instructions if any srclocs or debug tags are present.
245a3d6e407SChris Fallin     let indent = if func.rel_srclocs().is_empty() && func.debug_tags.is_empty() {
246a3d6e407SChris Fallin         4
247a3d6e407SChris Fallin     } else {
248a3d6e407SChris Fallin         36
249a3d6e407SChris Fallin     };
250747ad3c4Slazypassion 
25143a86f14SBenjamin Bouvier     func_w.write_block_header(w, func, block, indent)?;
252832666c4SRyan Hunt     for a in func.dfg.block_params(block).iter().cloned() {
253747ad3c4Slazypassion         write_value_aliases(w, aliases, a, indent)?;
254747ad3c4Slazypassion     }
2558f95c517SYury Delendik 
256832666c4SRyan Hunt     for inst in func.layout.block_insts(block) {
25743a86f14SBenjamin Bouvier         func_w.write_instruction(w, func, aliases, inst, indent)?;
258747ad3c4Slazypassion     }
259747ad3c4Slazypassion 
260747ad3c4Slazypassion     Ok(())
261747ad3c4Slazypassion }
262747ad3c4Slazypassion 
263747ad3c4Slazypassion //----------------------------------------------------------------------
264747ad3c4Slazypassion //
265747ad3c4Slazypassion // Instructions
266747ad3c4Slazypassion 
267747ad3c4Slazypassion // Should `inst` be printed with a type suffix?
268747ad3c4Slazypassion //
269747ad3c4Slazypassion // Polymorphic instructions may need a suffix indicating the value of the controlling type variable
270747ad3c4Slazypassion // if it can't be trivially inferred.
271747ad3c4Slazypassion //
type_suffix(func: &Function, inst: Inst) -> Option<Type>272747ad3c4Slazypassion fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
27325bf8e0eSTrevor Elliott     let inst_data = &func.dfg.insts[inst];
274747ad3c4Slazypassion     let constraints = inst_data.opcode().constraints();
275747ad3c4Slazypassion 
276747ad3c4Slazypassion     if !constraints.is_polymorphic() {
277747ad3c4Slazypassion         return None;
278747ad3c4Slazypassion     }
279747ad3c4Slazypassion 
280747ad3c4Slazypassion     // If the controlling type variable can be inferred from the type of the designated value input
281747ad3c4Slazypassion     // operand, we don't need the type suffix.
282747ad3c4Slazypassion     if constraints.use_typevar_operand() {
283747ad3c4Slazypassion         let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap();
284832666c4SRyan Hunt         let def_block = match func.dfg.value_def(ctrl_var) {
285832666c4SRyan Hunt             ValueDef::Result(instr, _) => func.layout.inst_block(instr),
286832666c4SRyan Hunt             ValueDef::Param(block, _) => Some(block),
287f980defeSChris Fallin             ValueDef::Union(..) => None,
288747ad3c4Slazypassion         };
289832666c4SRyan Hunt         if def_block.is_some() && def_block == func.layout.inst_block(inst) {
290747ad3c4Slazypassion             return None;
291747ad3c4Slazypassion         }
292747ad3c4Slazypassion     }
293747ad3c4Slazypassion 
294747ad3c4Slazypassion     let rtype = func.dfg.ctrl_typevar(inst);
295747ad3c4Slazypassion     assert!(
296747ad3c4Slazypassion         !rtype.is_invalid(),
297747ad3c4Slazypassion         "Polymorphic instruction must produce a result"
298747ad3c4Slazypassion     );
299747ad3c4Slazypassion     Some(rtype)
300747ad3c4Slazypassion }
301747ad3c4Slazypassion 
302747ad3c4Slazypassion /// Write out any aliases to the given target, including indirect aliases
write_value_aliases( w: &mut dyn Write, aliases: &SecondaryMap<Value, Vec<Value>>, target: Value, indent: usize, ) -> fmt::Result303747ad3c4Slazypassion fn write_value_aliases(
304d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
305747ad3c4Slazypassion     aliases: &SecondaryMap<Value, Vec<Value>>,
306747ad3c4Slazypassion     target: Value,
307747ad3c4Slazypassion     indent: usize,
308747ad3c4Slazypassion ) -> fmt::Result {
309747ad3c4Slazypassion     let mut todo_stack = vec![target];
310747ad3c4Slazypassion     while let Some(target) = todo_stack.pop() {
311747ad3c4Slazypassion         for &a in &aliases[target] {
312747ad3c4Slazypassion             writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?;
313747ad3c4Slazypassion             todo_stack.push(a);
314747ad3c4Slazypassion         }
315747ad3c4Slazypassion     }
316747ad3c4Slazypassion 
317747ad3c4Slazypassion     Ok(())
318747ad3c4Slazypassion }
319747ad3c4Slazypassion 
write_instruction( w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, inst: Inst, mut indent: usize, ) -> fmt::Result320747ad3c4Slazypassion fn write_instruction(
321d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
322747ad3c4Slazypassion     func: &Function,
323747ad3c4Slazypassion     aliases: &SecondaryMap<Value, Vec<Value>>,
324747ad3c4Slazypassion     inst: Inst,
325a3d6e407SChris Fallin     mut indent: usize,
326747ad3c4Slazypassion ) -> fmt::Result {
327747ad3c4Slazypassion     // Prefix containing source location, encoding, and value locations.
328747ad3c4Slazypassion     let mut s = String::with_capacity(16);
329747ad3c4Slazypassion 
330747ad3c4Slazypassion     // Source location goes first.
3318a9b1a90SBenjamin Bouvier     let srcloc = func.srcloc(inst);
332747ad3c4Slazypassion     if !srcloc.is_default() {
333a0442ea0SHamir Mahal         write!(s, "{srcloc} ")?;
334747ad3c4Slazypassion     }
335747ad3c4Slazypassion 
336a3d6e407SChris Fallin     // Write out any debug tags.
337a3d6e407SChris Fallin     write_debug_tags(w, &func, inst, &mut indent)?;
338a3d6e407SChris Fallin 
339747ad3c4Slazypassion     // Write out prefix and indent the instruction.
340a0442ea0SHamir Mahal     write!(w, "{s:indent$}")?;
341747ad3c4Slazypassion 
342747ad3c4Slazypassion     // Write out the result values, if any.
343747ad3c4Slazypassion     let mut has_results = false;
344747ad3c4Slazypassion     for r in func.dfg.inst_results(inst) {
345747ad3c4Slazypassion         if !has_results {
346747ad3c4Slazypassion             has_results = true;
347a0442ea0SHamir Mahal             write!(w, "{r}")?;
348747ad3c4Slazypassion         } else {
349a0442ea0SHamir Mahal             write!(w, ", {r}")?;
350747ad3c4Slazypassion         }
351747ad3c4Slazypassion     }
352747ad3c4Slazypassion     if has_results {
353747ad3c4Slazypassion         write!(w, " = ")?;
354747ad3c4Slazypassion     }
355747ad3c4Slazypassion 
356747ad3c4Slazypassion     // Then the opcode, possibly with a '.type' suffix.
35725bf8e0eSTrevor Elliott     let opcode = func.dfg.insts[inst].opcode();
358747ad3c4Slazypassion 
359747ad3c4Slazypassion     match type_suffix(func, inst) {
360a0442ea0SHamir Mahal         Some(suf) => write!(w, "{opcode}.{suf}")?,
361a0442ea0SHamir Mahal         None => write!(w, "{opcode}")?,
362747ad3c4Slazypassion     }
363747ad3c4Slazypassion 
36443a86f14SBenjamin Bouvier     write_operands(w, &func.dfg, inst)?;
365747ad3c4Slazypassion     writeln!(w)?;
366747ad3c4Slazypassion 
367747ad3c4Slazypassion     // Value aliases come out on lines after the instruction defining the referent.
368747ad3c4Slazypassion     for r in func.dfg.inst_results(inst) {
369747ad3c4Slazypassion         write_value_aliases(w, aliases, *r, indent)?;
370747ad3c4Slazypassion     }
371747ad3c4Slazypassion     Ok(())
372747ad3c4Slazypassion }
373747ad3c4Slazypassion 
374747ad3c4Slazypassion /// Write the operands of `inst` to `w` with a prepended space.
write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result37543a86f14SBenjamin Bouvier pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
376747ad3c4Slazypassion     let pool = &dfg.value_lists;
37715fe9c7cSTrevor Elliott     let jump_tables = &dfg.jump_tables;
37894ec88eaSChris Fallin     let exception_tables = &dfg.exception_tables;
379747ad3c4Slazypassion     use crate::ir::instructions::InstructionData::*;
3800683b84bSNick Fitzgerald     let ctrl_ty = dfg.ctrl_typevar(inst);
38125bf8e0eSTrevor Elliott     match dfg.insts[inst] {
382138148a5SJamey Sharp         AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]),
383138148a5SJamey Sharp         AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
384a0442ea0SHamir Mahal         LoadNoOffset { flags, arg, .. } => write!(w, "{flags} {arg}"),
385138148a5SJamey Sharp         StoreNoOffset { flags, args, .. } => write!(w, "{} {}, {}", flags, args[0], args[1]),
386a0442ea0SHamir Mahal         Unary { arg, .. } => write!(w, " {arg}"),
3870683b84bSNick Fitzgerald         UnaryImm { imm, .. } => write!(w, " {}", {
3880683b84bSNick Fitzgerald             let mut imm = imm;
3890683b84bSNick Fitzgerald             if ctrl_ty.bits() != 0 {
3900683b84bSNick Fitzgerald                 imm = imm.sign_extend_from_width(ctrl_ty.bits());
3910683b84bSNick Fitzgerald             }
3920683b84bSNick Fitzgerald             imm
3930683b84bSNick Fitzgerald         }),
394a0442ea0SHamir Mahal         UnaryIeee16 { imm, .. } => write!(w, " {imm}"),
395a0442ea0SHamir Mahal         UnaryIeee32 { imm, .. } => write!(w, " {imm}"),
396a0442ea0SHamir Mahal         UnaryIeee64 { imm, .. } => write!(w, " {imm}"),
397a0442ea0SHamir Mahal         UnaryGlobalValue { global_value, .. } => write!(w, " {global_value}"),
3980672d1dcSAndrew Brown         UnaryConst {
3990672d1dcSAndrew Brown             constant_handle, ..
400a0442ea0SHamir Mahal         } => write!(w, " {constant_handle}"),
401138148a5SJamey Sharp         Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
402a0442ea0SHamir Mahal         BinaryImm8 { arg, imm, .. } => write!(w, " {arg}, {imm}"),
4030683b84bSNick Fitzgerald         BinaryImm64 { arg, imm, .. } => write!(w, " {}, {}", arg, {
4040683b84bSNick Fitzgerald             let mut imm = imm;
4050683b84bSNick Fitzgerald             if ctrl_ty.bits() != 0 {
4060683b84bSNick Fitzgerald                 imm = imm.sign_extend_from_width(ctrl_ty.bits());
4070683b84bSNick Fitzgerald             }
4080683b84bSNick Fitzgerald             imm
4090683b84bSNick Fitzgerald         }),
410138148a5SJamey Sharp         Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
411747ad3c4Slazypassion         MultiAry { ref args, .. } => {
412747ad3c4Slazypassion             if args.is_empty() {
413747ad3c4Slazypassion                 write!(w, "")
414747ad3c4Slazypassion             } else {
415138148a5SJamey Sharp                 write!(w, " {}", DisplayValues(args.as_slice(pool)))
416747ad3c4Slazypassion             }
417747ad3c4Slazypassion         }
418747ad3c4Slazypassion         NullAry { .. } => write!(w, " "),
419138148a5SJamey Sharp         TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm),
4202fbd57e9Sbjorn3         Shuffle { imm, args, .. } => {
4212fbd57e9Sbjorn3             let data = dfg.immediates.get(imm).expect(
422af1499ceSAndrew Brown                 "Expected the shuffle mask to already be inserted into the immediates table",
423af1499ceSAndrew Brown             );
424138148a5SJamey Sharp             write!(w, " {}, {}, {}", args[0], args[1], data)
425af1499ceSAndrew Brown         }
426138148a5SJamey Sharp         IntCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
4270683b84bSNick Fitzgerald         IntCompareImm { cond, arg, imm, .. } => write!(w, " {} {}, {}", cond, arg, {
4280683b84bSNick Fitzgerald             let mut imm = imm;
4290683b84bSNick Fitzgerald             if ctrl_ty.bits() != 0 {
4300683b84bSNick Fitzgerald                 imm = imm.sign_extend_from_width(ctrl_ty.bits());
4310683b84bSNick Fitzgerald             }
4320683b84bSNick Fitzgerald             imm
4330683b84bSNick Fitzgerald         }),
434138148a5SJamey Sharp         IntAddTrap { args, code, .. } => write!(w, " {}, {}, {}", args[0], args[1], code),
435138148a5SJamey Sharp         FloatCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
4361e6c13d8STrevor Elliott         Jump { destination, .. } => {
437e82995f0STrevor Elliott             write!(w, " {}", destination.display(pool))
438747ad3c4Slazypassion         }
439b58a197dSTrevor Elliott         Brif {
440b58a197dSTrevor Elliott             arg,
441b58a197dSTrevor Elliott             blocks: [block_then, block_else],
442b58a197dSTrevor Elliott             ..
443b58a197dSTrevor Elliott         } => {
444138148a5SJamey Sharp             write!(w, " {}, {}", arg, block_then.display(pool))?;
445e82995f0STrevor Elliott             write!(w, ", {}", block_else.display(pool))
446b58a197dSTrevor Elliott         }
44780c147d9STrevor Elliott         BranchTable { arg, table, .. } => {
448138148a5SJamey Sharp             write!(w, " {}, {}", arg, jump_tables[table].display(pool))
44980c147d9STrevor Elliott         }
450747ad3c4Slazypassion         Call {
451747ad3c4Slazypassion             func_ref, ref args, ..
45259de3a32SNick Fitzgerald         } => {
45359de3a32SNick Fitzgerald             write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool)))?;
45459de3a32SNick Fitzgerald             write_user_stack_map_entries(w, dfg, inst)
45559de3a32SNick Fitzgerald         }
456747ad3c4Slazypassion         CallIndirect {
457747ad3c4Slazypassion             sig_ref, ref args, ..
458747ad3c4Slazypassion         } => {
459747ad3c4Slazypassion             let args = args.as_slice(pool);
460138148a5SJamey Sharp             write!(
461138148a5SJamey Sharp                 w,
462138148a5SJamey Sharp                 " {}, {}({})",
463138148a5SJamey Sharp                 sig_ref,
464138148a5SJamey Sharp                 args[0],
465138148a5SJamey Sharp                 DisplayValues(&args[1..])
46659de3a32SNick Fitzgerald             )?;
46759de3a32SNick Fitzgerald             write_user_stack_map_entries(w, dfg, inst)
468747ad3c4Slazypassion         }
46994ec88eaSChris Fallin         TryCall {
47094ec88eaSChris Fallin             func_ref,
47194ec88eaSChris Fallin             ref args,
47294ec88eaSChris Fallin             exception,
47394ec88eaSChris Fallin             ..
47494ec88eaSChris Fallin         } => {
47594ec88eaSChris Fallin             write!(
47694ec88eaSChris Fallin                 w,
47794ec88eaSChris Fallin                 " {}({}), {}",
47894ec88eaSChris Fallin                 func_ref,
47994ec88eaSChris Fallin                 DisplayValues(args.as_slice(pool)),
48094ec88eaSChris Fallin                 exception_tables[exception].display(pool),
481d70a517cSNick Fitzgerald             )?;
482d70a517cSNick Fitzgerald             write_user_stack_map_entries(w, dfg, inst)
48394ec88eaSChris Fallin         }
48494ec88eaSChris Fallin         TryCallIndirect {
48594ec88eaSChris Fallin             ref args,
48694ec88eaSChris Fallin             exception,
48794ec88eaSChris Fallin             ..
48894ec88eaSChris Fallin         } => {
48994ec88eaSChris Fallin             let args = args.as_slice(pool);
49094ec88eaSChris Fallin             write!(
49194ec88eaSChris Fallin                 w,
49294ec88eaSChris Fallin                 " {}({}), {}",
49394ec88eaSChris Fallin                 args[0],
49494ec88eaSChris Fallin                 DisplayValues(&args[1..]),
49594ec88eaSChris Fallin                 exception_tables[exception].display(pool),
496d70a517cSNick Fitzgerald             )?;
497d70a517cSNick Fitzgerald             write_user_stack_map_entries(w, dfg, inst)
49894ec88eaSChris Fallin         }
499a0442ea0SHamir Mahal         FuncAddr { func_ref, .. } => write!(w, " {func_ref}"),
500747ad3c4Slazypassion         StackLoad {
501747ad3c4Slazypassion             stack_slot, offset, ..
502a0442ea0SHamir Mahal         } => write!(w, " {stack_slot}{offset}"),
503747ad3c4Slazypassion         StackStore {
504747ad3c4Slazypassion             arg,
505747ad3c4Slazypassion             stack_slot,
506747ad3c4Slazypassion             offset,
507747ad3c4Slazypassion             ..
508a0442ea0SHamir Mahal         } => write!(w, " {arg}, {stack_slot}{offset}"),
5099c43749dSSam Parker         DynamicStackLoad {
5109c43749dSSam Parker             dynamic_stack_slot, ..
511a0442ea0SHamir Mahal         } => write!(w, " {dynamic_stack_slot}"),
5129c43749dSSam Parker         DynamicStackStore {
5139c43749dSSam Parker             arg,
5149c43749dSSam Parker             dynamic_stack_slot,
5159c43749dSSam Parker             ..
516a0442ea0SHamir Mahal         } => write!(w, " {arg}, {dynamic_stack_slot}"),
517747ad3c4Slazypassion         Load {
518747ad3c4Slazypassion             flags, arg, offset, ..
519a0442ea0SHamir Mahal         } => write!(w, "{flags} {arg}{offset}"),
520747ad3c4Slazypassion         Store {
521747ad3c4Slazypassion             flags,
522747ad3c4Slazypassion             args,
523747ad3c4Slazypassion             offset,
524747ad3c4Slazypassion             ..
525138148a5SJamey Sharp         } => write!(w, "{} {}, {}{}", flags, args[0], args[1], offset),
526a0442ea0SHamir Mahal         Trap { code, .. } => write!(w, " {code}"),
527a0442ea0SHamir Mahal         CondTrap { arg, code, .. } => write!(w, " {arg}, {code}"),
5284c01ee2fSChris Fallin         ExceptionHandlerAddress { block, imm, .. } => write!(w, " {block}, {imm}"),
5293629bbbdSJamey Sharp     }?;
5303629bbbdSJamey Sharp 
5313629bbbdSJamey Sharp     let mut sep = "  ; ";
5321e6c13d8STrevor Elliott     for arg in dfg.inst_values(inst) {
5333629bbbdSJamey Sharp         if let ValueDef::Result(src, _) = dfg.value_def(arg) {
53425bf8e0eSTrevor Elliott             let imm = match dfg.insts[src] {
5350683b84bSNick Fitzgerald                 UnaryImm { imm, .. } => {
5360683b84bSNick Fitzgerald                     let mut imm = imm;
5370683b84bSNick Fitzgerald                     if dfg.ctrl_typevar(src).bits() != 0 {
5380683b84bSNick Fitzgerald                         imm = imm.sign_extend_from_width(dfg.ctrl_typevar(src).bits());
5390683b84bSNick Fitzgerald                     }
5400683b84bSNick Fitzgerald                     imm.to_string()
5410683b84bSNick Fitzgerald                 }
54241eca60bSbeetrees                 UnaryIeee16 { imm, .. } => imm.to_string(),
5433629bbbdSJamey Sharp                 UnaryIeee32 { imm, .. } => imm.to_string(),
5443629bbbdSJamey Sharp                 UnaryIeee64 { imm, .. } => imm.to_string(),
5453629bbbdSJamey Sharp                 UnaryConst {
54641eca60bSbeetrees                     constant_handle,
54741eca60bSbeetrees                     opcode: Opcode::F128const,
54841eca60bSbeetrees                 } => Ieee128::try_from(dfg.constants.get(constant_handle))
54941eca60bSbeetrees                     .expect("16-byte f128 constant")
55041eca60bSbeetrees                     .to_string(),
55141eca60bSbeetrees                 UnaryConst {
5523629bbbdSJamey Sharp                     constant_handle, ..
5533629bbbdSJamey Sharp                 } => constant_handle.to_string(),
5543629bbbdSJamey Sharp                 _ => continue,
5553629bbbdSJamey Sharp             };
556a0442ea0SHamir Mahal             write!(w, "{sep}{arg} = {imm}")?;
5573629bbbdSJamey Sharp             sep = ", ";
558747ad3c4Slazypassion         }
559747ad3c4Slazypassion     }
5603629bbbdSJamey Sharp     Ok(())
5613629bbbdSJamey Sharp }
562747ad3c4Slazypassion 
write_debug_tags( w: &mut dyn Write, func: &Function, inst: Inst, indent: &mut usize, ) -> fmt::Result563a3d6e407SChris Fallin fn write_debug_tags(
564a3d6e407SChris Fallin     w: &mut dyn Write,
565a3d6e407SChris Fallin     func: &Function,
566a3d6e407SChris Fallin     inst: Inst,
567a3d6e407SChris Fallin     indent: &mut usize,
568a3d6e407SChris Fallin ) -> fmt::Result {
569a3d6e407SChris Fallin     let tags = func.debug_tags.get(inst);
570a3d6e407SChris Fallin     if !tags.is_empty() {
571a3d6e407SChris Fallin         let tags = tags
572a3d6e407SChris Fallin             .iter()
573a3d6e407SChris Fallin             .map(|tag| format!("{tag}"))
574a3d6e407SChris Fallin             .collect::<Vec<_>>()
575a3d6e407SChris Fallin             .join(", ");
576a3d6e407SChris Fallin         let s = format!("<{tags}> ");
577a3d6e407SChris Fallin         write!(w, "{s}")?;
578a3d6e407SChris Fallin         *indent = indent.saturating_sub(s.len());
579a3d6e407SChris Fallin     }
580a3d6e407SChris Fallin     Ok(())
581a3d6e407SChris Fallin }
582a3d6e407SChris Fallin 
write_user_stack_map_entries(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result58359de3a32SNick Fitzgerald fn write_user_stack_map_entries(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
58459de3a32SNick Fitzgerald     let entries = match dfg.user_stack_map_entries(inst) {
58559de3a32SNick Fitzgerald         None => return Ok(()),
58659de3a32SNick Fitzgerald         Some(es) => es,
58759de3a32SNick Fitzgerald     };
58859de3a32SNick Fitzgerald     write!(w, ", stack_map=[")?;
58959de3a32SNick Fitzgerald     let mut need_comma = false;
59059de3a32SNick Fitzgerald     for entry in entries {
59159de3a32SNick Fitzgerald         if need_comma {
59259de3a32SNick Fitzgerald             write!(w, ", ")?;
59359de3a32SNick Fitzgerald         }
59459de3a32SNick Fitzgerald         write!(w, "{} @ {}+{}", entry.ty, entry.slot, entry.offset)?;
59559de3a32SNick Fitzgerald         need_comma = true;
59659de3a32SNick Fitzgerald     }
59759de3a32SNick Fitzgerald     write!(w, "]")?;
59859de3a32SNick Fitzgerald     Ok(())
59959de3a32SNick Fitzgerald }
60059de3a32SNick Fitzgerald 
601747ad3c4Slazypassion /// Displayable slice of values.
602747ad3c4Slazypassion struct DisplayValues<'a>(&'a [Value]);
603747ad3c4Slazypassion 
604747ad3c4Slazypassion impl<'a> fmt::Display for DisplayValues<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result605747ad3c4Slazypassion     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
606747ad3c4Slazypassion         for (i, val) in self.0.iter().enumerate() {
607747ad3c4Slazypassion             if i == 0 {
608a0442ea0SHamir Mahal                 write!(f, "{val}")?;
609747ad3c4Slazypassion             } else {
610a0442ea0SHamir Mahal                 write!(f, ", {val}")?;
611747ad3c4Slazypassion             }
612747ad3c4Slazypassion         }
613747ad3c4Slazypassion         Ok(())
614747ad3c4Slazypassion     }
615747ad3c4Slazypassion }
616747ad3c4Slazypassion 
617747ad3c4Slazypassion #[cfg(test)]
618747ad3c4Slazypassion mod tests {
619747ad3c4Slazypassion     use crate::cursor::{Cursor, CursorPosition, FuncCursor};
620747ad3c4Slazypassion     use crate::ir::types;
6218a9b1a90SBenjamin Bouvier     use crate::ir::{Function, InstBuilder, StackSlotData, StackSlotKind, UserFuncName};
62210e226f9Sbjorn3     use alloc::string::ToString;
623747ad3c4Slazypassion 
624747ad3c4Slazypassion     #[test]
basic()625747ad3c4Slazypassion     fn basic() {
626747ad3c4Slazypassion         let mut f = Function::new();
627747ad3c4Slazypassion         assert_eq!(f.to_string(), "function u0:0() fast {\n}\n");
628747ad3c4Slazypassion 
6298a9b1a90SBenjamin Bouvier         f.name = UserFuncName::testcase("foo");
630747ad3c4Slazypassion         assert_eq!(f.to_string(), "function %foo() fast {\n}\n");
631747ad3c4Slazypassion 
63245bc7366SChris Fallin         f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0));
633747ad3c4Slazypassion         assert_eq!(
634747ad3c4Slazypassion             f.to_string(),
635747ad3c4Slazypassion             "function %foo() fast {\n    ss0 = explicit_slot 4\n}\n"
636747ad3c4Slazypassion         );
637747ad3c4Slazypassion 
638832666c4SRyan Hunt         let block = f.dfg.make_block();
639832666c4SRyan Hunt         f.layout.append_block(block);
640747ad3c4Slazypassion         assert_eq!(
641747ad3c4Slazypassion             f.to_string(),
642832666c4SRyan Hunt             "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0:\n}\n"
643747ad3c4Slazypassion         );
644747ad3c4Slazypassion 
645832666c4SRyan Hunt         f.dfg.append_block_param(block, types::I8);
646747ad3c4Slazypassion         assert_eq!(
647747ad3c4Slazypassion             f.to_string(),
648832666c4SRyan Hunt             "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8):\n}\n"
649747ad3c4Slazypassion         );
650747ad3c4Slazypassion 
651832666c4SRyan Hunt         f.dfg.append_block_param(block, types::F32.by(4).unwrap());
652747ad3c4Slazypassion         assert_eq!(
653747ad3c4Slazypassion             f.to_string(),
654832666c4SRyan Hunt             "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n}\n"
655747ad3c4Slazypassion         );
656747ad3c4Slazypassion 
657747ad3c4Slazypassion         {
658747ad3c4Slazypassion             let mut cursor = FuncCursor::new(&mut f);
659832666c4SRyan Hunt             cursor.set_position(CursorPosition::After(block));
660747ad3c4Slazypassion             cursor.ins().return_(&[])
661747ad3c4Slazypassion         };
662747ad3c4Slazypassion         assert_eq!(
663747ad3c4Slazypassion             f.to_string(),
664832666c4SRyan Hunt             "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n    return\n}\n"
665747ad3c4Slazypassion         );
66645bc7366SChris Fallin 
66745bc7366SChris Fallin         let mut f = Function::new();
66845bc7366SChris Fallin         f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 2));
66945bc7366SChris Fallin         assert_eq!(
67045bc7366SChris Fallin             f.to_string(),
67145bc7366SChris Fallin             "function u0:0() fast {\n    ss0 = explicit_slot 4, align = 4\n}\n"
67245bc7366SChris Fallin         );
673747ad3c4Slazypassion     }
674747ad3c4Slazypassion 
675747ad3c4Slazypassion     #[test]
aliases()676747ad3c4Slazypassion     fn aliases() {
677747ad3c4Slazypassion         use crate::ir::InstBuilder;
678747ad3c4Slazypassion 
679747ad3c4Slazypassion         let mut func = Function::new();
680747ad3c4Slazypassion         {
681832666c4SRyan Hunt             let block0 = func.dfg.make_block();
682747ad3c4Slazypassion             let mut pos = FuncCursor::new(&mut func);
683832666c4SRyan Hunt             pos.insert_block(block0);
684747ad3c4Slazypassion 
685747ad3c4Slazypassion             // make some detached values for change_to_alias
686832666c4SRyan Hunt             let v0 = pos.func.dfg.append_block_param(block0, types::I32);
687832666c4SRyan Hunt             let v1 = pos.func.dfg.append_block_param(block0, types::I32);
688832666c4SRyan Hunt             let v2 = pos.func.dfg.append_block_param(block0, types::I32);
689832666c4SRyan Hunt             pos.func.dfg.detach_block_params(block0);
690747ad3c4Slazypassion 
691832666c4SRyan Hunt             // alias to a param--will be printed at beginning of block defining param
692832666c4SRyan Hunt             let v3 = pos.func.dfg.append_block_param(block0, types::I32);
693747ad3c4Slazypassion             pos.func.dfg.change_to_alias(v0, v3);
694747ad3c4Slazypassion 
695747ad3c4Slazypassion             // alias to an alias--should print attached to alias, not ultimate target
696747ad3c4Slazypassion             pos.func.dfg.make_value_alias_for_serialization(v0, v2); // v0 <- v2
697747ad3c4Slazypassion 
698747ad3c4Slazypassion             // alias to a result--will be printed after instruction producing result
699747ad3c4Slazypassion             let _dummy0 = pos.ins().iconst(types::I32, 42);
700747ad3c4Slazypassion             let v4 = pos.ins().iadd(v0, v0);
701747ad3c4Slazypassion             pos.func.dfg.change_to_alias(v1, v4);
702747ad3c4Slazypassion             let _dummy1 = pos.ins().iconst(types::I32, 23);
703747ad3c4Slazypassion             let _v7 = pos.ins().iadd(v1, v1);
704747ad3c4Slazypassion         }
705747ad3c4Slazypassion         assert_eq!(
706747ad3c4Slazypassion             func.to_string(),
707138148a5SJamey Sharp             "function u0:0() fast {\nblock0(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"
708747ad3c4Slazypassion         );
709747ad3c4Slazypassion     }
71051649d56SChris Fallin 
71151649d56SChris Fallin     #[test]
cold_blocks()71251649d56SChris Fallin     fn cold_blocks() {
71351649d56SChris Fallin         let mut func = Function::new();
71451649d56SChris Fallin         {
71551649d56SChris Fallin             let mut pos = FuncCursor::new(&mut func);
71651649d56SChris Fallin 
71751649d56SChris Fallin             let block0 = pos.func.dfg.make_block();
71851649d56SChris Fallin             pos.insert_block(block0);
71951649d56SChris Fallin             pos.func.layout.set_cold(block0);
72051649d56SChris Fallin 
72151649d56SChris Fallin             let block1 = pos.func.dfg.make_block();
72251649d56SChris Fallin             pos.insert_block(block1);
72351649d56SChris Fallin             pos.func.dfg.append_block_param(block1, types::I32);
72451649d56SChris Fallin             pos.func.layout.set_cold(block1);
72551649d56SChris Fallin         }
72651649d56SChris Fallin 
72751649d56SChris Fallin         assert_eq!(
72851649d56SChris Fallin             func.to_string(),
72951649d56SChris Fallin             "function u0:0() fast {\nblock0 cold:\n\nblock1(v0: i32) cold:\n}\n"
73051649d56SChris Fallin         );
73151649d56SChris Fallin     }
732747ad3c4Slazypassion }
733