Coverage Report

Created: 2026-03-26 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cranelift-codegen-0.129.1/src/write.rs
Line
Count
Source
1
//! Converting Cranelift IR to text.
2
//!
3
//! The `write` module provides the `write_function` function which converts an IR `Function` to an
4
//! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate.
5
6
use crate::entity::SecondaryMap;
7
use crate::ir::entities::AnyEntity;
8
use crate::ir::immediates::Ieee128;
9
use crate::ir::pcc::Fact;
10
use crate::ir::{Block, DataFlowGraph, Function, Inst, Opcode, SigRef, Type, Value, ValueDef};
11
use crate::packed_option::ReservedValue;
12
use alloc::string::{String, ToString};
13
use alloc::vec::Vec;
14
use core::fmt::{self, Write};
15
16
/// A `FuncWriter` used to decorate functions during printing.
17
pub trait FuncWriter {
18
    /// Write the basic block header for the current function.
19
    fn write_block_header(
20
        &mut self,
21
        w: &mut dyn Write,
22
        func: &Function,
23
        block: Block,
24
        indent: usize,
25
    ) -> fmt::Result;
26
27
    /// Write the given `inst` to `w`.
28
    fn write_instruction(
29
        &mut self,
30
        w: &mut dyn Write,
31
        func: &Function,
32
        aliases: &SecondaryMap<Value, Vec<Value>>,
33
        inst: Inst,
34
        indent: usize,
35
    ) -> fmt::Result;
36
37
    /// Write the preamble to `w`. By default, this uses `write_entity_definition`.
38
0
    fn write_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error> {
39
0
        self.super_preamble(w, func)
40
0
    }
Unexecuted instantiation: <cranelift_codegen::print_errors::PrettyVerifierError as cranelift_codegen::write::FuncWriter>::write_preamble
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_preamble
Unexecuted instantiation: <cranelift_codegen::print_errors::PrettyVerifierError as cranelift_codegen::write::FuncWriter>::write_preamble
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_preamble
41
42
    /// Default impl of `write_preamble`
43
0
    fn super_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result<bool, fmt::Error> {
44
0
        let mut any = false;
45
46
0
        for (ss, slot) in func.dynamic_stack_slots.iter() {
47
0
            any = true;
48
0
            self.write_entity_definition(w, func, ss.into(), slot, None)?;
49
        }
50
51
0
        for (ss, slot) in func.sized_stack_slots.iter() {
52
0
            any = true;
53
0
            self.write_entity_definition(w, func, ss.into(), slot, None)?;
54
        }
55
56
0
        for (gv, gv_data) in &func.global_values {
57
0
            any = true;
58
0
            let maybe_fact = func.global_value_facts[gv].as_ref();
59
0
            self.write_entity_definition(w, func, gv.into(), gv_data, maybe_fact)?;
60
        }
61
62
0
        for (mt, mt_data) in &func.memory_types {
63
0
            any = true;
64
0
            self.write_entity_definition(w, func, mt.into(), mt_data, None)?;
65
        }
66
67
        // Write out all signatures before functions since function declarations can refer to
68
        // signatures.
69
0
        for (sig, sig_data) in &func.dfg.signatures {
70
0
            any = true;
71
0
            self.write_entity_definition(w, func, sig.into(), &sig_data, None)?;
72
        }
73
74
0
        for (fnref, ext_func) in &func.dfg.ext_funcs {
75
0
            if ext_func.signature != SigRef::reserved_value() {
76
0
                any = true;
77
0
                self.write_entity_definition(
78
0
                    w,
79
0
                    func,
80
0
                    fnref.into(),
81
0
                    &ext_func.display(Some(&func.params)),
82
0
                    None,
83
0
                )?;
84
0
            }
85
        }
86
87
0
        for (&cref, cval) in func.dfg.constants.iter() {
88
0
            any = true;
89
0
            self.write_entity_definition(w, func, cref.into(), cval, None)?;
90
        }
91
92
0
        if let Some(limit) = func.stack_limit {
93
0
            any = true;
94
0
            self.write_entity_definition(w, func, AnyEntity::StackLimit, &limit, None)?;
95
0
        }
96
97
0
        Ok(any)
98
0
    }
Unexecuted instantiation: <cranelift_codegen::print_errors::PrettyVerifierError as cranelift_codegen::write::FuncWriter>::super_preamble
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::super_preamble
Unexecuted instantiation: <cranelift_codegen::print_errors::PrettyVerifierError as cranelift_codegen::write::FuncWriter>::super_preamble
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::super_preamble
99
100
    /// Write an entity definition defined in the preamble to `w`.
101
0
    fn write_entity_definition(
102
0
        &mut self,
103
0
        w: &mut dyn Write,
104
0
        func: &Function,
105
0
        entity: AnyEntity,
106
0
        value: &dyn fmt::Display,
107
0
        maybe_fact: Option<&Fact>,
108
0
    ) -> fmt::Result {
109
0
        self.super_entity_definition(w, func, entity, value, maybe_fact)
110
0
    }
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_entity_definition
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_entity_definition
111
112
    /// Default impl of `write_entity_definition`
113
0
    fn super_entity_definition(
114
0
        &mut self,
115
0
        w: &mut dyn Write,
116
0
        _func: &Function,
117
0
        entity: AnyEntity,
118
0
        value: &dyn fmt::Display,
119
0
        maybe_fact: Option<&Fact>,
120
0
    ) -> fmt::Result {
121
0
        if let Some(fact) = maybe_fact {
122
0
            writeln!(w, "    {entity} ! {fact} = {value}")
123
        } else {
124
0
            writeln!(w, "    {entity} = {value}")
125
        }
126
0
    }
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::super_entity_definition
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::super_entity_definition
127
}
128
129
/// A `PlainWriter` that doesn't decorate the function.
130
pub struct PlainWriter;
131
132
impl FuncWriter for PlainWriter {
133
0
    fn write_instruction(
134
0
        &mut self,
135
0
        w: &mut dyn Write,
136
0
        func: &Function,
137
0
        aliases: &SecondaryMap<Value, Vec<Value>>,
138
0
        inst: Inst,
139
0
        indent: usize,
140
0
    ) -> fmt::Result {
141
0
        write_instruction(w, func, aliases, inst, indent)
142
0
    }
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_instruction
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_instruction
143
144
0
    fn write_block_header(
145
0
        &mut self,
146
0
        w: &mut dyn Write,
147
0
        func: &Function,
148
0
        block: Block,
149
0
        indent: usize,
150
0
    ) -> fmt::Result {
151
0
        write_block_header(w, func, block, indent)
152
0
    }
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_block_header
Unexecuted instantiation: <cranelift_codegen::write::PlainWriter as cranelift_codegen::write::FuncWriter>::write_block_header
153
}
154
155
/// Write `func` to `w` as equivalent text.
156
/// Use `isa` to emit ISA-dependent annotations.
157
0
pub fn write_function(w: &mut dyn Write, func: &Function) -> fmt::Result {
158
0
    decorate_function(&mut PlainWriter, w, func)
159
0
}
Unexecuted instantiation: cranelift_codegen::write::write_function
Unexecuted instantiation: cranelift_codegen::write::write_function
160
161
/// Create a reverse-alias map from a value to all aliases having that value as a direct target
162
0
fn alias_map(func: &Function) -> SecondaryMap<Value, Vec<Value>> {
163
0
    let mut aliases = SecondaryMap::<_, Vec<_>>::new();
164
0
    for v in func.dfg.values() {
165
        // VADFS returns the immediate target of an alias
166
0
        if let Some(k) = func.dfg.value_alias_dest_for_serialization(v) {
167
0
            aliases[k].push(v);
168
0
        }
169
    }
170
0
    aliases
171
0
}
Unexecuted instantiation: cranelift_codegen::write::alias_map
Unexecuted instantiation: cranelift_codegen::write::alias_map
172
173
/// Writes `func` to `w` as text.
174
/// write_function_plain is passed as 'closure' to print instructions as text.
175
/// pretty_function_error is passed as 'closure' to add error decoration.
176
0
pub fn decorate_function<FW: FuncWriter>(
177
0
    func_w: &mut FW,
178
0
    w: &mut dyn Write,
179
0
    func: &Function,
180
0
) -> fmt::Result {
181
0
    write!(w, "function ")?;
182
0
    write_function_spec(w, func)?;
183
0
    writeln!(w, " {{")?;
184
0
    let aliases = alias_map(func);
185
0
    let mut any = func_w.write_preamble(w, func)?;
186
0
    for block in &func.layout {
187
0
        if any {
188
0
            writeln!(w)?;
189
0
        }
190
0
        decorate_block(func_w, w, func, &aliases, block)?;
191
0
        any = true;
192
    }
193
0
    writeln!(w, "}}")
194
0
}
Unexecuted instantiation: cranelift_codegen::write::decorate_function::<cranelift_codegen::write::PlainWriter>
Unexecuted instantiation: cranelift_codegen::write::decorate_function::<cranelift_codegen::print_errors::PrettyVerifierError>
Unexecuted instantiation: cranelift_codegen::write::decorate_function::<cranelift_codegen::write::PlainWriter>
Unexecuted instantiation: cranelift_codegen::write::decorate_function::<cranelift_codegen::print_errors::PrettyVerifierError>
195
196
//----------------------------------------------------------------------
197
//
198
// Function spec.
199
200
/// Writes the spec (name and signature) of 'func' to 'w' as text.
201
0
pub fn write_function_spec(w: &mut dyn Write, func: &Function) -> fmt::Result {
202
0
    write!(w, "{}{}", func.name, func.signature)
203
0
}
Unexecuted instantiation: cranelift_codegen::write::write_function_spec
Unexecuted instantiation: cranelift_codegen::write::write_function_spec
204
205
//----------------------------------------------------------------------
206
//
207
// Basic blocks
208
209
0
fn write_arg(w: &mut dyn Write, func: &Function, arg: Value) -> fmt::Result {
210
0
    let ty = func.dfg.value_type(arg);
211
0
    if let Some(f) = &func.dfg.facts[arg] {
212
0
        write!(w, "{arg} ! {f}: {ty}")
213
    } else {
214
0
        write!(w, "{arg}: {ty}")
215
    }
216
0
}
Unexecuted instantiation: cranelift_codegen::write::write_arg
Unexecuted instantiation: cranelift_codegen::write::write_arg
217
218
/// Write out the basic block header, outdented:
219
///
220
///    block1:
221
///    block1(v1: i32):
222
///    block10(v4: f64, v5: i8):
223
///
224
0
pub fn write_block_header(
225
0
    w: &mut dyn Write,
226
0
    func: &Function,
227
0
    block: Block,
228
0
    indent: usize,
229
0
) -> fmt::Result {
230
0
    let cold = if func.layout.is_cold(block) {
231
0
        " cold"
232
    } else {
233
0
        ""
234
    };
235
236
    // The `indent` is the instruction indentation. block headers are 4 spaces out from that.
237
0
    write!(w, "{1:0$}{2}", indent - 4, "", block)?;
238
239
0
    let mut args = func.dfg.block_params(block).iter().cloned();
240
0
    match args.next() {
241
0
        None => return writeln!(w, "{cold}:"),
242
0
        Some(arg) => {
243
0
            write!(w, "(")?;
244
0
            write_arg(w, func, arg)?;
245
        }
246
    }
247
    // Remaining arguments.
248
0
    for arg in args {
249
0
        write!(w, ", ")?;
250
0
        write_arg(w, func, arg)?;
251
    }
252
0
    writeln!(w, "){cold}:")
253
0
}
Unexecuted instantiation: cranelift_codegen::write::write_block_header
Unexecuted instantiation: cranelift_codegen::write::write_block_header
254
255
0
fn decorate_block<FW: FuncWriter>(
256
0
    func_w: &mut FW,
257
0
    w: &mut dyn Write,
258
0
    func: &Function,
259
0
    aliases: &SecondaryMap<Value, Vec<Value>>,
260
0
    block: Block,
261
0
) -> fmt::Result {
262
    // Indent all instructions if any srclocs or debug tags are present.
263
0
    let indent = if func.rel_srclocs().is_empty() && func.debug_tags.is_empty() {
264
0
        4
265
    } else {
266
0
        36
267
    };
268
269
0
    func_w.write_block_header(w, func, block, indent)?;
270
0
    for a in func.dfg.block_params(block).iter().cloned() {
271
0
        write_value_aliases(w, aliases, a, indent)?;
272
    }
273
274
0
    for inst in func.layout.block_insts(block) {
275
0
        func_w.write_instruction(w, func, aliases, inst, indent)?;
276
    }
277
278
0
    Ok(())
279
0
}
Unexecuted instantiation: cranelift_codegen::write::decorate_block::<cranelift_codegen::write::PlainWriter>
Unexecuted instantiation: cranelift_codegen::write::decorate_block::<cranelift_codegen::print_errors::PrettyVerifierError>
Unexecuted instantiation: cranelift_codegen::write::decorate_block::<cranelift_codegen::write::PlainWriter>
Unexecuted instantiation: cranelift_codegen::write::decorate_block::<cranelift_codegen::print_errors::PrettyVerifierError>
280
281
//----------------------------------------------------------------------
282
//
283
// Instructions
284
285
// Should `inst` be printed with a type suffix?
286
//
287
// Polymorphic instructions may need a suffix indicating the value of the controlling type variable
288
// if it can't be trivially inferred.
289
//
290
0
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
291
0
    let inst_data = &func.dfg.insts[inst];
