You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
6.5 KiB

use super::ir::{
basicblock::BasicBlock,
context::Context,
function::Function,
global::{Global, GlobalData},
instruction::{
BinaryOp as IBinaryOp,InstructionKind,
MemAccessOp, TerminatorOp
},
typ::{Typ, TypeData},
value::{Value, ValueKind},
};
use crate::{
frontend::ir::instruction::Instruction,
utils::{
linked_list::LinkedListContainer,
storage::{ArenaPtr, Idx},
},
};
pub trait Display {
fn display(self, ctx: &Context) -> String;
}
impl Context {
pub fn get_ir_string(&self) -> String {
let mut ir = String::new();
for GlobalData {
self_ptr: global, ..
} in self.globals.iter()
{
ir += &format!("{}\n", global.display(self));
}
for func in self.get_functions() {
ir += &format!("{}\n", func.display(self));
}
ir
}
}
impl Display for Global {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
let typ = self.value(ctx).typ().display(ctx);
if self.value(ctx).is_undef() || self.value(ctx).is_zero() {
ir += &format!("@{} = global {} zeroinitializer\n", self.name(ctx), typ);
} else {
ir += &format!(
"@{} = global {} {}\n",
self.name(ctx),
typ,
self.value(ctx).to_string(ctx)
);
}
ir
}
}
impl Display for Function {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
ir += &format!(
"define {} @{}(",
self.get_return_type(ctx).display(ctx),
self.get_id(ctx)
);
for (i, param) in self.get_parameters(ctx).iter().enumerate() {
if i != 0 {
ir += ", ";
}
ir += &format!("{} {}", param.kind(ctx).display(ctx), param.display(ctx));
}
ir += ") {\n";
for bbk in self.iter(ctx) {
ir += &format!("{}\n", bbk.display(ctx));
}
ir += "}";
ir
}
}
impl Display for Typ {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
match self.deref(ctx).unwrap() {
TypeData::Void => {
ir += "void";
}
TypeData::Int32 => {
ir += "i32";
}
TypeData::Ptr { typ_of_ptr: typ } => {
if typ.is_void(ctx) {
ir += &format!("i8*")
} else {
ir += &format!("{}*", typ.display(ctx));
}
}
}
ir
}
}
impl Display for BasicBlock {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
ir += &format!("{}:", self.get_name());
for inst in self.iter(ctx) {
ir += &format!("\n\t{}", inst.display(ctx));
}
ir
}
}
impl Display for Instruction {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
if let Some(result) = self.get_result(ctx) {
ir += &format!("{} = ", result.display(ctx));
}
match self.get_kind(ctx) {
InstructionKind::Terminator { op } => match op {
TerminatorOp::Ret => {
if let Some(ret_val) = self.get_operand(ctx, 0) {
ir += &format!(
"ret {} {}",
ret_val.kind(ctx).display(ctx),
ret_val.display(ctx)
);
} else {
ir += "ret void";
}
}
TerminatorOp::Br => {
ir += &format!(
"br label %{}",
self.get_operand_bbk(ctx, 0)
.expect("Failed to get the first operand of the br instruction")
.get_name()
);
}
},
InstructionKind::Binary { op } => match op {
IBinaryOp::Add => {
let op1 = self.get_operand(ctx, 0).unwrap();
let op2 = self.get_operand(ctx, 1).unwrap();
let typ = op1.kind(ctx);
ir += &format!(
"add {} {}, {}",
typ.display(ctx),
op1.display(ctx),
op2.display(ctx)
);
}
},
InstructionKind::MemAccess { op } => {
match op {
MemAccessOp::Alloca { typ } => {
ir += &format!("alloca {}", typ.display(ctx));
}
MemAccessOp::Load => {
let typ = self.result_typ(ctx);
let op1 = self.get_operand(ctx, 0).unwrap();
let typ_of_op1 = op1.kind(ctx);
ir += &format!(
"load {}, {}* {}",
typ.display(ctx),
typ_of_op1.display(ctx),
op1.display(ctx)
);
}
MemAccessOp::Store => {
let op1 = self.get_operand(ctx, 0).unwrap();
let typ_of_op1 = op1.kind(ctx);
let op2 = self.get_operand(ctx, 1).unwrap();
let typ_of_op2 = op2.kind(ctx);
ir += &format!(
"store {} {}, {}* {}",
typ_of_op1.display(ctx),
op1.display(ctx),
typ_of_op2.display(ctx),
op2.display(ctx)
);
}
};
}
}
ir
}
}
impl Display for Value {
fn display(self, ctx: &Context) -> String {
let mut ir = String::new();
match &self.deref(ctx).unwrap().kind {
ValueKind::InstResult {
instruction: _,
typ: _,
}
| ValueKind::Parameter {
function: _,
index: _,
typ: _,
} => {
ir += &format!("%v{}", self.0.index());
}
ValueKind::Constant { value } => {
ir += &format!("{}", value.to_string(ctx));
}
};
ir
}
}