forked from NUDT-compiler/nudt-compiler-rust
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
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
|
|
}
|
|
}
|