292
0
    let constraints = inst_data.opcode().constraints();
293
294
0
    if !constraints.is_polymorphic() {
295
0
        return None;
296
0
    }
297
298
    // If the controlling type variable can be inferred from the type of the designated value input
299
    // operand, we don't need the type suffix.
300
0
    if constraints.use_typevar_operand() {
301
0
        let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap();
302
0
        let def_block = match func.dfg.value_def(ctrl_var) {
303
0
            ValueDef::Result(instr, _) => func.layout.inst_block(instr),
304
0
            ValueDef::Param(block, _) => Some(block),
305
0
            ValueDef::Union(..) => None,
306
        };
307
0
        if def_block.is_some() && def_block == func.layout.inst_block(inst) {
308
0
            return None;
309
0
        }
310
0
    }
311
312
0
    let rtype = func.dfg.ctrl_typevar(inst);
313
0
    assert!(
314
0
        !rtype.is_invalid(),
315
        "Polymorphic instruction must produce a result"
316
    );
317
0
    Some(rtype)
318
0
}
Unexecuted instantiation: cranelift_codegen::write::type_suffix
Unexecuted instantiation: cranelift_codegen::write::type_suffix
319
320
/// Write out any aliases to the given target, including indirect aliases
321
0
fn write_value_aliases(
322
0
    w: &mut dyn Write,
323
0
    aliases: &SecondaryMap<Value, Vec<Value>>,
324
0
    target: Value,
325
0
    indent: usize,
326
0
) -> fmt::Result {
327
0
    let mut todo_stack = vec![target];
328
0
    while let Some(target) = todo_stack.pop() {
329
0
        for &a in &aliases[target] {
330
0
            writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?;
331
0
            todo_stack.push(a);
332
        }
333
    }
334
335
0
    Ok(())
336
0
}
Unexecuted instantiation: cranelift_codegen::write::write_value_aliases
Unexecuted instantiation: cranelift_codegen::write::write_value_aliases
337
338
0
fn write_instruction(
339
0
    w: &mut dyn Write,
340
0
    func: &Function,
341
0
    aliases: &SecondaryMap<Value, Vec<Value>>,
342
0
    inst: Inst,
343
0
    mut indent: usize,
344
0
) -> fmt::Result {
345
    // Prefix containing source location, encoding, and value locations.
346
0
    let mut s = String::with_capacity(16);
347
348
    // Source location goes first.
349
0
    let srcloc = func.srcloc(inst);
350
0
    if !srcloc.is_default() {
351
0
        write!(s, "{srcloc} ")?;
352
0
    }
353
354
    // Write out any debug tags.
355
0
    write_debug_tags(w, &func, inst, &mut indent)?;
356
357
    // Write out prefix and indent the instruction.
358
0
    write!(w, "{s:indent$}")?;
359
360
    // Write out the result values, if any.
361
0
    let mut has_results = false;
362
0
    for r in func.dfg.inst_results(inst) {
363
0
        if !has_results {
364
0
            has_results = true;
365
0
            write!(w, "{r}")?;
366
        } else {
367
0
            write!(w, ", {r}")?;
368
        }
369
0
        if let Some(f) = &func.dfg.facts[*r] {
370
0
            write!(w, " ! {f}")?;
371
0
        }
372
    }
373
0
    if has_results {
374
0
        write!(w, " = ")?;
375
0
    }
376
377
    // Then the opcode, possibly with a '.type' suffix.
378
0
    let opcode = func.dfg.insts[inst].opcode();
379
380
0
    match type_suffix(func, inst) {
381
0
        Some(suf) => write!(w, "{opcode}.{suf}")?,
382
0
        None => write!(w, "{opcode}")?,
383
    }
384
385
0
    write_operands(w, &func.dfg, inst)?;
386
0
    writeln!(w)?;
387
388
    // Value aliases come out on lines after the instruction defining the referent.
389
0
    for r in func.dfg.inst_results(inst) {
390
0
        write_value_aliases(w, aliases, *r, indent)?;
391
    }
392
0
    Ok(())
393
0
}
Unexecuted instantiation: cranelift_codegen::write::write_instruction
Unexecuted instantiation: cranelift_codegen::write::write_instruction
394
395
/// Write the operands of `inst` to `w` with a prepended space.
396
0
pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
397
0
    let pool = &dfg.value_lists;
