Skip to main content

backend_lang/mir/
print.rs

1//! The deterministic text form of a function; the grammar is documented on
2//! the [`mir`](crate::mir) module.
3
4use core::fmt::{self, Write};
5
6use super::entity::Block;
7use super::function::{Function, SlotKind};
8use super::operand::{ImplicitKind, Operand};
9use crate::regs::{Reg, RegSet};
10use crate::target::{InstKind, Target};
11
12impl Function {
13    fn write_reg(&self, f: &mut fmt::Formatter<'_>, reg: Reg, with_class: bool) -> fmt::Result {
14        let target = self.target();
15        match (reg.as_phys(), reg.as_virt()) {
16            (Some(p), _) => f.write_str(target.reg(p).name()),
17            (_, Some(v)) => {
18                write!(f, "%{}", v.index())?;
19                if with_class {
20                    let class = self
21                        .vreg_class(v)
22                        .map_or("<invalid>", |c| target.class(c).name());
23                    write!(f, ":{class}")?;
24                }
25                Ok(())
26            }
27            _ => Ok(()),
28        }
29    }
30
31    fn write_operand(&self, f: &mut fmt::Formatter<'_>, op: &Operand, def: bool) -> fmt::Result {
32        let target = self.target();
33        match *op {
34            Operand::Reg(r) => self.write_reg(f, r, def),
35            Operand::Imm(v) => write!(f, "{v}"),
36            Operand::Mem(m) => {
37                f.write_char('[')?;
38                let mut first = true;
39                if let Some(b) = m.base_reg() {
40                    self.write_reg(f, b, false)?;
41                    first = false;
42                }
43                if let Some((i, s)) = m.index_reg() {
44                    if !first {
45                        f.write_str(" + ")?;
46                    }
47                    self.write_reg(f, i, false)?;
48                    write!(f, "*{}", s.factor())?;
49                    first = false;
50                }
51                let d = m.disp();
52                if first {
53                    write!(f, "{d}")?;
54                } else if d > 0 {
55                    write!(f, " + {d}")?;
56                } else if d < 0 {
57                    write!(f, " - {}", i64::from(d).unsigned_abs())?;
58                }
59                f.write_char(']')
60            }
61            Operand::Slot { slot, offset } => {
62                write!(f, "{slot}")?;
63                if offset != 0 {
64                    write!(f, "{offset:+}")?;
65                }
66                Ok(())
67            }
68            Operand::Symbol(s) => write!(f, "@{}", self.symbol_name(s).unwrap_or("<invalid>")),
69            Operand::Cond(c) => f.write_str(target.cond_name(c)),
70            Operand::Block(call) => {
71                write!(f, "{}(", call.block())?;
72                for (i, a) in self.args(call).iter().enumerate() {
73                    if i > 0 {
74                        f.write_str(", ")?;
75                    }
76                    self.write_operand(f, a, false)?;
77                }
78                f.write_char(')')
79            }
80        }
81    }
82
83    fn write_list(&self, f: &mut fmt::Formatter<'_>, ops: &[Operand], def: bool) -> fmt::Result {
84        for (i, op) in ops.iter().enumerate() {
85            if i > 0 {
86                f.write_str(", ")?;
87            }
88            self.write_operand(f, op, def)?;
89        }
90        Ok(())
91    }
92
93    fn write_block_header(&self, f: &mut fmt::Formatter<'_>, block: Block) -> fmt::Result {
94        write!(f, "{block}")?;
95        let params = self.params(block);
96        if !params.is_empty() {
97            f.write_char('(')?;
98            self.write_list(f, params, true)?;
99            f.write_char(')')?;
100        }
101        f.write_str(":\n")
102    }
103}
104
105fn write_regs(
106    f: &mut fmt::Formatter<'_>,
107    target: &Target,
108    label: &str,
109    regs: RegSet,
110) -> fmt::Result {
111    if regs.is_empty() {
112        return Ok(());
113    }
114    write!(f, " {label}(")?;
115    for (i, r) in regs.iter().enumerate() {
116        if i > 0 {
117            f.write_str(", ")?;
118        }
119        f.write_str(target.reg(r).name())?;
120    }
121    f.write_char(')')
122}
123
124impl fmt::Display for Function {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        let target = self.target();
127        writeln!(f, "function {} ({}) {{", self.name(), self.abi().name())?;
128        if !self.frame_pointer() {
129            f.write_str("    omit-frame-pointer\n")?;
130        }
131        if self.outgoing() > 0 {
132            writeln!(f, "    outgoing {}", self.outgoing())?;
133        }
134        for (i, s) in self.slots().iter().enumerate() {
135            match *s {
136                SlotKind::Local { size, align } => {
137                    writeln!(f, "    ss{i} = local {size}, align {align}")?;
138                }
139                SlotKind::Incoming { offset, size } => {
140                    writeln!(f, "    ss{i} = incoming {offset}, size {size}")?;
141                }
142            }
143        }
144        for (i, name) in self.symbols.iter().enumerate() {
145            writeln!(f, "    sym{i} = @{name}")?;
146        }
147        for block in self.blocks() {
148            self.write_block_header(f, block)?;
149            for &inst in self.insts(block) {
150                let Some(opcode) = self.opcode(inst) else {
151                    continue;
152                };
153                let ops = self.operands(inst);
154                let (name, defs) = match target.inst(opcode) {
155                    Some(d) => (
156                        d.name(),
157                        match d.kind() {
158                            InstKind::Copy => ops.len().min(1),
159                            InstKind::ParallelCopy => ops.len() / 2,
160                            _ => d.defs().min(ops.len()),
161                        },
162                    ),
163                    None => ("<invalid>", 0),
164                };
165                f.write_str("    ")?;
166                if defs > 0 {
167                    self.write_list(f, &ops[..defs], true)?;
168                    f.write_str(" = ")?;
169                }
170                f.write_str(name)?;
171                if ops.len() > defs {
172                    f.write_char(' ')?;
173                    self.write_list(f, &ops[defs..], false)?;
174                }
175                let imp = self.implicit(inst);
176                let uses: RegSet = imp
177                    .iter()
178                    .filter(|i| i.kind == ImplicitKind::Use)
179                    .map(|i| i.reg)
180                    .collect();
181                let defs: RegSet = imp
182                    .iter()
183                    .filter(|i| i.kind == ImplicitKind::Def)
184                    .map(|i| i.reg)
185                    .collect();
186                write_regs(f, target, "implicit", uses)?;
187                write_regs(f, target, "implicit-def", defs)?;
188                write_regs(f, target, "clobber", self.clobbers(inst))?;
189                f.write_char('\n')?;
190            }
191        }
192        f.write_str("}\n")
193    }
194}