209 lines
6 KiB
Rust
209 lines
6 KiB
Rust
//! Text formatting for Slonik IR.
|
|
|
|
use std::fmt;
|
|
|
|
use crate::ir::{Block, BlockCall, Body, Stmt, StmtData, Value};
|
|
|
|
/// Writes `body` in textual form.
|
|
pub fn write_body(f: &mut fmt::Formatter<'_>, body: &Body) -> fmt::Result {
|
|
Printer { body }.write_body(f)
|
|
}
|
|
|
|
impl fmt::Display for Body {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write_body(f, self)
|
|
}
|
|
}
|
|
|
|
struct Printer<'a> {
|
|
body: &'a Body,
|
|
}
|
|
|
|
impl Printer<'_> {
|
|
fn write_body(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
writeln!(f, "body {{")?;
|
|
|
|
let mut first = true;
|
|
for block in self.body.blocks() {
|
|
if !first {
|
|
writeln!(f)?;
|
|
}
|
|
first = false;
|
|
self.write_block(f, block)?;
|
|
}
|
|
|
|
writeln!(f, "}}")
|
|
}
|
|
|
|
fn write_block(&self, f: &mut fmt::Formatter<'_>, block: Block) -> fmt::Result {
|
|
write!(f, " ^{block}")?;
|
|
|
|
let params = self.body.block_params(block);
|
|
if !params.is_empty() {
|
|
write!(f, "(")?;
|
|
for (i, ¶m) in params.iter().enumerate() {
|
|
if i != 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
write!(f, "%{}: {}", param, self.body.value_type(param))?;
|
|
}
|
|
write!(f, ")")?;
|
|
}
|
|
|
|
writeln!(f, ":")?;
|
|
|
|
for &stmt in self.body.block_stmts(block) {
|
|
self.write_stmt(f, stmt)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn write_stmt(&self, f: &mut fmt::Formatter<'_>, stmt: Stmt) -> fmt::Result {
|
|
write!(f, " ")?;
|
|
|
|
match *self.body.stmt_data(stmt) {
|
|
StmtData::IConst { imm, result } => {
|
|
writeln!(f, "%{result} = iconst {imm} : {}", self.body.value_type(result))
|
|
}
|
|
|
|
StmtData::F32Const { bits, result } => {
|
|
writeln!(f, "%{result} = f32const 0x{bits:08x} : f32")
|
|
}
|
|
|
|
StmtData::F64Const { bits, result } => {
|
|
writeln!(f, "%{result} = f64const 0x{bits:016x} : f64")
|
|
}
|
|
|
|
StmtData::BConst { value, result } => {
|
|
writeln!(f, "%{result} = bconst {value} : bool")
|
|
}
|
|
|
|
StmtData::Unary { op, arg, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = {op} %{arg} : {}",
|
|
self.body.value_type(result)
|
|
)
|
|
}
|
|
|
|
StmtData::Binary { op, lhs, rhs, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = {op} %{lhs}, %{rhs} : {}",
|
|
self.body.value_type(result)
|
|
)
|
|
}
|
|
|
|
StmtData::Cast { op, arg, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = {op} %{arg} : {} -> {}",
|
|
self.body.value_type(arg),
|
|
self.body.value_type(result)
|
|
)
|
|
}
|
|
|
|
StmtData::Icmp { cc, lhs, rhs, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = icmp {cc} %{lhs}, %{rhs} : {}",
|
|
self.body.value_type(lhs)
|
|
)
|
|
}
|
|
|
|
StmtData::Fcmp { cc, lhs, rhs, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = fcmp {cc} %{lhs}, %{rhs} : {}",
|
|
self.body.value_type(lhs)
|
|
)
|
|
}
|
|
|
|
StmtData::Select {
|
|
cond,
|
|
if_true,
|
|
if_false,
|
|
result,
|
|
} => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = select %{cond}, %{if_true}, %{if_false} : {}",
|
|
self.body.value_type(result)
|
|
)
|
|
}
|
|
|
|
StmtData::Load { addr, size, result } => {
|
|
writeln!(
|
|
f,
|
|
"%{result} = load %{addr} : {size} -> {}",
|
|
self.body.value_type(result)
|
|
)
|
|
}
|
|
|
|
StmtData::Store { addr, value, size } => {
|
|
writeln!(f, "store %{value}, %{addr} : {size}")
|
|
}
|
|
|
|
StmtData::Call { callee, args } => {
|
|
write!(f, "call %{callee}")?;
|
|
let args = args.as_slice(&self.body.value_lists);
|
|
if !args.is_empty() {
|
|
write!(f, "(")?;
|
|
self.write_value_list(f, args)?;
|
|
write!(f, ")")?;
|
|
}
|
|
writeln!(f)
|
|
}
|
|
|
|
StmtData::Jump { dst } => {
|
|
write!(f, "br ")?;
|
|
self.write_block_call(f, dst)?;
|
|
writeln!(f)
|
|
}
|
|
|
|
StmtData::BrIf {
|
|
cond,
|
|
then_dst,
|
|
else_dst,
|
|
} => {
|
|
write!(f, "cond_br %{cond}, ")?;
|
|
self.write_block_call(f, then_dst)?;
|
|
write!(f, ", ")?;
|
|
self.write_block_call(f, else_dst)?;
|
|
writeln!(f)
|
|
}
|
|
|
|
StmtData::Return { values } => {
|
|
write!(f, "return")?;
|
|
let values = values.as_slice(&self.body.value_lists);
|
|
if !values.is_empty() {
|
|
write!(f, " ")?;
|
|
self.write_value_list(f, values)?;
|
|
}
|
|
writeln!(f)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn write_block_call(&self, f: &mut fmt::Formatter<'_>, call: BlockCall) -> fmt::Result {
|
|
write!(f, "^{}", call.block)?;
|
|
let args = call.args.as_slice(&self.body.value_lists);
|
|
if !args.is_empty() {
|
|
write!(f, "(")?;
|
|
self.write_value_list(f, args)?;
|
|
write!(f, ")")?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn write_value_list(&self, f: &mut fmt::Formatter<'_>, values: &[Value]) -> fmt::Result {
|
|
for (i, value) in values.iter().enumerate() {
|
|
if i != 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
write!(f, "%{value}")?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|