1use crate::ast;
4use id_arena::{Arena, Id};
5use std::{
6 collections::HashSet,
7 fmt::{self, Display},
8};
9
10trait DisplayWithContext {
12 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result;
13}
14
15fn topo_sort_statements(
16 stmts: &Arena<ast::Statement>,
17 seen: &mut HashSet<Id<ast::Statement>>,
18 root: Id<ast::Statement>,
19) -> Vec<Id<ast::Statement>> {
20 let mut seq = vec![];
21
22 let mut stack = vec![Entry::Trace(root)];
23 while let Some(entry) = stack.pop() {
24 let id = match entry {
25 Entry::Finished(id) => {
26 seq.push(id);
27 continue;
28 }
29 Entry::Trace(id) if seen.contains(&id) => continue,
30 Entry::Trace(id) => {
31 seen.insert(id);
32 id
33 }
34 };
35
36 stack.push(Entry::Finished(id));
37
38 match &stmts[id] {
39 ast::Statement::Pc(ast::Pc { x, y }) => {
40 if let ast::Operand::Value(v) = *y {
41 stack.push(Entry::Trace(v.into()));
42 }
43 if let ast::Operand::Value(v) = *x {
44 stack.push(Entry::Trace(v.into()));
45 }
46 }
47 ast::Statement::BlockPc(ast::BlockPc {
48 block,
49 predecessor: _,
50 x,
51 y,
52 }) => {
53 if let ast::Operand::Value(v) = *y {
54 stack.push(Entry::Trace(v.into()));
55 }
56 if let ast::Operand::Value(v) = *x {
57 stack.push(Entry::Trace(v.into()));
58 }
59 stack.push(Entry::Trace((*block).into()));
60 }
61 ast::Statement::Assignment(ast::Assignment { value, .. }) => match value {
62 | ast::AssignmentRhs::Var
63 | ast::AssignmentRhs::Block(_)
64 | ast::AssignmentRhs::ReservedInst
65 | ast::AssignmentRhs::ReservedConst => continue,
66 ast::AssignmentRhs::Phi(ast::Phi { block, values }) => {
67 for v in values.iter().rev().copied() {
68 if let ast::Operand::Value(v) = v {
69 stack.push(Entry::Trace(v.into()));
70 }
71 }
72 stack.push(Entry::Trace((*block).into()));
73 }
74 ast::AssignmentRhs::Instruction(inst) => {
75 let n = stack.len();
76 inst.value_ids(|v| stack.push(Entry::Trace(v.into())));
77 stack[n..].reverse();
78 }
79 },
80 }
81 }
82
83 return seq;
84
85 enum Entry {
86 Trace(Id<ast::Statement>),
87 Finished(Id<ast::Statement>),
88 }
89}
90
91impl Display for ast::Replacement {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 let mut seen = HashSet::new();
94 match self {
95 ast::Replacement::LhsRhs {
96 statements,
97 lhs,
98 rhs,
99 } => {
100 for s in topo_sort_statements(statements, &mut seen, lhs.value.into()) {
101 statements[s].display(statements, f)?;
102 }
103 lhs.display(statements, f)?;
104 match rhs {
105 ast::Operand::Value(v) => {
106 for s in topo_sort_statements(statements, &mut seen, (*v).into()) {
107 statements[s].display(statements, f)?;
108 }
109 writeln!(f, "result {}", self.assignment(*v).name)
110 }
111 ast::Operand::Constant(ast::Constant { value, r#type }) => {
112 write!(f, "result {}", value)?;
113 if let Some(ty) = r#type {
114 write!(f, ":{}", ty)?;
115 }
116 writeln!(f)
117 }
118 }
119 }
120 ast::Replacement::Cand { statements, cand } => {
121 if let ast::Operand::Value(v) = cand.lhs {
122 for s in topo_sort_statements(statements, &mut seen, v.into()) {
123 statements[s].display(statements, f)?;
124 }
125 }
126 if let ast::Operand::Value(v) = cand.rhs {
127 for s in topo_sort_statements(statements, &mut seen, v.into()) {
128 statements[s].display(statements, f)?;
129 }
130 }
131 cand.display(statements, f)
132 }
133 }
134 }
135}
136
137impl Display for ast::LeftHandSide {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 let mut seen = HashSet::new();
140 for s in topo_sort_statements(&self.statements, &mut seen, self.infer.value.into()) {
141 self.statements[s].display(&self.statements, f)?;
142 }
143 self.infer.display(&self.statements, f)
144 }
145}
146
147impl Display for ast::RightHandSide {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 let mut seen = HashSet::new();
150 if let ast::Operand::Value(v) = self.result {
151 for s in topo_sort_statements(&self.statements, &mut seen, v.into()) {
152 self.statements[s].display(&self.statements, f)?;
153 }
154 }
155 write!(f, "result ")?;
156 self.result.display(&self.statements, f)
157 }
158}
159
160fn assignment(statements: &Arena<ast::Statement>, id: ast::ValueId) -> &ast::Assignment {
161 match &statements[id.into()] {
162 ast::Statement::Assignment(a) => a,
163 _ => panic!("use of an `id` that is not from this `Replacement`'s arena"),
164 }
165}
166
167impl DisplayWithContext for ast::Infer {
168 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
169 write!(f, "infer ")?;
170 self.value.display(statements, f)?;
171 for attr in &self.attributes {
172 write!(f, " {}", attr)?;
173 }
174 writeln!(f)
175 }
176}
177
178impl DisplayWithContext for ast::Cand {
179 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
180 write!(f, "cand ")?;
181 self.lhs.display(statements, f)?;
182 write!(f, " ")?;
183 self.rhs.display(statements, f)?;
184 for attr in &self.attributes {
185 write!(f, " {}", attr)?;
186 }
187 writeln!(f)
188 }
189}
190
191impl DisplayWithContext for ast::Statement {
192 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
193 match self {
194 ast::Statement::Assignment(a) => a.display(statements, f)?,
195 ast::Statement::Pc(pc) => pc.display(statements, f)?,
196 ast::Statement::BlockPc(bpc) => bpc.display(statements, f)?,
197 }
198
199 writeln!(f)
200 }
201}
202
203impl DisplayWithContext for ast::Assignment {
204 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
205 write!(f, "{}", self.name)?;
206 if let Some(ty) = self.r#type {
207 write!(f, ":{}", ty)?;
208 }
209 write!(f, " = ")?;
210 self.value.display(statements, f)?;
211 for attr in &self.attributes {
212 write!(f, " {}", attr)?;
213 }
214 Ok(())
215 }
216}
217
218impl DisplayWithContext for ast::AssignmentRhs {
219 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
220 match self {
221 ast::AssignmentRhs::Var => write!(f, "var"),
222 ast::AssignmentRhs::Block(block) => <ast::Block as Display>::fmt(block, f),
223 ast::AssignmentRhs::Phi(phi) => phi.display(statements, f),
224 ast::AssignmentRhs::ReservedInst => write!(f, "reservedinst"),
225 ast::AssignmentRhs::ReservedConst => write!(f, "reservedconst"),
226 ast::AssignmentRhs::Instruction(inst) => inst.display(statements, f),
227 }
228 }
229}
230
231impl Display for ast::Block {
232 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233 write!(f, "block {}", self.predecessors)
234 }
235}
236
237impl DisplayWithContext for ast::Phi {
238 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
239 write!(f, "phi ")?;
240 self.block.display(statements, f)?;
241 for v in &self.values {
242 write!(f, ", ")?;
243 v.display(statements, f)?;
244 }
245 Ok(())
246 }
247}
248
249impl DisplayWithContext for ast::Instruction {
250 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
251 write!(f, "{}", self.instruction_name())?;
252 let mut first = true;
253 let mut result = Ok(());
254 self.operands(|x| {
255 result = result.and_then(|_| {
256 if first {
257 write!(f, " ")?;
258 first = false;
259 } else {
260 write!(f, ", ")?;
261 }
262 x.display(statements, f)
263 });
264 });
265 result
266 }
267}
268
269impl DisplayWithContext for ast::Pc {
270 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
271 write!(f, "pc ")?;
272 self.x.display(statements, f)?;
273 write!(f, " ")?;
274 self.y.display(statements, f)
275 }
276}
277
278impl DisplayWithContext for ast::BlockPc {
279 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
280 write!(f, "blockpc ")?;
281 self.block.display(statements, f)?;
282 write!(f, " {}", self.predecessor)?;
283 self.x.display(statements, f)?;
284 write!(f, " ")?;
285 self.y.display(statements, f)
286 }
287}
288
289impl Display for ast::RootAttribute {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291 write!(f, "(")?;
292 match self {
293 ast::RootAttribute::DemandedBits(db) => {
294 write!(f, "demandedBits=")?;
295 for b in db {
296 if *b {
297 write!(f, "1")?;
298 } else {
299 write!(f, "0")?;
300 }
301 }
302 }
303 ast::RootAttribute::HarvestedFromUse => write!(f, "harvestedFromUse")?,
304 }
305 write!(f, ")")
306 }
307}
308
309impl Display for ast::Attribute {
310 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311 write!(f, "(")?;
312 match self {
313 ast::Attribute::KnownBits(bits) => {
314 write!(f, "knownBits=")?;
315 for b in bits {
316 match b {
317 None => write!(f, "x")?,
318 Some(true) => write!(f, "1")?,
319 Some(false) => write!(f, "0")?,
320 }
321 }
322 }
323 ast::Attribute::PowerOfTwo => write!(f, "powerOfTwo")?,
324 ast::Attribute::Negative => write!(f, "negative")?,
325 ast::Attribute::NonNegative => write!(f, "nonNegative")?,
326 ast::Attribute::NonZero => write!(f, "nonZero")?,
327 ast::Attribute::HasExternalUses => write!(f, "hasExternalUses")?,
328 ast::Attribute::SignBits(n) => write!(f, "signBits={}", n)?,
329 ast::Attribute::Range(min, max) => write!(f, "range=[{},{})", min, max)?,
330 }
331 write!(f, ")")
332 }
333}
334
335impl DisplayWithContext for ast::Operand {
336 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
337 match self {
338 ast::Operand::Value(id) => id.display(statements, f),
339 ast::Operand::Constant(c) => <ast::Constant as Display>::fmt(c, f),
340 }
341 }
342}
343
344impl Display for ast::Constant {
345 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
346 write!(f, "{}", self.value)?;
347 if let Some(ty) = self.r#type {
348 write!(f, ":{}", ty)?;
349 }
350 Ok(())
351 }
352}
353
354impl DisplayWithContext for ast::ValueId {
355 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
356 write!(f, "{}", assignment(statements, *self).name)
357 }
358}
359
360impl DisplayWithContext for ast::BlockId {
361 fn display(&self, statements: &Arena<ast::Statement>, f: &mut fmt::Formatter) -> fmt::Result {
362 write!(f, "{}", assignment(statements, self.0).name)
363 }
364}
365
366impl Display for ast::Type {
367 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
368 write!(f, "i{}", self.width)
369 }
370}