398
0
    let jump_tables = &dfg.jump_tables;
399
0
    let exception_tables = &dfg.exception_tables;
400
    use crate::ir::instructions::InstructionData::*;
401
0
    let ctrl_ty = dfg.ctrl_typevar(inst);
402
0
    match dfg.insts[inst] {
403
0
        AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]),
404
0
        AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
405
0
        LoadNoOffset { flags, arg, .. } => write!(w, "{flags} {arg}"),
406
0
        StoreNoOffset { flags, args, .. } => write!(w, "{} {}, {}", flags, args[0], args[1]),
407
0
        Unary { arg, .. } => write!(w, " {arg}"),
408
0
        UnaryImm { imm, .. } => write!(w, " {}", {
409
0
            let mut imm = imm;
410
0
            if ctrl_ty.bits() != 0 {
411
0
                imm = imm.sign_extend_from_width(ctrl_ty.bits());
412
0
            }
413
0
            imm
414
        }),
415
0
        UnaryIeee16 { imm, .. } => write!(w, " {imm}"),
416
0
        UnaryIeee32 { imm, .. } => write!(w, " {imm}"),
417
0
        UnaryIeee64 { imm, .. } => write!(w, " {imm}"),
418
0
        UnaryGlobalValue { global_value, .. } => write!(w, " {global_value}"),
