mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-12 21:18:45 +00:00
HW8 (4)
This commit is contained in:
4
bench/run.sh
Executable file
4
bench/run.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
(make clean && make run) | tail -n 1
|
||||
|
||||
11
compile.sh
Executable file
11
compile.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용법 확인
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <path-to-c-file>"
|
||||
echo "Example: $0 examples/c/unary.c"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cargo run --features=build-bin -- "$1" --optimize --iroutput > "hello.ir"
|
||||
cargo run --features=build-bin -- "$1" --optimize > "hello.S"
|
||||
@@ -43,7 +43,11 @@ struct InferenceGraph {
|
||||
}
|
||||
|
||||
impl InferenceGraph {
|
||||
fn new(code: &ir::FunctionDefinition) -> Self {
|
||||
fn new(
|
||||
code: &ir::FunctionDefinition,
|
||||
signature: &ir::FunctionSignature,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) -> Self {
|
||||
let cfg = make_cfg(code);
|
||||
let reverse_cfg = reverse_cfg(&cfg);
|
||||
let domtree = Domtree::new(code.bid_init, &cfg, &reverse_cfg);
|
||||
@@ -228,10 +232,56 @@ impl InferenceGraph {
|
||||
*num_of_edges.entry(*rid1).or_insert(0) += 1;
|
||||
}
|
||||
|
||||
let (mut num_int_args, mut num_float_args) =
|
||||
get_number_of_register_arguments(&signature.ret, &signature.params, structs);
|
||||
|
||||
'outer: for block in code.blocks.values() {
|
||||
for inst in &block.instructions {
|
||||
if let ir::Instruction::Call {
|
||||
callee,
|
||||
args,
|
||||
return_type,
|
||||
} = inst.deref()
|
||||
{
|
||||
// let (new_num_int_args, new_num_float_args) = get_number_of_register_arguments(
|
||||
// return_type,
|
||||
// &args.iter().map(|operand| operand.dtype()).collect(),
|
||||
// structs,
|
||||
// );
|
||||
// num_int_args = std::cmp::max(num_int_args, new_num_int_args);
|
||||
// num_float_args = std::cmp::max(num_float_args, new_num_float_args);
|
||||
|
||||
num_int_args = 8;
|
||||
num_float_args = 8; // call이 있는 경우 a는 사용 x
|
||||
break 'outer;
|
||||
} else if let ir::Instruction::Store { value, .. } = inst.deref() {
|
||||
if is_struct(&value.dtype(), structs).is_some() {
|
||||
num_int_args = 8;
|
||||
num_float_args = 8;
|
||||
break 'outer;
|
||||
}
|
||||
} else if let ir::Instruction::Load { ptr } = inst.deref() {
|
||||
if is_struct(ptr.dtype().get_pointer_inner().unwrap(), structs).is_some() {
|
||||
num_int_args = 8;
|
||||
num_float_args = 8;
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(size) = is_struct(&signature.ret, structs) {
|
||||
if size > 16 {
|
||||
num_int_args = 8;
|
||||
num_float_args = 8;
|
||||
}
|
||||
}
|
||||
|
||||
let mut vertices_order = vertices
|
||||
.keys()
|
||||
.map(|rid| (*rid, num_of_edges.get(rid).cloned().unwrap_or_default()))
|
||||
.sorted_by(|(_, v1), (_, v2)| v2.cmp(v1));
|
||||
|
||||
for (rid, count) in vertices_order {
|
||||
if count == 0 {
|
||||
continue;
|
||||
@@ -252,44 +302,121 @@ impl InferenceGraph {
|
||||
.iter()
|
||||
.filter_map(|(_, reg)| {
|
||||
// TODO: Saved말고 다른 것도 쓰게?
|
||||
if is_integer(dtype) {
|
||||
if let asm::Register::Saved(asm::RegisterType::Integer, i) = reg {
|
||||
return Some(*i);
|
||||
}
|
||||
if is_integer(dtype)
|
||||
&& matches!(
|
||||
reg,
|
||||
asm::Register::Saved(asm::RegisterType::Integer, _)
|
||||
| asm::Register::Arg(asm::RegisterType::Integer, _)
|
||||
)
|
||||
{
|
||||
return Some(*reg);
|
||||
}
|
||||
if is_float(dtype) {
|
||||
if let asm::Register::Saved(asm::RegisterType::FloatingPoint, i) = reg {
|
||||
return Some(*i);
|
||||
}
|
||||
if is_float(dtype)
|
||||
&& matches!(
|
||||
reg,
|
||||
asm::Register::Saved(asm::RegisterType::FloatingPoint, _)
|
||||
| asm::Register::Arg(asm::RegisterType::FloatingPoint, _)
|
||||
)
|
||||
{
|
||||
return Some(*reg);
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
if is_integer(dtype) {
|
||||
let my_i = smallest_missing_integer(&neighbor_registers, 1); // s0는 못 씀
|
||||
if my_i >= 12 {
|
||||
// TODO: Spilling or 레지스터 쪼개기 필요
|
||||
} else {
|
||||
let smallest_arg_reg = smallest_missing_integer(
|
||||
&neighbor_registers
|
||||
.iter()
|
||||
.filter_map(|reg| {
|
||||
if let asm::Register::Arg(_, i) = reg {
|
||||
Some(*i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
num_int_args as usize,
|
||||
);
|
||||
let smallest_saved_reg = smallest_missing_integer(
|
||||
&neighbor_registers
|
||||
.iter()
|
||||
.filter_map(|reg| {
|
||||
if let asm::Register::Saved(_, i) = reg {
|
||||
Some(*i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
1,
|
||||
); // s0는 못 씀
|
||||
if smallest_arg_reg <= 7 {
|
||||
let _unused = vertices.insert(
|
||||
rid,
|
||||
(
|
||||
dtype.clone(),
|
||||
asm::Register::Saved(asm::RegisterType::Integer, my_i),
|
||||
asm::Register::arg(asm::RegisterType::Integer, smallest_arg_reg),
|
||||
),
|
||||
);
|
||||
} else if smallest_saved_reg <= 11 {
|
||||
let _unused = vertices.insert(
|
||||
rid,
|
||||
(
|
||||
dtype.clone(),
|
||||
asm::Register::saved(asm::RegisterType::Integer, smallest_saved_reg),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Spilling
|
||||
}
|
||||
} else if is_float(dtype) {
|
||||
let my_i = smallest_missing_integer(&neighbor_registers, 0); // s0는 못 씀
|
||||
if my_i >= 12 {
|
||||
// TODO: Spilling or 레지스터 쪼개기 필요
|
||||
} else {
|
||||
let smallest_arg_reg = smallest_missing_integer(
|
||||
&neighbor_registers
|
||||
.iter()
|
||||
.filter_map(|reg| {
|
||||
if let asm::Register::Arg(_, i) = reg {
|
||||
Some(*i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
num_float_args as usize,
|
||||
);
|
||||
let smallest_saved_reg = smallest_missing_integer(
|
||||
&neighbor_registers
|
||||
.iter()
|
||||
.filter_map(|reg| {
|
||||
if let asm::Register::Saved(_, i) = reg {
|
||||
Some(*i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
0,
|
||||
);
|
||||
if smallest_arg_reg <= 7 {
|
||||
let _unused = vertices.insert(
|
||||
rid,
|
||||
(
|
||||
dtype.clone(),
|
||||
asm::Register::Saved(asm::RegisterType::FloatingPoint, my_i),
|
||||
asm::Register::arg(asm::RegisterType::FloatingPoint, smallest_arg_reg),
|
||||
),
|
||||
);
|
||||
} else if smallest_saved_reg <= 11 {
|
||||
let _unused = vertices.insert(
|
||||
rid,
|
||||
(
|
||||
dtype.clone(),
|
||||
asm::Register::saved(
|
||||
asm::RegisterType::FloatingPoint,
|
||||
smallest_saved_reg,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Spilling
|
||||
}
|
||||
} else {
|
||||
// TODO: Spilling or 레지스터 쪼개기 필요
|
||||
@@ -402,7 +529,7 @@ impl Asmgen {
|
||||
definition,
|
||||
} => {
|
||||
if let Some(definition) = definition {
|
||||
let graph = InferenceGraph::new(definition);
|
||||
let graph = InferenceGraph::new(definition, signature, structs);
|
||||
|
||||
// println!("asdf: {:?}", graph.vertices);
|
||||
|
||||
@@ -487,7 +614,7 @@ impl Asmgen {
|
||||
|
||||
stack_allocation += 24; // s0, ra, a0
|
||||
|
||||
let num_int_regs = inference_graph
|
||||
let num_int_saved_regs = inference_graph
|
||||
.vertices
|
||||
.values()
|
||||
.filter_map(|(_, reg)| {
|
||||
@@ -499,7 +626,7 @@ impl Asmgen {
|
||||
})
|
||||
.collect::<HashSet<_>>()
|
||||
.len();
|
||||
let num_float_regs = inference_graph
|
||||
let num_float_saved_regs = inference_graph
|
||||
.vertices
|
||||
.values()
|
||||
.filter_map(|(_, reg)| {
|
||||
@@ -511,7 +638,7 @@ impl Asmgen {
|
||||
})
|
||||
.collect::<HashSet<_>>()
|
||||
.len();
|
||||
stack_allocation += ((num_int_regs + num_float_regs) * 8) as u64;
|
||||
stack_allocation += ((num_int_saved_regs + num_float_saved_regs) * 8) as u64;
|
||||
|
||||
if stack_allocation % 16 != 0 {
|
||||
// 스택은 16바이트 정렬
|
||||
@@ -556,7 +683,7 @@ impl Asmgen {
|
||||
});
|
||||
|
||||
// S1~레지스터 및 FS0~ 레지스터 백업
|
||||
for i in 0..num_int_regs {
|
||||
for i in 0..num_int_saved_regs {
|
||||
insts.push(asm::Instruction::SType {
|
||||
instr: asm::SType::SD,
|
||||
rs1: asm::Register::S0,
|
||||
@@ -567,12 +694,12 @@ impl Asmgen {
|
||||
imm: asm::Immediate::Value((!(32 + i * 8) + 1) as u64),
|
||||
});
|
||||
}
|
||||
for i in 0..num_float_regs {
|
||||
for i in 0..num_float_saved_regs {
|
||||
insts.push(asm::Instruction::SType {
|
||||
instr: asm::SType::store(ir::Dtype::DOUBLE),
|
||||
rs1: asm::Register::S0,
|
||||
rs2: asm::Register::saved(asm::RegisterType::FloatingPoint, i),
|
||||
imm: asm::Immediate::Value((!(32 + num_int_regs * 8 + i * 8) + 1) as u64),
|
||||
imm: asm::Immediate::Value((!(32 + num_int_saved_regs * 8 + i * 8) + 1) as u64),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -729,80 +856,82 @@ impl Asmgen {
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
});
|
||||
if !large_struct.is_empty() {
|
||||
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() {
|
||||
if let Some(size) = is_struct(dtype, structs) {
|
||||
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
|
||||
if size > 16 {
|
||||
let reg_index = large_struct[&i];
|
||||
for (i, dtype) in signature.params.iter().enumerate() {
|
||||
if let Some(size) = is_struct(dtype, structs) {
|
||||
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
|
||||
if size > 16 {
|
||||
let reg_index = large_struct[&i];
|
||||
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
stack_offset,
|
||||
&mut insts,
|
||||
);
|
||||
self.translate_addi(
|
||||
asm::Register::A0,
|
||||
asm::Register::S0,
|
||||
stack_offset,
|
||||
&mut insts,
|
||||
);
|
||||
|
||||
match reg_index {
|
||||
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, reg_index),
|
||||
})),
|
||||
match reg_index {
|
||||
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, reg_index),
|
||||
})),
|
||||
}
|
||||
|
||||
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")),
|
||||
}));
|
||||
}
|
||||
|
||||
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")),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd: asm::Register::Sp,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(16),
|
||||
});
|
||||
insts.push(asm::Instruction::IType {
|
||||
instr: asm::IType::ADDI,
|
||||
rd: asm::Register::Sp,
|
||||
rs1: asm::Register::Sp,
|
||||
imm: asm::Immediate::Value(16),
|
||||
});
|
||||
}
|
||||
|
||||
Context {
|
||||
insts,
|
||||
@@ -2012,11 +2141,6 @@ impl Asmgen {
|
||||
}
|
||||
ir::Operand::Register { rid: ptr_rid, .. } => match ptr_rid {
|
||||
ir::RegisterId::Local { aid } => {
|
||||
let rs2 = self.translate_load_operand(
|
||||
offset,
|
||||
get_rhs_register(&offset_dtype),
|
||||
context,
|
||||
);
|
||||
let rd = rd.unwrap_or(get_res_register(&ptr_dtype));
|
||||
self.translate_addi(
|
||||
rd,
|
||||
@@ -2040,11 +2164,6 @@ impl Asmgen {
|
||||
get_lhs_register(&ptr_dtype),
|
||||
context,
|
||||
);
|
||||
let rs2 = self.translate_load_operand(
|
||||
offset,
|
||||
get_rhs_register(&offset_dtype),
|
||||
context,
|
||||
);
|
||||
let rd = rd.unwrap_or(get_res_register(&ptr_dtype));
|
||||
context.insts.push(asm::Instruction::RType {
|
||||
instr: asm::RType::add(ptr_dtype.clone()),
|
||||
@@ -2794,3 +2913,76 @@ fn get_struct_dtype<'a>(
|
||||
let fields = struct_dtype.get_struct_fields().unwrap().as_ref().unwrap();
|
||||
(struct_dtype, fields)
|
||||
}
|
||||
|
||||
fn get_number_of_register_arguments(
|
||||
return_type: &ir::Dtype,
|
||||
params: &Vec<ir::Dtype>,
|
||||
structs: &HashMap<String, Option<ir::Dtype>>,
|
||||
) -> (i32, i32) {
|
||||
let mut num_int_args = 0;
|
||||
let mut num_float_args = 0;
|
||||
|
||||
if is_struct(return_type, structs).is_some_and(|size| size > 16) {
|
||||
num_int_args += 1;
|
||||
}
|
||||
|
||||
for dtype in params {
|
||||
if is_integer(dtype) {
|
||||
num_int_args += 1;
|
||||
} else if is_float(dtype) {
|
||||
num_float_args += 1;
|
||||
} else if let Some(size) = is_struct(dtype, structs) {
|
||||
if size > 16 {
|
||||
num_int_args += 1;
|
||||
} else {
|
||||
let (struct_dtype, fields) = get_struct_dtype(dtype, structs);
|
||||
let mut is_packing = false;
|
||||
let mut packing_start_offset = 0;
|
||||
let mut packing_size = 0;
|
||||
|
||||
for field_dtype in fields {
|
||||
let (offset, _) = struct_dtype
|
||||
.get_offset_struct_field(field_dtype.name().unwrap(), structs)
|
||||
.unwrap();
|
||||
let field_size = get_dtype_size(field_dtype, structs);
|
||||
if is_integer(field_dtype) {
|
||||
if !is_packing {
|
||||
is_packing = true;
|
||||
packing_start_offset = offset;
|
||||
packing_size = field_size;
|
||||
} else if offset == packing_start_offset + (packing_size as usize)
|
||||
&& packing_size + field_size <= 8
|
||||
{
|
||||
packing_size += field_size;
|
||||
} else {
|
||||
num_int_args += 1;
|
||||
packing_start_offset = offset;
|
||||
packing_size = field_size;
|
||||
}
|
||||
} else if is_float(field_dtype) {
|
||||
if is_packing {
|
||||
num_int_args += 1;
|
||||
is_packing = false;
|
||||
}
|
||||
|
||||
num_float_args += 1;
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
if is_packing {
|
||||
num_int_args += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if num_int_args == 0 && is_integer(return_type) {
|
||||
num_int_args = 1;
|
||||
} else if num_float_args == 0 && is_float(return_type) {
|
||||
num_float_args = 1;
|
||||
}
|
||||
|
||||
(num_int_args, num_float_args)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user