1use 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}