419
        UnaryConst {
420
0
            constant_handle, ..
421
0
        } => write!(w, " {constant_handle}"),
422
0
        Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
423
0
        BinaryImm8 { arg, imm, .. } => write!(w, " {arg}, {imm}"),
424
0
        BinaryImm64 { arg, imm, .. } => write!(w, " {}, {}", arg, {
425
0
            let mut imm = imm;
426
0
            if ctrl_ty.bits() != 0 {
427
0
                imm = imm.sign_extend_from_width(ctrl_ty.bits());
428
0
            }
429
0
            imm
430
        }),
431
0
        Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
432
0
        MultiAry { ref args, .. } => {
433
0
            if args.is_empty() {
434
0
                write!(w, "")
435
            } else {
436
0
                write!(w, " {}", DisplayValues(args.as_slice(pool)))
437
            }
438
        }
439
0
        NullAry { .. } => write!(w, " "),
440
0
        TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm),
441
0
        Shuffle { imm, args, .. } => {
442
0
            let data = dfg.immediates.get(imm).expect(
443
0
                "Expected the shuffle mask to already be inserted into the immediates table",
444
            );
445
0
            write!(w, " {}, {}, {}", args[0], args[1], data)
446
        }
447
0
        IntCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
448
0
        IntCompareImm { cond, arg, imm, .. } => write!(w, " {} {}, {}", cond, arg, {
449
0
            let mut imm = imm;
450
0
            if ctrl_ty.bits() != 0 {
451
0
                imm = imm.sign_extend_from_width(ctrl_ty.bits());
452
0
            }
453
0
            imm
454
        }),
