mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-15 15:08:52 +00:00
HW7 (4)
This commit is contained in:
@@ -21,7 +21,7 @@ impl Translate<ir::TranslationUnit> for Asmgen {
|
||||
|
||||
fn translate(&mut self, source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
|
||||
for (name, decl) in &source.decls {
|
||||
self.translate_decl(name, decl);
|
||||
self.translate_decl(name, decl, &source.structs);
|
||||
}
|
||||
|
||||
// println!("{:?}", self.functions);
|
||||
@@ -43,43 +43,31 @@ struct Context {
|
||||
}
|
||||
|
||||
impl Asmgen {
|
||||
fn translate_decl(&mut self, name: &String, decl: &ir::Declaration) {
|
||||
fn translate_decl(
|
||||
&mut self,
|
||||
name: &String,
|
||||
decl: &ir::Declaration,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) {
|
||||
match decl {
|
||||
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!()
|
||||
let mut directives = initializer_to_directives(initializer);
|
||||
if let ir::Dtype::Array { inner, size } = dtype {
|
||||
if *size != directives.len() {
|
||||
directives.push(asm::Directive::Zero(
|
||||
(size - directives.len())
|
||||
* (get_dtype_size(&inner, structs) as usize),
|
||||
));
|
||||
}
|
||||
}
|
||||
ir::Constant::Float { value, width } => {
|
||||
if width == 32 {
|
||||
asm::Directive::Word((*value as f32).to_bits())
|
||||
} else if width == 64 {
|
||||
asm::Directive::Quad(value.to_bits())
|
||||
} 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]),
|
||||
asm::Variable::new(asm::Label(name.clone()), directives),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -88,12 +76,13 @@ impl Asmgen {
|
||||
definition,
|
||||
} => {
|
||||
if let Some(definition) = definition {
|
||||
let mut context = self.translate_prologue(signature, definition);
|
||||
let mut context = self.translate_prologue(signature, definition, structs);
|
||||
self.translate_block(
|
||||
name,
|
||||
definition.bid_init,
|
||||
&definition.blocks[&definition.bid_init],
|
||||
&mut context,
|
||||
structs,
|
||||
);
|
||||
let mut blocks = vec![asm::Block::new(
|
||||
Some(asm::Label(name.clone())),
|
||||
@@ -106,7 +95,7 @@ impl Asmgen {
|
||||
}
|
||||
|
||||
context.insts = Vec::new();
|
||||
self.translate_block(name, *bid, block, &mut context);
|
||||
self.translate_block(name, *bid, block, &mut context, structs);
|
||||
blocks.push(asm::Block::new(
|
||||
Some(asm::Label::new(name, *bid)),
|
||||
context.insts,
|
||||
@@ -136,6 +125,7 @@ impl Asmgen {
|
||||
&mut self,
|
||||
signature: &ir::FunctionSignature,
|
||||
definition: &ir::FunctionDefinition,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) -> Context {
|
||||
let mut stack_allocation = 0;
|
||||
let mut stack_offsets = HashMap::new();
|
||||
@@ -143,20 +133,20 @@ impl Asmgen {
|
||||
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));
|
||||
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype, structs));
|
||||
}
|
||||
for (iid, inst) in block.instructions.iter().enumerate() {
|
||||
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(), structs));
|
||||
}
|
||||
}
|
||||
|
||||
for (aid, dtype) in definition.allocations.iter().enumerate() {
|
||||
let _ = stack_offsets.insert(ir::RegisterId::local(aid), stack_allocation);
|
||||
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype));
|
||||
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype, structs));
|
||||
}
|
||||
|
||||
stack_allocation += 16; // s0, ra
|
||||
stack_allocation += 32; // s0, ra, a0, (padding)
|
||||
|
||||
for offset in stack_offsets.values_mut() {
|
||||
*offset = offset.wrapping_sub(stack_allocation);
|
||||
@@ -188,17 +178,114 @@ impl Asmgen {
|
||||
rs2: asm::Register::Ra,
|
||||
imm: asm::Immediate::Value(!16 + 1),
|
||||
});
|
||||
insts.push(asm::Instruction::SType {
|
||||
instr: asm::SType::SD,
|
||||
rs1: asm::Register::S0,
|
||||
rs2: asm::Register::A0,
|
||||
imm: asm::Immediate::Value(!24 + 1),
|
||||
});
|
||||
|
||||
let mut num_int_args = 0;
|
||||
let mut num_float_args = 0;
|
||||
|
||||
if is_struct(&signature.ret, structs).is_some() {
|
||||
num_int_args += 1;
|
||||
}
|
||||
|
||||
// TODO: Floating point or optimizations
|
||||
for (i, dtype) in signature.params.iter().enumerate() {
|
||||
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
|
||||
if is_integer(dtype) {
|
||||
self.translate_store(
|
||||
asm::SType::SD,
|
||||
asm::Register::S0,
|
||||
asm::Register::arg(asm::RegisterType::Integer, i),
|
||||
stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)],
|
||||
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
|
||||
stack_offset,
|
||||
&mut insts,
|
||||
);
|
||||
num_int_args += 1;
|
||||
} else if is_float(dtype) {
|
||||
self.translate_store(
|
||||
asm::SType::store(dtype.clone()),
|
||||
asm::Register::S0,
|
||||
asm::Register::arg(asm::RegisterType::FloatingPoint, num_float_args),
|
||||
stack_offset,
|
||||
&mut insts,
|
||||
);
|
||||
num_float_args += 1;
|
||||
}
|
||||
}
|
||||
|
||||
insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd: asm::Register::Sp,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(!16 + 1),
|
||||
});
|
||||
insts.push(asm::Instruction::SType {
|
||||
instr: asm::SType::SD,
|
||||
rs1: asm::Register::Sp,
|
||||
rs2: asm::Register::A1,
|
||||
imm: asm::Immediate::Value(0),
|
||||
});
|
||||
insts.push(asm::Instruction::SType {
|
||||
instr: asm::SType::SD,
|
||||
rs1: asm::Register::Sp,
|
||||
rs2: asm::Register::A2,
|
||||
imm: asm::Immediate::Value(8),
|
||||
});
|
||||
|
||||
for (i, dtype) in signature.params.iter().enumerate() {
|
||||
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
|
||||
if let Some(size) = is_struct(dtype, structs) {
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
stack_offset,
|
||||
&mut insts,
|
||||
);
|
||||
|
||||
match i {
|
||||
0 => insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::LD,
|
||||
rd: asm::Register::A1,
|
||||
rs1: asm::Register::S0,
|
||||
imm: asm::Immediate::Value(!24 + 1),
|
||||
}),
|
||||
1 => insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::LD,
|
||||
rd: asm::Register::A1,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(0),
|
||||
}),
|
||||
2 => insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::LD,
|
||||
rd: asm::Register::A1,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(8),
|
||||
}),
|
||||
_ => insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
|
||||
rd: asm::Register::A1,
|
||||
rs: asm::Register::arg(asm::RegisterType::Integer, i),
|
||||
})),
|
||||
}
|
||||
|
||||
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
}));
|
||||
num_int_args += 1;
|
||||
}
|
||||
}
|
||||
|
||||
insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd: asm::Register::Sp,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(16),
|
||||
});
|
||||
|
||||
Context {
|
||||
insts,
|
||||
@@ -239,6 +326,7 @@ impl Asmgen {
|
||||
bid: ir::BlockId,
|
||||
block: &ir::Block,
|
||||
context: &mut Context,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) {
|
||||
for (iid, inst) in block.instructions.iter().enumerate() {
|
||||
let rid = ir::RegisterId::temp(bid, iid);
|
||||
@@ -355,7 +443,7 @@ impl Asmgen {
|
||||
});
|
||||
}
|
||||
ast::BinaryOperator::Less => {
|
||||
// TODO: FLoating point
|
||||
if is_integer(&operand_dtype) {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::Slt {
|
||||
is_signed: operand_dtype.is_int_signed(),
|
||||
@@ -364,9 +452,17 @@ impl Asmgen {
|
||||
rs1,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
} else {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::flt(operand_dtype),
|
||||
rd,
|
||||
rs1,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::Greater => {
|
||||
// TODO: FLoating point
|
||||
if is_integer(&operand_dtype) {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::Slt {
|
||||
is_signed: operand_dtype.is_int_signed(),
|
||||
@@ -375,9 +471,17 @@ impl Asmgen {
|
||||
rs1: rs2,
|
||||
rs2: Some(rs1),
|
||||
});
|
||||
} else {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::flt(operand_dtype),
|
||||
rd,
|
||||
rs1: rs2,
|
||||
rs2: Some(rs1),
|
||||
});
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::LessOrEqual => {
|
||||
// TODO: FLoating point
|
||||
if is_integer(&operand_dtype) {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::Slt {
|
||||
is_signed: operand_dtype.is_int_signed(),
|
||||
@@ -386,12 +490,20 @@ impl Asmgen {
|
||||
rs1: rs2,
|
||||
rs2: Some(rs1),
|
||||
});
|
||||
} else {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::flt(operand_dtype),
|
||||
rd,
|
||||
rs1: rs2,
|
||||
rs2: Some(rs1),
|
||||
});
|
||||
}
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
|
||||
}
|
||||
ast::BinaryOperator::GreaterOrEqual => {
|
||||
// TODO: FLoating point
|
||||
if is_integer(&operand_dtype) {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::Slt {
|
||||
is_signed: operand_dtype.is_int_signed(),
|
||||
@@ -400,6 +512,14 @@ impl Asmgen {
|
||||
rs1,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
} else {
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::flt(operand_dtype),
|
||||
rd,
|
||||
rs1,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
}
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
|
||||
@@ -491,6 +611,33 @@ impl Asmgen {
|
||||
dtype: ptr_dtype,
|
||||
} => match ptr_rid {
|
||||
ir::RegisterId::Temp { .. } => {
|
||||
if let Some(size) = is_struct(&value_dtype, structs) {
|
||||
let rs1 = get_lhs_register(ptr_dtype);
|
||||
self.translate_load_operand(ptr, rs1, context);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
|
||||
rd: asm::Register::A0,
|
||||
rs: rs1,
|
||||
}));
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[value.get_register().unwrap().0],
|
||||
&mut context.insts,
|
||||
);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context.insts.push(asm::Instruction::Pseudo(
|
||||
asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
},
|
||||
));
|
||||
} else {
|
||||
let rs1 = get_lhs_register(ptr_dtype);
|
||||
let rs2 = get_rhs_register(&value_dtype);
|
||||
self.translate_load_operand(ptr, rs1, context);
|
||||
@@ -502,7 +649,33 @@ impl Asmgen {
|
||||
imm: asm::Immediate::Value(0),
|
||||
});
|
||||
}
|
||||
}
|
||||
ir::RegisterId::Local { aid } => {
|
||||
if let Some(size) = is_struct(&value_dtype, structs) {
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[ptr_rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[value.get_register().unwrap().0],
|
||||
&mut context.insts,
|
||||
);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context.insts.push(asm::Instruction::Pseudo(
|
||||
asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
},
|
||||
));
|
||||
} else {
|
||||
let rs2 = get_rhs_register(&value_dtype);
|
||||
self.translate_load_operand(value, rs2, context);
|
||||
self.translate_store(
|
||||
@@ -513,6 +686,7 @@ impl Asmgen {
|
||||
&mut context.insts,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
@@ -540,6 +714,63 @@ impl Asmgen {
|
||||
dtype: ptr_dtype,
|
||||
} => {
|
||||
let value_dtype = ptr_dtype.get_pointer_inner().unwrap().clone();
|
||||
if let Some(size) = is_struct(&value_dtype, structs) {
|
||||
match ptr_rid {
|
||||
ir::RegisterId::Temp { .. } => {
|
||||
let rs1 = get_rhs_register(ptr_dtype);
|
||||
self.translate_load_operand(ptr, rs1, context);
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[&rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
|
||||
rd: asm::Register::A1,
|
||||
rs: rs1,
|
||||
}));
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context.insts.push(asm::Instruction::Pseudo(
|
||||
asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
},
|
||||
));
|
||||
}
|
||||
ir::RegisterId::Local { aid } => {
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[&rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[ptr_rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context.insts.push(asm::Instruction::Pseudo(
|
||||
asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
},
|
||||
));
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
} else {
|
||||
let rd = get_lhs_register(&value_dtype);
|
||||
match ptr_rid {
|
||||
ir::RegisterId::Temp { .. } => {
|
||||
@@ -567,6 +798,7 @@ impl Asmgen {
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
ir::Instruction::Call {
|
||||
@@ -574,13 +806,109 @@ impl Asmgen {
|
||||
args,
|
||||
return_type,
|
||||
} => {
|
||||
let mut num_int_args = 0;
|
||||
let mut num_float_args = 0;
|
||||
let mut struct_stack_allocations = 0;
|
||||
let mut struct_stack_offsets = HashMap::new();
|
||||
|
||||
// 구조체 반환을 위한 공간 예약
|
||||
if let Some(size) = is_struct(return_type, structs) {
|
||||
num_int_args += 1;
|
||||
struct_stack_allocations += ceil_to_multiple_of_16(size);
|
||||
}
|
||||
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
// TODO: FloatingPoint
|
||||
if let Some(size) = is_struct(&arg.dtype(), structs) {
|
||||
let _ = struct_stack_offsets.insert(i, struct_stack_allocations);
|
||||
struct_stack_allocations += ceil_to_multiple_of_16(size);
|
||||
}
|
||||
}
|
||||
|
||||
if struct_stack_allocations > 0 {
|
||||
self.translate_addi(
|
||||
asm::Register::Sp,
|
||||
asm::Register::Sp,
|
||||
!struct_stack_allocations + 1,
|
||||
&mut context.insts,
|
||||
);
|
||||
}
|
||||
|
||||
// 구조체 인수 복사
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if let Some(size) = is_struct(&arg.dtype(), structs) {
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::Sp,
|
||||
struct_stack_offsets[&i],
|
||||
&mut context.insts,
|
||||
);
|
||||
match arg {
|
||||
ir::Operand::Register { rid, .. } => match rid {
|
||||
ir::RegisterId::Temp { bid, iid } => {
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let dtype = arg.dtype();
|
||||
if is_integer(&dtype) {
|
||||
self.translate_load_operand(
|
||||
arg,
|
||||
asm::Register::arg(asm::RegisterType::Integer, i),
|
||||
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
|
||||
context,
|
||||
);
|
||||
num_int_args += 1;
|
||||
} else if is_float(&dtype) {
|
||||
self.translate_load_operand(
|
||||
arg,
|
||||
asm::Register::arg(
|
||||
asm::RegisterType::FloatingPoint,
|
||||
num_float_args,
|
||||
),
|
||||
context,
|
||||
);
|
||||
num_float_args += 1;
|
||||
} else if let Some(size) = is_struct(&dtype, structs) {
|
||||
self.translate_addi(
|
||||
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
|
||||
asm::Register::Sp,
|
||||
struct_stack_offsets[&i],
|
||||
&mut context.insts,
|
||||
);
|
||||
num_int_args += 1;
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
if is_struct(return_type, structs).is_some() {
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
|
||||
rd: asm::Register::A0,
|
||||
rs: asm::Register::Sp,
|
||||
})); // For returned structure
|
||||
}
|
||||
|
||||
match callee {
|
||||
@@ -616,6 +944,39 @@ impl Asmgen {
|
||||
asm::Register::FA0,
|
||||
context,
|
||||
);
|
||||
} else if let Some(size) = is_struct(return_type, structs) {
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[&rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::Sp,
|
||||
0,
|
||||
&mut context.insts,
|
||||
);
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
}));
|
||||
}
|
||||
|
||||
if struct_stack_allocations > 0 {
|
||||
context.insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd: asm::Register::Sp,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(struct_stack_allocations),
|
||||
});
|
||||
}
|
||||
}
|
||||
ir::Instruction::TypeCast {
|
||||
@@ -672,6 +1033,102 @@ impl Asmgen {
|
||||
}
|
||||
}
|
||||
ir::Instruction::Nop => (),
|
||||
ir::Instruction::GetElementPtr { ptr, offset, .. } => {
|
||||
let offset_dtype = offset.dtype();
|
||||
let rs2 = get_rhs_register(&offset_dtype);
|
||||
self.translate_load_operand(offset, rs2, context);
|
||||
match ptr {
|
||||
ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => {
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::La {
|
||||
rd: asm::Register::T0,
|
||||
symbol: asm::Label(name.clone()),
|
||||
}));
|
||||
let rd = get_lhs_register(&ptr.dtype());
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ptr.dtype()),
|
||||
rd,
|
||||
rs1: asm::Register::T0,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
self.translate_store_result(&rid, ptr.dtype(), rd, context);
|
||||
}
|
||||
ir::Operand::Register {
|
||||
rid: ptr_rid,
|
||||
dtype: ptr_dtype,
|
||||
} => match ptr_rid {
|
||||
ir::RegisterId::Temp { .. } => {
|
||||
let rs1 = get_lhs_register(ptr_dtype);
|
||||
let rs2 = get_rhs_register(&offset_dtype);
|
||||
self.translate_load_operand(ptr, rs1, context);
|
||||
self.translate_load_operand(offset, rs2, context);
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ptr_dtype.clone()),
|
||||
rd: rs1,
|
||||
rs1,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
self.translate_store_result(&rid, ptr.dtype(), rs1, context);
|
||||
}
|
||||
ir::RegisterId::Local { aid } => {
|
||||
let rd = get_lhs_register(&ptr.dtype());
|
||||
let rs2 = get_rhs_register(&offset_dtype);
|
||||
self.translate_load_operand(offset, rs2, context);
|
||||
|
||||
let stack_offset = context.stack_offsets[ptr_rid];
|
||||
let imm_signed = stack_offset as i64;
|
||||
if (-2048..=2047).contains(&imm_signed) {
|
||||
context.insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd,
|
||||
rs1: asm::Register::S0,
|
||||
imm: asm::Immediate::Value(stack_offset),
|
||||
});
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ptr_dtype.clone()),
|
||||
rd,
|
||||
rs1: rd,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
self.translate_store_result(
|
||||
&rid,
|
||||
ptr_dtype.clone(),
|
||||
rd,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::T3,
|
||||
imm: stack_offset,
|
||||
}));
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ir::Dtype::int(64)),
|
||||
rd: asm::Register::T3,
|
||||
rs1: asm::Register::S0,
|
||||
rs2: Some(asm::Register::T3),
|
||||
});
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ptr_dtype.clone()),
|
||||
rd,
|
||||
rs1: rd,
|
||||
rs2: Some(rs2),
|
||||
});
|
||||
self.translate_store_result(
|
||||
&rid,
|
||||
ptr_dtype.clone(),
|
||||
rd,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@@ -680,7 +1137,7 @@ impl Asmgen {
|
||||
ir::BlockExit::Jump { arg } => {
|
||||
context
|
||||
.insts
|
||||
.append(&mut self.translate_phinode(name, arg, context));
|
||||
.append(&mut self.translate_phinode(name, arg, context, structs));
|
||||
}
|
||||
ir::BlockExit::ConditionalJump {
|
||||
condition,
|
||||
@@ -690,7 +1147,7 @@ impl Asmgen {
|
||||
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 phinode_insts = self.translate_phinode(name, arg_then, context, structs);
|
||||
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
|
||||
self.phinode_counter += 1;
|
||||
context.new_blocks.push((label.clone(), phinode_insts));
|
||||
@@ -699,7 +1156,7 @@ impl Asmgen {
|
||||
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 phinode_insts = self.translate_phinode(name, arg_else, context, structs);
|
||||
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
|
||||
self.phinode_counter += 1;
|
||||
context.new_blocks.push((label.clone(), phinode_insts));
|
||||
@@ -733,7 +1190,7 @@ impl Asmgen {
|
||||
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 phinode_insts = self.translate_phinode(name, default, context, structs);
|
||||
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
|
||||
self.phinode_counter += 1;
|
||||
context.new_blocks.push((label.clone(), phinode_insts));
|
||||
@@ -750,7 +1207,7 @@ impl Asmgen {
|
||||
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 phinode_insts = self.translate_phinode(name, arg, context, structs);
|
||||
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
|
||||
self.phinode_counter += 1;
|
||||
context.new_blocks.push((label.clone(), phinode_insts));
|
||||
@@ -771,10 +1228,47 @@ impl Asmgen {
|
||||
}
|
||||
ir::BlockExit::Return { value } => {
|
||||
// TODO
|
||||
if is_integer(&value.dtype()) {
|
||||
let dtype = value.dtype();
|
||||
if is_integer(&dtype) {
|
||||
self.translate_load_operand(value, asm::Register::A0, context);
|
||||
} else if is_float(&value.dtype()) {
|
||||
} else if is_float(&dtype) {
|
||||
self.translate_load_operand(value, asm::Register::FA0, context);
|
||||
} else if let Some(size) = is_struct(&dtype, structs) {
|
||||
context.insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::load(ir::Dtype::pointer(ir::Dtype::unit())), // TODO: ok?
|
||||
rd: asm::Register::A0,
|
||||
rs1: asm::Register::S0,
|
||||
imm: asm::Immediate::Value(!24 + 1),
|
||||
});
|
||||
match value {
|
||||
ir::Operand::Constant(constant) => match constant {
|
||||
ir::Constant::Undef { .. } => (), // DO nothing
|
||||
_ => todo!(),
|
||||
},
|
||||
ir::Operand::Register { rid, .. } => match rid {
|
||||
ir::RegisterId::Temp { bid, iid } => {
|
||||
self.translate_addi(
|
||||
asm::Register::A1,
|
||||
asm::Register::S0,
|
||||
context.stack_offsets[rid],
|
||||
&mut context.insts,
|
||||
);
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
|
||||
rd: asm::Register::A2,
|
||||
imm: size,
|
||||
}));
|
||||
context
|
||||
.insts
|
||||
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
|
||||
offset: asm::Label(String::from("memcpy")),
|
||||
}));
|
||||
}
|
||||
self.translate_epilogue(context);
|
||||
}
|
||||
@@ -889,13 +1383,15 @@ impl Asmgen {
|
||||
name: &str,
|
||||
arg: &ir::JumpArg,
|
||||
context: &Context,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) -> 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()));
|
||||
phinode_stack_allocations +=
|
||||
ceil_to_multiple_of_16(get_dtype_size(&arg.dtype(), structs));
|
||||
}
|
||||
|
||||
let mut phinode_insts = Vec::new();
|
||||
@@ -1131,14 +1627,9 @@ fn ceil_to_multiple_of_16(x: u64) -> u64 {
|
||||
(x + 15) & !15
|
||||
}
|
||||
|
||||
fn get_dtype_size(dtype: &ir::Dtype) -> u64 {
|
||||
((match dtype {
|
||||
ir::Dtype::Unit { .. } => 0,
|
||||
ir::Dtype::Int { width, .. } => std::cmp::max(8, *width),
|
||||
ir::Dtype::Float { width, .. } => *width,
|
||||
ir::Dtype::Pointer { .. } => 64,
|
||||
_ => todo!(),
|
||||
}) / 8) as u64
|
||||
fn get_dtype_size(dtype: &ir::Dtype, structs: &HashMap<String, Option<ir::Dtype>>) -> u64 {
|
||||
let (size, _) = dtype.size_align_of(structs).unwrap();
|
||||
return size as u64;
|
||||
}
|
||||
|
||||
fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype {
|
||||
@@ -1162,6 +1653,65 @@ fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype {
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_to_directive(constant: ir::Constant) -> asm::Directive {
|
||||
match constant {
|
||||
ir::Constant::Int { value, width, .. } => match width {
|
||||
8 => asm::Directive::Byte(value as u8),
|
||||
16 => asm::Directive::Half(value as u16),
|
||||
32 => asm::Directive::Word(value as u32),
|
||||
64 => asm::Directive::Quad(value as u64),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
ir::Constant::Float { value, width } => match width {
|
||||
32 => asm::Directive::Word((*value as f32).to_bits()),
|
||||
64 => asm::Directive::Quad(value.to_bits()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn expression_to_constant(expression: &ast::Expression) -> ir::Constant {
|
||||
match expression {
|
||||
ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(),
|
||||
ast::Expression::UnaryOperator(unary_op) => {
|
||||
let operand = expression_to_constant(&unary_op.node.operand.node);
|
||||
match unary_op.node.operator.node {
|
||||
ast::UnaryOperator::Minus => match operand {
|
||||
ir::Constant::Int {
|
||||
value,
|
||||
width,
|
||||
is_signed,
|
||||
} => ir::Constant::Int {
|
||||
value: !value + 1,
|
||||
width,
|
||||
is_signed,
|
||||
},
|
||||
ir::Constant::Float { value, width } => ir::Constant::Float {
|
||||
value: -value,
|
||||
width,
|
||||
},
|
||||
_ => panic!(),
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn initializer_to_directives(initializer: &ast::Initializer) -> Vec<asm::Directive> {
|
||||
match initializer {
|
||||
ast::Initializer::Expression(expression) => vec![constant_to_directive(
|
||||
expression_to_constant(&expression.node),
|
||||
)],
|
||||
ast::Initializer::List(list) => list
|
||||
.iter()
|
||||
.flat_map(|item| initializer_to_directives(&item.node.initializer.node))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_constant_from_initializer(initializer: &ast::Initializer) -> ir::Constant {
|
||||
match initializer {
|
||||
ast::Initializer::Expression(expression) => match &expression.node {
|
||||
@@ -1206,3 +1756,12 @@ fn is_integer(dtype: &ir::Dtype) -> bool {
|
||||
fn is_float(dtype: &ir::Dtype) -> bool {
|
||||
matches!(dtype, ir::Dtype::Float { .. })
|
||||
}
|
||||
|
||||
fn is_struct(dtype: &ir::Dtype, structs: &HashMap<String, Option<ir::Dtype>>) -> Option<u64> {
|
||||
if matches!(dtype, ir::Dtype::Struct { .. }) {
|
||||
let (size, _) = dtype.size_align_of(structs).unwrap();
|
||||
Some(size as u64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user