This commit is contained in:
static
2025-06-14 05:07:56 +00:00
parent f4efab6ebf
commit 9a8c8d4a1c

View File

@@ -11,6 +11,7 @@ use crate::{Translate, asm, ir};
pub struct Asmgen { pub struct Asmgen {
functions: Vec<asm::Section<asm::Function>>, functions: Vec<asm::Section<asm::Function>>,
variables: Vec<asm::Section<asm::Variable>>, variables: Vec<asm::Section<asm::Variable>>,
phinode_counter: usize,
} }
impl Default for Asmgen { impl Default for Asmgen {
@@ -18,6 +19,7 @@ impl Default for Asmgen {
Asmgen { Asmgen {
functions: Vec::new(), functions: Vec::new(),
variables: Vec::new(), variables: Vec::new(),
phinode_counter: 0,
} }
} }
} }
@@ -46,18 +48,47 @@ struct Context {
insts: Vec<asm::Instruction>, insts: Vec<asm::Instruction>,
stack_offsets: HashMap<ir::RegisterId, u64>, stack_offsets: HashMap<ir::RegisterId, u64>,
stack_allocation: u64, stack_allocation: u64,
new_blocks: Vec<(asm::Label, Vec<asm::Instruction>)>,
} }
impl Asmgen { impl Asmgen {
fn translate_decl(&mut self, name: &String, decl: &ir::Declaration) { fn translate_decl(&mut self, name: &String, decl: &ir::Declaration) {
match decl { match decl {
ir::Declaration::Variable { dtype, initializer } => todo!(), ir::Declaration::Variable { dtype, initializer } => {
if let Some(initializer) = initializer {
let constant = get_constant_from_initializer(initializer);
let value = match constant {
ir::Constant::Int { value, width, .. } => {
if width == 8 {
asm::Directive::Byte(value as u8)
} else if width == 16 {
asm::Directive::Half(value as u16)
} else if width == 32 {
asm::Directive::Word(value as u32)
} else if width == 64 {
asm::Directive::Quad(value as u64)
} else {
unreachable!()
}
}
_ => todo!(),
};
self.variables.push(asm::Section::new(
vec![
asm::Directive::Globl(asm::Label(name.clone())),
asm::Directive::Section(asm::SectionType::Data),
asm::Directive::Type(asm::Label(name.clone()), asm::SymbolType::Object),
],
asm::Variable::new(asm::Label(name.clone()), vec![value]),
));
}
}
ir::Declaration::Function { ir::Declaration::Function {
signature, signature,
definition, definition,
} => { } => {
if let Some(definition) = definition { if let Some(definition) = definition {
let mut context = self.translate_prologue(definition); let mut context = self.translate_prologue(signature, definition);
self.translate_block( self.translate_block(
name, name,
definition.bid_init, definition.bid_init,
@@ -80,6 +111,10 @@ impl Asmgen {
Some(asm::Label::new(name, *bid)), Some(asm::Label::new(name, *bid)),
context.insts, context.insts,
)); ));
for (label, insts) in std::mem::replace(&mut context.new_blocks, Vec::new())
{
blocks.push(asm::Block::new(Some(label), insts));
}
} }
self.functions.push(asm::Section::new( self.functions.push(asm::Section::new(
@@ -98,11 +133,19 @@ impl Asmgen {
} }
} }
fn translate_prologue(&mut self, definition: &ir::FunctionDefinition) -> Context { fn translate_prologue(
&mut self,
signature: &ir::FunctionSignature,
definition: &ir::FunctionDefinition,
) -> Context {
let mut stack_allocation = 0; let mut stack_allocation = 0;
let mut stack_offsets = HashMap::new(); let mut stack_offsets = HashMap::new();
for (bid, block) in &definition.blocks { for (bid, block) in &definition.blocks {
for (aid, dtype) in block.phinodes.iter().enumerate() {
let _ = stack_offsets.insert(ir::RegisterId::arg(*bid, aid), stack_allocation);
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype));
}
for (iid, inst) in block.instructions.iter().enumerate() { for (iid, inst) in block.instructions.iter().enumerate() {
let _ = stack_offsets.insert(ir::RegisterId::temp(*bid, iid), stack_allocation); let _ = stack_offsets.insert(ir::RegisterId::temp(*bid, iid), stack_allocation);
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(&inst.dtype())); stack_allocation += ceil_to_multiple_of_16(get_dtype_size(&inst.dtype()));
@@ -116,7 +159,11 @@ impl Asmgen {
stack_allocation += 16; // s0, ra stack_allocation += 16; // s0, ra
let insts = vec![ for offset in stack_offsets.values_mut() {
*offset = stack_allocation - *offset;
}
let mut insts = vec![
asm::Instruction::IType { asm::Instruction::IType {
instr: asm::IType::ADDI, instr: asm::IType::ADDI,
rd: asm::Register::Sp, rd: asm::Register::Sp,
@@ -142,10 +189,24 @@ impl Asmgen {
imm: asm::Immediate::Value(!16 + 1), imm: asm::Immediate::Value(!16 + 1),
}, },
]; ];
// TODO: Floating point or optimizations
for (i, dtype) in signature.params.iter().enumerate() {
insts.push(asm::Instruction::SType {
instr: asm::SType::SD,
rs1: asm::Register::S0,
rs2: asm::Register::arg(asm::RegisterType::Integer, i),
imm: asm::Immediate::Value(
stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)],
),
});
}
Context { Context {
insts, insts,
stack_offsets, stack_offsets,
stack_allocation, stack_allocation,
new_blocks: Vec::new(),
} }
} }
@@ -274,7 +335,7 @@ impl Asmgen {
self.translate_load_operand(value, rs2, context); self.translate_load_operand(value, rs2, context);
context.insts.push(asm::Instruction::SType { context.insts.push(asm::Instruction::SType {
instr: asm::SType::store(value_dtype), instr: asm::SType::store(value_dtype),
rs1: asm::Register::Sp, rs1: asm::Register::S0,
rs2, rs2,
imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]),
}); });
@@ -282,34 +343,87 @@ impl Asmgen {
_ => todo!(), _ => todo!(),
} }
} }
ir::Instruction::Load { ptr } => { ir::Instruction::Load { ptr } => match ptr {
let (ptr_rid, ptr_dtype) = ptr.get_register().unwrap(); ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => {
let value_dtype = ptr_dtype.get_pointer_inner().unwrap().clone(); let rd = get_lhs_register(&dtype);
let rd = get_lhs_register(&value_dtype); context
match ptr_rid { .insts
ir::RegisterId::Temp { .. } => { .push(asm::Instruction::Pseudo(asm::Pseudo::La {
let rs1 = get_rhs_register(ptr_dtype); rd: asm::Register::T0,
self.translate_load_operand(ptr, rs1, context); symbol: asm::Label(name.clone()),
context.insts.push(asm::Instruction::IType { }));
instr: asm::IType::load(value_dtype.clone()), context.insts.push(asm::Instruction::IType {
rd, instr: asm::IType::load(dtype.clone()),
rs1, rd,
imm: asm::Immediate::Value(0), rs1: asm::Register::T0,
}); imm: asm::Immediate::Value(0),
self.translate_store_result(&rid, value_dtype, rs1, context); });
} self.translate_store_result(&rid, dtype.clone(), rd, context);
ir::RegisterId::Local { aid } => {
let rs1 = get_lhs_register(ptr_dtype);
context.insts.push(asm::Instruction::IType {
instr: asm::IType::load(value_dtype.clone()),
rd,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]),
});
self.translate_store_result(&rid, value_dtype, rs1, context);
}
_ => todo!(),
} }
ir::Operand::Register {
rid: ptr_rid,
dtype: ptr_dtype,
} => {
let value_dtype = ptr_dtype.get_pointer_inner().unwrap().clone();
let rd = get_lhs_register(&value_dtype);
match ptr_rid {
ir::RegisterId::Temp { .. } => {
let rs1 = get_rhs_register(ptr_dtype);
self.translate_load_operand(ptr, rs1, context);
context.insts.push(asm::Instruction::IType {
instr: asm::IType::load(value_dtype.clone()),
rd,
rs1,
imm: asm::Immediate::Value(0),
});
self.translate_store_result(&rid, value_dtype, rd, context);
}
ir::RegisterId::Local { aid } => {
let rs1 = get_lhs_register(ptr_dtype);
context.insts.push(asm::Instruction::IType {
instr: asm::IType::load(value_dtype.clone()),
rd,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]),
});
self.translate_store_result(&rid, value_dtype, rd, context);
}
_ => todo!(),
}
}
_ => todo!(),
},
ir::Instruction::Call {
callee,
args,
return_type,
} => {
for (i, arg) in args.iter().enumerate() {
// TODO: FloatingPoint
self.translate_load_operand(
arg,
asm::Register::arg(asm::RegisterType::Integer, i),
context,
);
}
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
offset: asm::Label(
callee
.get_constant()
.unwrap()
.get_global_variable_name()
.unwrap(),
),
}));
// TODO
self.translate_store_result(
&rid,
return_type.clone(),
asm::Register::A0,
context,
);
} }
ir::Instruction::TypeCast { ir::Instruction::TypeCast {
value, value,
@@ -326,17 +440,33 @@ impl Asmgen {
match &block.exit { match &block.exit {
ir::BlockExit::Jump { arg } => { ir::BlockExit::Jump { arg } => {
// TODO: Phinode context
context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { .insts
offset: asm::Label::new(name, arg.bid), .append(&mut self.translate_phinode(name, arg, context));
}));
} }
ir::BlockExit::ConditionalJump { ir::BlockExit::ConditionalJump {
condition, condition,
arg_then, arg_then,
arg_else, arg_else,
} => { } => {
// TODO: Phinode let arg_then_label = if arg_then.args.is_empty() {
asm::Label::new(name, arg_then.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg_then, context);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
label
};
let arg_else_label = if arg_else.args.is_empty() {
asm::Label::new(name, arg_else.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg_else, context);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
label
};
let rs1 = get_lhs_register(&condition.dtype()); let rs1 = get_lhs_register(&condition.dtype());
self.translate_load_operand(condition, rs1, context); self.translate_load_operand(condition, rs1, context);
@@ -351,18 +481,26 @@ impl Asmgen {
instr: asm::BType::Bne, instr: asm::BType::Bne,
rs1, rs1,
rs2: asm::Register::Zero, rs2: asm::Register::Zero,
imm: asm::Label::new(name, arg_else.bid), imm: arg_else_label,
}); });
context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J {
offset: asm::Label::new(name, arg_then.bid), offset: arg_then_label,
})); })); // TODO: 최적화 가능?
} }
ir::BlockExit::Switch { ir::BlockExit::Switch {
value, value,
default, default,
cases, cases,
} => { } => {
// TODO: Phinode let default_label = if default.args.is_empty() {
asm::Label::new(name, default.bid)
} else {
let phinode_insts = self.translate_phinode(name, default, context);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
label
};
let rs1 = get_lhs_register(&value.dtype()); let rs1 = get_lhs_register(&value.dtype());
let rs2 = get_rhs_register(&value.dtype()); let rs2 = get_rhs_register(&value.dtype());
@@ -370,17 +508,28 @@ impl Asmgen {
for (case, arg) in cases { for (case, arg) in cases {
self.translate_load_operand(&ir::Operand::constant(case.clone()), rs2, context); self.translate_load_operand(&ir::Operand::constant(case.clone()), rs2, context);
let case_label = if arg.args.is_empty() {
asm::Label::new(name, arg.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg, context);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
label
};
context.insts.push(asm::Instruction::BType { context.insts.push(asm::Instruction::BType {
instr: asm::BType::Beq, instr: asm::BType::Beq,
rs1, rs1,
rs2, rs2,
imm: asm::Label::new(name, arg.bid), imm: case_label,
}); });
} }
context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J {
offset: asm::Label::new(name, default.bid), offset: default_label,
})); })); // TODO: 최적화 가능?
} }
ir::BlockExit::Return { value } => { ir::BlockExit::Return { value } => {
// TODO // TODO
@@ -399,6 +548,9 @@ impl Asmgen {
) { ) {
match operand { match operand {
ir::Operand::Constant(c) => match c { ir::Operand::Constant(c) => match c {
ir::Constant::Undef { dtype } => context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li { rd, imm: 0 })),
ir::Constant::Int { ir::Constant::Int {
value, value,
width, width,
@@ -409,12 +561,15 @@ impl Asmgen {
rd, rd,
imm: *value as u64, imm: *value as u64,
})), })),
_ => todo!(), _ => {
println!("{c}");
todo!()
}
}, },
ir::Operand::Register { rid, dtype } => context.insts.push(asm::Instruction::IType { ir::Operand::Register { rid, dtype } => context.insts.push(asm::Instruction::IType {
instr: asm::IType::load(dtype.clone()), instr: asm::IType::load(dtype.clone()),
rd, rd,
rs1: asm::Register::Sp, rs1: asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[rid]), imm: asm::Immediate::Value(context.stack_offsets[rid]),
}), }),
} }
@@ -429,11 +584,121 @@ impl Asmgen {
) { ) {
context.insts.push(asm::Instruction::SType { context.insts.push(asm::Instruction::SType {
instr: asm::SType::store(dtype), instr: asm::SType::store(dtype),
rs1: asm::Register::Sp, rs1: asm::Register::S0,
rs2: rs, rs2: rs,
imm: asm::Immediate::Value(context.stack_offsets[rid]), imm: asm::Immediate::Value(context.stack_offsets[rid]),
}) })
} }
fn translate_phinode(
&mut self,
name: &String,
arg: &ir::JumpArg,
context: &Context,
) -> Vec<asm::Instruction> {
let mut phinode_stack_offsets = HashMap::new();
let mut phinode_stack_allocations = 0;
for (aid, arg) in arg.args.iter().enumerate() {
let _ = phinode_stack_offsets.insert(aid, phinode_stack_allocations);
phinode_stack_allocations += ceil_to_multiple_of_16(get_dtype_size(&arg.dtype()));
}
let mut phinode_insts = Vec::new();
if phinode_stack_allocations > 0 {
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd: asm::Register::Sp,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(!phinode_stack_allocations + 1),
});
}
let bid = arg.bid;
for (aid, arg) in arg.args.iter().enumerate() {
let rs1 = get_lhs_register(&arg.dtype());
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::load(arg.dtype()),
rd: rs1,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]),
});
phinode_insts.push(asm::Instruction::SType {
instr: asm::SType::store(arg.dtype()),
rs1: asm::Register::Sp,
rs2: rs1,
imm: asm::Immediate::Value(phinode_stack_offsets[&aid]),
});
}
for (aid, arg) in arg.args.iter().enumerate() {
let rs1 = get_lhs_register(&arg.dtype());
match arg {
ir::Operand::Constant(c) => match c {
ir::Constant::Int {
value,
width,
is_signed,
} => phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: rs1,
imm: *value as u64,
})),
_ => todo!(),
},
ir::Operand::Register { rid, .. } => {
if let ir::RegisterId::Arg {
bid: arg_bid,
aid: arg_aid,
} = rid
{
if *arg_bid == bid {
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::load(arg.dtype()),
rd: rs1,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(phinode_stack_offsets[arg_aid]),
});
} else {
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::load(arg.dtype()),
rd: rs1,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[rid]),
});
}
} else {
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::load(arg.dtype()),
rd: rs1,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[rid]),
});
}
}
}
phinode_insts.push(asm::Instruction::SType {
instr: asm::SType::store(arg.dtype()),
rs1: asm::Register::S0,
rs2: rs1,
imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]),
});
}
if phinode_stack_allocations > 0 {
phinode_insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd: asm::Register::Sp,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(phinode_stack_allocations),
});
}
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::J {
offset: asm::Label::new(name, bid),
}));
phinode_insts
}
} }
fn get_lhs_register(dtype: &ir::Dtype) -> asm::Register { fn get_lhs_register(dtype: &ir::Dtype) -> asm::Register {
@@ -494,3 +759,13 @@ fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype {
_ => dtype.clone(), _ => dtype.clone(),
} }
} }
fn get_constant_from_initializer(initializer: &ast::Initializer) -> ir::Constant {
match initializer {
ast::Initializer::Expression(expression) => match &expression.node {
ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(),
_ => panic!(),
},
_ => panic!(),
}
}