455
0
        IntAddTrap { args, code, .. } => write!(w, " {}, {}, {}", args[0], args[1], code),
456
0
        FloatCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
457
0
        Jump { destination, .. } => {
458
0
            write!(w, " {}", destination.display(pool))
459
        }
460
        Brif {
461
0
            arg,
462
0
            blocks: [block_then, block_else],
463
            ..
464
        } => {
465
0
            write!(w, " {}, {}", arg, block_then.display(pool))?;
466
0
            write!(w, ", {}", block_else.display(pool))
467
        }
468
0
        BranchTable { arg, table, .. } => {
469
0
            write!(w, " {}, {}", arg, jump_tables[table].display(pool))
470
        }
471
        Call {
472
0
            func_ref, ref args, ..
473
        } => {
474
0
            write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool)))?;
475
0
            write_user_stack_map_entries(w, dfg, inst)
476
        }
477
        CallIndirect {
478
0
            sig_ref, ref args, ..
479
        } => {
480
0
            let args = args.as_slice(pool);
481
0
            write!(
482
0
                w,
483
                " {}, {}({})",
484
                sig_ref,
485
0
                args[0],
486
0
                DisplayValues(&args[1..])
487
0
            )?;
488
0
            write_user_stack_map_entries(w, dfg, inst)
489
        }
