/ src / ir_display.rs
ir_display.rs
  1  // This code is bad!
  2  
  3  use crate::ir::*;
  4  use std::fmt::{Display, Formatter, Result};
  5  
  6  type F<'a, 'b> = &'a mut Formatter<'b>;
  7  
  8  const DISPLAY_TYS: bool = false;
  9  
 10  struct SepBy<'a, T, U: ?Sized>(T, &'a U);
 11  impl<T, I, U> Display for SepBy<'_, T, U>
 12  where
 13      T: Clone + IntoIterator<Item = I>,
 14      I: Display,
 15      U: Display + ?Sized,
 16  {
 17      fn fmt(&self, f: F) -> Result {
 18          for (i, item) in self.0.clone().into_iter().enumerate() {
 19              if i != 0 {
 20                  write!(f, "{}", self.1)?;
 21              }
 22              write!(f, "{item}")?;
 23          }
 24          Ok(())
 25      }
 26  }
 27  
 28  struct Commas<T>(T);
 29  impl<T, I> Display for Commas<T>
 30  where
 31      T: Clone + IntoIterator<Item = I>,
 32      I: Display,
 33  {
 34      fn fmt(&self, f: F) -> Result {
 35          write!(f, "{}", SepBy(self.0.clone(), ", "))
 36      }
 37  }
 38  
 39  struct WithTy<'a, T: ?Sized>(&'a T, &'a Ty);
 40  impl<T: Display + ?Sized> Display for WithTy<'_, T> {
 41      fn fmt(&self, f: F) -> Result {
 42          write!(f, "{}", self.0)?;
 43          if DISPLAY_TYS {
 44              write!(f, " {}", self.1)?;
 45          }
 46          Ok(())
 47      }
 48  }
 49  
 50  impl<'a, T> Clone for WithTy<'a, T> {
 51      fn clone(&self) -> Self {
 52          *self
 53      }
 54  }
 55  
 56  impl<'a, T> Copy for WithTy<'a, T> {}
 57  
 58  struct Returns<T>(T);
 59  impl<T, I> Display for Returns<T>
 60  where
 61      T: Clone + IntoIterator<Item = I>,
 62      I: Display,
 63  {
 64      fn fmt(&self, f: F) -> Result {
 65          let oops: Vec<_> = self.0.clone().into_iter().collect();
 66          match oops.len() {
 67              0 => Ok(()),
 68              1 => write!(f, "{}", oops[0]),
 69              _ => write!(f, "{{{}}}", Commas(&oops)),
 70          }
 71      }
 72  }
 73  
 74  struct ReturnsSpace<T>(T);
 75  impl<T, I> Display for ReturnsSpace<T>
 76  where
 77      T: Clone + IntoIterator<Item = I>,
 78      I: Display,
 79  {
 80      fn fmt(&self, f: F) -> Result {
 81          let returns = format!("{}", Returns(self.0.clone()));
 82          if returns.is_empty() {
 83              Ok(())
 84          } else {
 85              write!(f, " {returns}")
 86          }
 87      }
 88  }
 89  
 90  trait DisplayWithName {
 91      fn fmt_with_name(&self, f: F, name: &str) -> Result;
 92      fn with_name<'a>(&'a self, name: &'a str) -> impl Display + 'a
 93      where
 94          Self: Sized,
 95      {
 96          struct WithName<'a, T>(&'a T, &'a str);
 97          impl<T: DisplayWithName> Display for WithName<'_, T> {
 98              fn fmt(&self, f: F) -> Result {
 99                  self.0.fmt_with_name(f, self.1)
100              }
101          }
102          WithName(self, name)
103      }
104  }
105  
106  impl DisplayWithName for BlockId {
107      fn fmt_with_name(&self, f: F, name: &str) -> Result {
108          write!(f, "{name}_{}", self.0)
109      }
110  }
111  
112  impl DisplayWithName for Exit {
113      fn fmt_with_name(&self, f: F, name: &str) -> Result {
114          match self {
115              Self::Jump(loc) => write!(f, "goto {}", loc.with_name(name)),
116              Self::CondJump(cond, loc_true, loc_false) => write!(
117                  f,
118                  "if {cond}: goto {} else goto {}",
119                  loc_true.with_name(name),
120                  loc_false.with_name(name)
121              ),
122              Self::Return(regs) => write!(f, "return{}", ReturnsSpace(regs)),
123          }
124      }
125  }
126  
127  impl DisplayWithName for Function {
128      fn fmt_with_name<'a>(&'a self, f: F, name: &str) -> Result {
129          let reg_def = |r: &'a Register| WithTy(r, self.tys.get(r).unwrap_or(&Ty::Int(IntKind::U8)));
130          write!(
131              f,
132              "fn {name}({})",
133              Commas(self.parameters.iter().map(reg_def)),
134          )?;
135          for (id, block) in self.iter() {
136              write!(f, "\n{}:", id.with_name(name))?;
137              for inst in &block.insts {
138                  write!(f, "\n    ")?;
139                  match inst {
140                      Inst::Store(r, sk) => {
141                          use StoreKind as Sk;
142                          write!(f, "{} = ", reg_def(r))?;
143                          match sk {
144                              Sk::StackAlloc(ty) => write!(f, "StackAlloc({ty})"),
145                              Sk::Int(i, kind) => write!(f, "{i}_{kind}"),
146                              Sk::Copy(r) => write!(f, "{r}"),
147                              Sk::Read(r) => write!(f, "{r}^"),
148                              Sk::UnaryOp(op, inner) => write!(
149                                  f,
150                                  "{}{inner}",
151                                  match op {
152                                      UnaryOp::Neg => "-",
153                                  }
154                              ),
155                              Sk::BinOp(op, lhs, rhs) => write!(
156                                  f,
157                                  "{lhs} {} {rhs}",
158                                  match op {
159                                      BinOp::Add => "+",
160                                      BinOp::Sub => "-",
161                                      BinOp::Mul => "*",
162                                      BinOp::CmpLe => "<=",
163                                  }
164                              ),
165                              Sk::IntCast(inner, ty) => write!(f, "{inner} as {ty}"),
166                              Sk::PtrOffset(lhs, rhs) => write!(f, "{lhs}[{rhs}]@"),
167                              Sk::FieldOffset(inner, field) => write!(f, "{inner}.{field}@"),
168                              Sk::Phi(regs) => write!(
169                                  f,
170                                  "Phi({})",
171                                  Commas(
172                                      regs.iter()
173                                          .map(|(id, r)| format!("{}: {r}", id.with_name(name)))
174                                  )
175                              ),
176  
177                              Sk::Function(name) => write!(f, "{name}"),
178                          }
179                      }
180                      Inst::Write(dst, src) => write!(f, "{dst}^ = {src}"),
181                      Inst::Call {
182                          callee,
183                          returns,
184                          args,
185                      } => write!(
186                          f,
187                          "[{}] = {callee}({})",
188                          Returns(returns.iter().map(reg_def)),
189                          Commas(args)
190                      ),
191                      Inst::Nop => write!(f, "Nop"),
192                  }?;
193              }
194              write!(f, "\n    {}", block.exit.with_name(name))?;
195          }
196          Ok(())
197      }
198  }
199  
200  impl Display for Register {
201      fn fmt(&self, f: F) -> Result {
202          write!(f, "%{}", self.0)
203      }
204  }
205  
206  impl Display for Condition {
207      fn fmt(&self, f: F) -> Result {
208          match self {
209              Self::NonZero(r) => write!(f, "NonZero({r})"),
210          }
211      }
212  }
213  
214  impl Display for Program {
215      fn fmt(&self, f: F) -> Result {
216          for (i, (name, function)) in self.functions.iter().enumerate() {
217              if i != 0 {
218                  write!(f, "\n\n")?;
219              }
220              write!(f, "{}", function.with_name(name))?;
221          }
222          Ok(())
223      }
224  }
225  
226  impl Display for Ty {
227      fn fmt(&self, f: F) -> Result {
228          match self {
229              Self::Int(kind) => write!(f, "{kind}"),
230              Self::Pointer(inner) => write!(f, "{inner}^"),
231              Self::Function(params, returns) => {
232                  write!(f, "fn({}){}", Commas(params), ReturnsSpace(returns))
233              }
234              Self::Struct(fields) => {
235                  write!(
236                      f,
237                      "struct({})",
238                      Commas(fields.iter().map(|(name, ty)| format!("{name} {ty}")))
239                  )
240              }
241          }
242      }
243  }
244  
245  impl Display for IntKind {
246      fn fmt(&self, f: F) -> Result {
247          let name = match self {
248              Self::Usize => "usize",
249              Self::U8 => "u8",
250          };
251          write!(f, "{name}")
252      }
253  }
254  
255  impl Display for Cfg {
256      fn fmt(&self, f: &mut Formatter<'_>) -> Result {
257          write!(f, "digraph CFG {{")?;
258          for (index, node) in &self.map {
259              for succ in &node.successors {
260                  write!(f, "    \"n{}\" -> \"n{}\"", index.0, succ.0)?;
261              }
262          }
263          write!(f, "}}")?;
264  
265          write!(f, "digraph DomTree {{")?;
266          for (index, node) in &self.map {
267              let Some(parent) = &node.immediate_dominator else {
268                  continue;
269              };
270              write!(f, "    \"n{}\" -> \"n{}\"", parent.0, index.0)?;
271          }
272          write!(f, "}}")?;
273          Ok(())
274      }
275  }