490
        TryCall {
491
0
            func_ref,
492
0
            ref args,
493
0
            exception,
494
            ..
495
        } => {
496
0
            write!(
497
0
                w,
498
                " {}({}), {}",
499
                func_ref,
500
0
                DisplayValues(args.as_slice(pool)),
501
0
                exception_tables[exception].display(pool),
502
            )
503
        }
504
        TryCallIndirect {
505
0
            ref args,
506
0
            exception,
507
            ..
508
        } => {
509
0
            let args = args.as_slice(pool);
510
0
            write!(
511
0
                w,
512
                " {}({}), {}",
513
0
                args[0],
514
0
                DisplayValues(&args[1..]),
515
0
                exception_tables[exception].display(pool),
516
            )
517
        }
518
0
        FuncAddr { func_ref, .. } => write!(w, " {func_ref}"),
519
        StackLoad {
520
0
            stack_slot, offset, ..
521
0
        } => write!(w, " {stack_slot}{offset}"),
522
        StackStore {
523
0
            arg,
524
0
            stack_slot,
525
0
            offset,
526
            ..
527
0
        } => write!(w, " {arg}, {stack_slot}{offset}"),
528
        DynamicStackLoad {
529
0
            dynamic_stack_slot, ..
530
0
        } => write!(w, " {dynamic_stack_slot}"),
531
        DynamicStackStore {
532
0
            arg,
533
0
            dynamic_stack_slot,
534
            ..
535
0
        } => write!(w, " {arg}, {dynamic_stack_slot}"),
536
        Load {
537
0
            flags, arg, offset, ..
538
0
        } => write!(w, "{flags} {arg}{offset}"),
539
        Store {
540
0
            flags,
541
0
            args,
542
0
            offset,
543
            ..
544
0
        } => write!(w, "{} {}, {}{}", flags, args[0], args[1], offset),
545
0
        Trap { code, .. } => write!(w, " {code}"),
546
0
        CondTrap { arg, code, .. } => write!(w, " {arg}, {code}"),
547
0
        ExceptionHandlerAddress { block, imm, .. } => write!(w, " {block}, {imm}"),
548
0
    }?;
549
550
0
    let mut sep = "  ; ";
551
0
    for arg in dfg.inst_values(inst) {
552
0
        if let ValueDef::Result(src, _) = dfg.value_def(arg) {
553
0
            let imm = match dfg.insts[src] {
554
0
                UnaryImm { imm, .. } => {
555
0
                    let mut imm = imm;
556
0
                    if dfg.ctrl_typevar(src).bits() != 0 {
557
0
                        imm = imm.sign_extend_from_width(dfg.ctrl_typevar(src).bits());
558
0
                    }
559
0
                    imm.to_string()
560
                }
561
0
                UnaryIeee16 { imm, .. } => imm.to_string(),
562
0
                UnaryIeee32 { imm, .. } => imm.to_string(),
563
0
                UnaryIeee64 { imm, .. } => imm.to_string(),
564
                UnaryConst {
565
0
                    constant_handle,
566
                    opcode: Opcode::F128const,
567
0
                } => Ieee128::try_from(dfg.constants.get(constant_handle))
568
0
                    .expect("16-byte f128 constant")
569
0
                    .to_string(),
570
                UnaryConst {
571
0
                    constant_handle, ..
572
0
                } => constant_handle.to_string(),
573
0
                _ => continue,
574
            };
575
0
            write!(w, "{sep}{arg} = {imm}")?;
576
0
            sep = ", ";
577
0
        }
578
    }
579
0
    Ok(())
580
0
}
Unexecuted instantiation: cranelift_codegen::write::write_operands
Unexecuted instantiation: cranelift_codegen::write::write_operands
581
582
0
fn write_debug_tags(
583
0
    w: &mut dyn Write,
584
0
    func: &Function,
585
0
    inst: Inst,
586
0
    indent: &mut usize,
587
0
) -> fmt::Result {
588
0
    let tags = func.debug_tags.get(inst);
589
0
    if !tags.is_empty() {
590
0
        let tags = tags
591
0
            .iter()
592
0
            .map(|tag| format!("{tag}"))
Unexecuted instantiation: cranelift_codegen::write::write_debug_tags::{closure#0}
Unexecuted instantiation: cranelift_codegen::write::write_debug_tags::{closure#0}
593
0
            .collect::<Vec<_>>()
594
0
            .join(", ");
595
0
        let s = format!("<{tags}> ");
596
0
        write!(w, "{s}")?;
597
0
        *indent = indent.saturating_sub(s.len());
598
0
    }
599
0
    Ok(())
600
0
}
Unexecuted instantiation: cranelift_codegen::write::write_debug_tags
Unexecuted instantiation: cranelift_codegen::write::write_debug_tags
601
602
0
fn write_user_stack_map_entries(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
603
0
    let entries = match dfg.user_stack_map_entries(inst) {
604
0
        None => return Ok(()),
605
0
        Some(es) => es,
606
    };
607
0
    write!(w, ", stack_map=[")?;
608
0
    let mut need_comma = false;
609
0
    for entry in entries {
610
0
        if need_comma {
611
0
            write!(w, ", ")?;
612
0
        }
613
0
        write!(w, "{} @ {}+{}", entry.ty, entry.slot, entry.offset)?;
614
0
        need_comma = true;
615
    }
616
0
    write!(w, "]")?;
617
0
    Ok(())
618
0
}
Unexecuted instantiation: cranelift_codegen::write::write_user_stack_map_entries
Unexecuted instantiation: cranelift_codegen::write::write_user_stack_map_entries
619
620
/// Displayable slice of values.
621
struct DisplayValues<'a>(&'a [Value]);
622
623
impl<'a> fmt::Display for DisplayValues<'a> {
624
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
625
0
        for (i, val) in self.0.iter().enumerate() {
626
0
            if i == 0 {
627
0
                write!(f, "{val}")?;
628
            } else {
629
0
                write!(f, ", {val}")?;
630
            }
631
        }
632
0
        Ok(())
633
0
    }
Unexecuted instantiation: <cranelift_codegen::write::DisplayValues as core::fmt::Display>::fmt
Unexecuted instantiation: <cranelift_codegen::write::DisplayValues as core::fmt::Display>::fmt
634
}
635
636
#[cfg(test)]
637
mod tests {
638
    use crate::cursor::{Cursor, CursorPosition, FuncCursor};
639
    use crate::ir::types;
640
    use crate::ir::{Function, InstBuilder, StackSlotData, StackSlotKind, UserFuncName};
641
    use alloc::string::ToString;
642
643
    #[test]
644
    fn basic() {
645
        let mut f = Function::new();
646
        assert_eq!(f.to_string(), "function u0:0() fast {\n}\n");
647
648
        f.name = UserFuncName::testcase("foo");
649
        assert_eq!(f.to_string(), "function %foo() fast {\n}\n");
650
651
        f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0));
652
        assert_eq!(
653
            f.to_string(),
654
            "function %foo() fast {\n    ss0 = explicit_slot 4\n}\n"
655
        );
656
657
        let block = f.dfg.make_block();
658
        f.layout.append_block(block);
659
        assert_eq!(
660
            f.to_string(),
661
            "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0:\n}\n"
662
        );
663
664
        f.dfg.append_block_param(block, types::I8);
665
        assert_eq!(
666
            f.to_string(),
667
            "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8):\n}\n"
668
        );
669
670
        f.dfg.append_block_param(block, types::F32.by(4).unwrap());
671
        assert_eq!(
672
            f.to_string(),
673
            "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n}\n"
674
        );
675
676
        {
677
            let mut cursor = FuncCursor::new(&mut f);
678
            cursor.set_position(CursorPosition::After(block));
679
            cursor.ins().return_(&[])
680
        };
681
        assert_eq!(
682
            f.to_string(),
683
            "function %foo() fast {\n    ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n    return\n}\n"
684
        );
685
686
        let mut f = Function::new();
687
        f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 2));
688
        assert_eq!(
689
            f.to_string(),
690
            "function u0:0() fast {\n    ss0 = explicit_slot 4, align = 4\n}\n"
691
        );
692
    }
693
694
    #[test]
695
    fn aliases() {
696
        use crate::ir::InstBuilder;
697
698
        let mut func = Function::new();
699
        {
700
            let block0 = func.dfg.make_block();
701
            let mut pos = FuncCursor::new(&mut func);
702
            pos.insert_block(block0);
703
704
            // make some detached values for change_to_alias
705
            let v0 = pos.func.dfg.append_block_param(block0, types::I32);
706
            let v1 = pos.func.dfg.append_block_param(block0, types::I32);
707
            let v2 = pos.func.dfg.append_block_param(block0, types::I32);
708
            pos.func.dfg.detach_block_params(block0);
709
710
            // alias to a param--will be printed at beginning of block defining param
711
            let v3 = pos.func.dfg.append_block_param(block0, types::I32);
712
            pos.func.dfg.change_to_alias(v0, v3);
713
714
            // alias to an alias--should print attached to alias, not ultimate target
715
            pos.func.dfg.make_value_alias_for_serialization(v0, v2); // v0 <- v2
716
717
            // alias to a result--will be printed after instruction producing result
718
            let _dummy0 = pos.ins().iconst(types::I32, 42);
719
            let v4 = pos.ins().iadd(v0, v0);
720
            pos.func.dfg.change_to_alias(v1, v4);
721
            let _dummy1 = pos.ins().iconst(types::I32, 23);
722
            let _v7 = pos.ins().iadd(v1, v1);
723
        }
724
        assert_eq!(
725
            func.to_string(),
726
            "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"
727
        );
728
    }
729
730
    #[test]
731
    fn cold_blocks() {
732
        let mut func = Function::new();
733
        {
734
            let mut pos = FuncCursor::new(&mut func);
735
736
            let block0 = pos.func.dfg.make_block();
737
            pos.insert_block(block0);
738
            pos.func.layout.set_cold(block0);
739
740
            let block1 = pos.func.dfg.make_block();
741
            pos.insert_block(block1);
742
            pos.func.dfg.append_block_param(block1, types::I32);
743
            pos.func.layout.set_cold(block1);
744
        }
745
746
        assert_eq!(
747
            func.to_string(),
748
            "function u0:0() fast {\nblock0 cold:\n\nblock1(v0: i32) cold:\n}\n"
749
        );
750
    }
751
}