This commit is contained in:
static
2025-06-17 22:51:58 +00:00
parent 982cd19af0
commit 58102acee3

View File

@@ -40,8 +40,8 @@ impl Translate<ir::TranslationUnit> for Asmgen {
struct InferenceGraph { struct InferenceGraph {
edges: HashSet<(ir::RegisterId, ir::RegisterId)>, edges: HashSet<(ir::RegisterId, ir::RegisterId)>,
vertices: HashMap<ir::RegisterId, (ir::Dtype, asm::Register)>, vertices: HashMap<ir::RegisterId, (ir::Dtype, asm::Register)>,
has_call: bool, analysis: Analysis,
is_a0_return_pointer: bool, lives: HashMap<ir::RegisterId, HashSet<ir::RegisterId>>,
} }
impl InferenceGraph { impl InferenceGraph {
@@ -192,6 +192,16 @@ impl InferenceGraph {
.or_insert_with(HashSet::new), .or_insert_with(HashSet::new),
uses, uses,
) || changed; ) || changed;
let phinodes = (0..block.phinodes.len())
.map(|i| ir::RegisterId::arg(*bid, i))
.collect();
changed = extend_set(
lives
.entry(ir::RegisterId::temp(*bid, 0))
.or_insert_with(HashSet::new),
phinodes,
) || changed;
} }
if !changed { if !changed {
@@ -212,95 +222,57 @@ impl InferenceGraph {
} }
} }
for (bid, block) in &code.blocks { // for (bid, block) in &code.blocks {
for (i, _) in block.phinodes.iter().enumerate() { // for (i, _) in block.phinodes.iter().enumerate() {
let rid1 = ir::RegisterId::arg(*bid, i); // let rid1 = ir::RegisterId::arg(*bid, i);
for (j, _) in block.phinodes.iter().enumerate() { // for (j, _) in block.phinodes.iter().enumerate() {
if i != j { // if i != j {
let rid2 = ir::RegisterId::arg(*bid, j); // let rid2 = ir::RegisterId::arg(*bid, j);
let _ = edges.insert((rid1, rid2)); // let _ = edges.insert((rid1, rid2));
} // }
} // }
for (j, _) in block.instructions.iter().enumerate() { // for (j, _) in block.instructions.iter().enumerate() {
let rid2 = ir::RegisterId::temp(*bid, j); // let rid2 = ir::RegisterId::temp(*bid, j);
let _ = edges.insert((rid1, rid2)); // let _ = edges.insert((rid1, rid2));
let _ = edges.insert((rid2, rid1)); // let _ = edges.insert((rid2, rid1));
} // }
} // }
} // }
let mut num_of_edges = HashMap::new(); let mut num_of_edges = HashMap::new();
for (rid1, _) in &edges { for (rid1, _) in &edges {
*num_of_edges.entry(*rid1).or_insert(0) += 1; *num_of_edges.entry(*rid1).or_insert(0) += 1;
} }
let (mut num_int_args, mut num_float_args, primitive_arg_reg_index) = let analysis = analyze_function(code, signature, structs);
get_number_of_register_arguments(&signature.ret, &signature.params, structs);
let mut has_call = false;
let mut is_a0_return_pointer = false;
'outer: for block in code.blocks.values() { if !analysis.has_memcpy_in_prologue {
for inst in &block.instructions { for (aid, dtype) in code.blocks[&code.bid_init].phinodes.iter().enumerate() {
if let ir::Instruction::Call { let rid = ir::RegisterId::arg(code.bid_init, aid);
callee, if analysis.is_temporary2(&rid, &lives) {
args, if is_integer(dtype) {
return_type, let (_, asm_reg) = vertices.get_mut(&rid).unwrap();
} = inst.deref() *asm_reg = asm::Register::arg(
{ asm::RegisterType::Integer,
// let (new_num_int_args, new_num_float_args) = get_number_of_register_arguments( analysis.primitive_arg_reg_index[&aid] as usize,
// return_type, );
// &args.iter().map(|operand| operand.dtype()).collect(), } else if is_float(dtype) {
// structs, let (_, asm_reg) = vertices.get_mut(&rid).unwrap();
// ); *asm_reg = asm::Register::arg(
// num_int_args = std::cmp::max(num_int_args, new_num_int_args); asm::RegisterType::FloatingPoint,
// num_float_args = std::cmp::max(num_float_args, new_num_float_args); analysis.primitive_arg_reg_index[&aid] as usize,
);
num_int_args = 8;
num_float_args = 8; // call이 있는 경우 a는 사용 x
has_call = true;
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;
has_call = true; // memcpy
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;
has_call = true; // memcpy
break 'outer;
} }
} }
} }
} }
if let Some(size) = is_struct(&signature.ret, structs) { for (bid, iid, _, reg) in &analysis.calls {
if size > 16 { let rid = ir::RegisterId::temp(*bid, *iid);
num_int_args = 8; if analysis.is_temporary2(&rid, &lives) {
num_float_args = 8; if let Some(reg) = reg {
has_call = true; // memcpy
is_a0_return_pointer = true;
}
}
if !has_call {
for (aid, dtype) in code.blocks[&code.bid_init].phinodes.iter().enumerate() {
let rid = ir::RegisterId::arg(code.bid_init, aid);
if is_integer(dtype) {
let (_, asm_reg) = vertices.get_mut(&rid).unwrap(); let (_, asm_reg) = vertices.get_mut(&rid).unwrap();
*asm_reg = asm::Register::arg( *asm_reg = *reg;
asm::RegisterType::Integer,
primitive_arg_reg_index[&aid] as usize,
);
} else if is_float(dtype) {
let (_, asm_reg) = vertices.get_mut(&rid).unwrap();
*asm_reg = asm::Register::arg(
asm::RegisterType::FloatingPoint,
primitive_arg_reg_index[&aid] as usize,
);
} }
} }
} }
@@ -363,7 +335,7 @@ impl InferenceGraph {
} }
}) })
.collect(), .collect(),
num_int_args as usize, 0,
); );
let smallest_saved_reg = smallest_missing_integer( let smallest_saved_reg = smallest_missing_integer(
&neighbor_registers &neighbor_registers
@@ -378,7 +350,7 @@ impl InferenceGraph {
.collect(), .collect(),
1, 1,
); // s0는 못 씀 ); // s0는 못 씀
if smallest_arg_reg <= 7 { if smallest_arg_reg <= 7 && analysis.is_temporary2(&rid, &lives) {
let _unused = vertices.insert( let _unused = vertices.insert(
rid, rid,
( (
@@ -409,7 +381,7 @@ impl InferenceGraph {
} }
}) })
.collect(), .collect(),
num_float_args as usize, 0,
); );
let smallest_saved_reg = smallest_missing_integer( let smallest_saved_reg = smallest_missing_integer(
&neighbor_registers &neighbor_registers
@@ -424,7 +396,7 @@ impl InferenceGraph {
.collect(), .collect(),
0, 0,
); );
if smallest_arg_reg <= 7 { if smallest_arg_reg <= 7 && analysis.is_temporary2(&rid, &lives) {
let _unused = vertices.insert( let _unused = vertices.insert(
rid, rid,
( (
@@ -454,8 +426,8 @@ impl InferenceGraph {
InferenceGraph { InferenceGraph {
edges, edges,
vertices, vertices,
has_call, analysis,
is_a0_return_pointer, lives,
} }
} }
@@ -501,6 +473,117 @@ fn smallest_missing_integer(set: &HashSet<usize>, start: usize) -> usize {
i i
} }
struct Analysis {
num_int_args: i32,
num_float_args: i32,
primitive_arg_reg_index: HashMap<usize, i32>,
is_a0_return_pointer: bool,
has_memcpy_in_prologue: bool,
calls: Vec<(
ir::BlockId,
usize,
HashSet<ir::RegisterId>,
Option<asm::Register>,
)>,
has_call: bool,
}
impl Analysis {
fn is_temporary2(
&self,
reg: &ir::RegisterId,
lives: &HashMap<ir::RegisterId, HashSet<ir::RegisterId>>,
) -> bool {
for (call_bid, call_iid, call_args, _) in &self.calls {
let lives_before = lives
.get(&ir::RegisterId::temp(*call_bid, *call_iid))
.unwrap();
let lives_after = lives
.get(&ir::RegisterId::temp(*call_bid, call_iid + 1))
.unwrap();
if lives_before.contains(reg) && (call_args.contains(reg) || lives_after.contains(reg))
{
return false;
}
}
true
}
}
fn analyze_function(
code: &ir::FunctionDefinition,
signature: &ir::FunctionSignature,
structs: &HashMap<String, Option<ir::Dtype>>,
) -> Analysis {
let (num_int_args, num_float_args, primitive_arg_reg_index) =
get_number_of_register_arguments(&signature.ret, &signature.params, structs);
let is_a0_return_pointer = is_struct(&signature.ret, structs).is_some_and(|size| size > 16);
let mut calls = Vec::new();
for (bid, block) in &code.blocks {
for (iid, inst) in block.instructions.iter().enumerate() {
match inst.deref() {
ir::Instruction::Call { callee, args, .. } => {
let mut used = HashSet::new();
mark_as_used(callee, &mut used);
for arg in args {
mark_as_used(arg, &mut used);
}
let return_type = callee
.dtype()
.get_pointer_inner()
.unwrap()
.get_function_inner()
.unwrap()
.0
.clone();
let ret_asm_reg = if is_integer(&return_type) {
Some(asm::Register::A0)
} else if is_float(&return_type) {
Some(asm::Register::FA0)
} else {
None
};
calls.push((*bid, iid, used, ret_asm_reg));
}
ir::Instruction::Store { value, .. } => {
if is_struct(&value.dtype(), structs).is_some() {
calls.push((*bid, iid, HashSet::new(), None)); // memcpy
}
}
ir::Instruction::Load { ptr } => {
if is_struct(ptr.dtype().get_pointer_inner().unwrap(), structs).is_some() {
calls.push((*bid, iid, HashSet::new(), None)); // memcpy
}
}
_ => (),
}
}
}
let has_memcpy_in_prologue = signature.params.iter().any(|param| {
if let Some(size) = is_struct(param, structs) {
size > 16
} else {
false
}
});
let has_call = has_memcpy_in_prologue || !calls.is_empty();
Analysis {
num_int_args,
num_float_args,
primitive_arg_reg_index,
is_a0_return_pointer,
has_memcpy_in_prologue,
calls,
has_call,
}
}
struct Context { struct Context {
insts: Vec<asm::Instruction>, insts: Vec<asm::Instruction>,
stack_offsets: HashMap<ir::RegisterId, u64>, stack_offsets: HashMap<ir::RegisterId, u64>,
@@ -649,11 +732,11 @@ impl Asmgen {
stack_allocation += 8; // s0 stack_allocation += 8; // s0
let mut saved_reg_offset = 8; let mut saved_reg_offset = 8;
if inference_graph.has_call { if inference_graph.analysis.has_call {
stack_allocation += 8; // ra stack_allocation += 8; // ra
saved_reg_offset += 8; saved_reg_offset += 8;
} }
if inference_graph.is_a0_return_pointer { if inference_graph.analysis.is_a0_return_pointer {
stack_allocation += 8; // a0 stack_allocation += 8; // a0
saved_reg_offset += 8; saved_reg_offset += 8;
} }
@@ -718,7 +801,7 @@ impl Asmgen {
stack_allocation, stack_allocation,
&mut insts, &mut insts,
); );
if inference_graph.has_call { if inference_graph.analysis.has_call {
insts.push(asm::Instruction::SType { insts.push(asm::Instruction::SType {
instr: asm::SType::SD, instr: asm::SType::SD,
rs1: asm::Register::S0, rs1: asm::Register::S0,
@@ -726,7 +809,7 @@ impl Asmgen {
imm: asm::Immediate::Value(!16 + 1), imm: asm::Immediate::Value(!16 + 1),
}); });
} }
if inference_graph.is_a0_return_pointer { if inference_graph.analysis.is_a0_return_pointer {
insts.push(asm::Instruction::SType { insts.push(asm::Instruction::SType {
instr: asm::SType::SD, instr: asm::SType::SD,
rs1: asm::Register::S0, rs1: asm::Register::S0,
@@ -1053,7 +1136,7 @@ impl Asmgen {
}); });
} }
if context.inference_graph.has_call { if context.inference_graph.analysis.has_call {
context.insts.push(asm::Instruction::IType { context.insts.push(asm::Instruction::IType {
instr: asm::IType::LD, instr: asm::IType::LD,
rd: asm::Register::Ra, rd: asm::Register::Ra,
@@ -1960,12 +2043,14 @@ impl Asmgen {
// TODO // TODO
if is_integer(return_type) { if is_integer(return_type) {
if let Some(rd) = context.inference_graph.get_register(&rid) { if let Some(rd) = context.inference_graph.get_register(&rid) {
context if rd != asm::Register::A0 {
.insts context
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv { .insts
rd, .push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rs: asm::Register::A0, rd,
})); rs: asm::Register::A0,
}));
}
} else { } else {
self.translate_store_result( self.translate_store_result(
&rid, &rid,
@@ -1976,14 +2061,16 @@ impl Asmgen {
} }
} else if is_float(return_type) { } else if is_float(return_type) {
if let Some(rd) = context.inference_graph.get_register(&rid) { if let Some(rd) = context.inference_graph.get_register(&rid) {
context if rd != asm::Register::FA0 {
.insts context
.push(asm::Instruction::Pseudo(asm::Pseudo::Fmv { .insts
data_size: asm::DataSize::try_from(return_type.clone()) .push(asm::Instruction::Pseudo(asm::Pseudo::Fmv {
.unwrap(), data_size: asm::DataSize::try_from(return_type.clone())
rd, .unwrap(),
rs: asm::Register::FA0, rd,
})); rs: asm::Register::FA0,
}));
}
} else { } else {
self.translate_store_result( self.translate_store_result(
&rid, &rid,
@@ -2153,9 +2240,14 @@ impl Asmgen {
} }
} }
} else if is_signed == target_is_signed { } else if is_signed == target_is_signed {
context if rd != rs1 {
.insts context
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv { rd, rs: rs1 })) .insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd,
rs: rs1,
}));
}
} else if *target_is_signed { } else if *target_is_signed {
let rs2 = get_rhs_register(&value_dtype); let rs2 = get_rhs_register(&value_dtype);
context context
@@ -2216,7 +2308,7 @@ impl Asmgen {
rs1, rs1,
context, context,
); );
} else { } else if rd != rs1 {
context context
.insts .insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv { .push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
@@ -2447,7 +2539,7 @@ impl Asmgen {
let default_label = self.translate_label(name, default, context, structs); let default_label = self.translate_label(name, default, context, structs);
for (case, arg) in cases { for (case, arg) in cases {
let _ = self.translate_load_operand( let rs2 = self.translate_load_operand(
&ir::Operand::constant(case.clone()), &ir::Operand::constant(case.clone()),
rs2, rs2,
context, context,
@@ -2611,6 +2703,7 @@ impl Asmgen {
ir::Operand::Constant(constant) => { ir::Operand::Constant(constant) => {
match constant { match constant {
ir::Constant::Undef { .. } => (), // Do nothing ir::Constant::Undef { .. } => (), // Do nothing
ir::Constant::Int { value: 0, .. } => return asm::Register::Zero,
&ir::Constant::Int { value, .. } => { &ir::Constant::Int { value, .. } => {
context context
.insts .insts
@@ -2703,7 +2796,14 @@ impl Asmgen {
structs: &HashMap<String, Option<ir::Dtype>>, structs: &HashMap<String, Option<ir::Dtype>>,
) -> Vec<asm::Instruction> { ) -> Vec<asm::Instruction> {
let bid = arg.bid; let bid = arg.bid;
let mut lives = context
.inference_graph
.lives
.get(&ir::RegisterId::temp(bid, 0))
.cloned()
.unwrap_or_default();
let mut referenced_org_phinodes = HashSet::new(); let mut referenced_org_phinodes = HashSet::new();
for arg in &arg.args { for arg in &arg.args {
if let ir::Operand::Register { if let ir::Operand::Register {
rid: ir::RegisterId::Arg { bid: arg_bid, aid }, rid: ir::RegisterId::Arg { bid: arg_bid, aid },
@@ -2714,13 +2814,67 @@ impl Asmgen {
let _ = referenced_org_phinodes.insert(aid); let _ = referenced_org_phinodes.insert(aid);
} }
} }
if let ir::Operand::Register { rid, .. } = arg {
let _ = lives.insert(*rid);
}
} }
let mut used_asm_registers = lives
.iter()
.filter_map(|rid| context.inference_graph.get_register(rid))
.collect::<HashSet<_>>();
let mut phinode_temp_registers = HashMap::new();
let mut phinode_stack_offsets = HashMap::new(); let mut phinode_stack_offsets = HashMap::new();
let mut phinode_stack_allocations = 0; let mut phinode_stack_allocations = 0;
for (aid, arg) in arg.args.iter().enumerate() { for (aid, arg) in arg.args.iter().enumerate() {
if referenced_org_phinodes.contains(&aid) { if referenced_org_phinodes.contains(&aid) {
let dtype = arg.dtype();
// 자리가 있으면 기존 phinode 값을 레지스터에 백업
if is_integer(&dtype) {
let used_asm_a_registers = used_asm_registers
.iter()
.filter_map(|asm_reg| {
if let asm::Register::Arg(asm::RegisterType::Integer, i) = asm_reg {
Some(*i)
} else {
None
}
})
.collect();
let smallest_a = smallest_missing_integer(&used_asm_a_registers, 0);
if smallest_a <= 7 {
let asm_reg = asm::Register::arg(asm::RegisterType::Integer, smallest_a);
let _ = phinode_temp_registers.insert(aid, asm_reg);
let _ = used_asm_registers.insert(asm_reg);
continue;
}
} else if is_float(&dtype) {
let used_asm_a_registers = used_asm_registers
.iter()
.filter_map(|asm_reg| {
if let asm::Register::Arg(asm::RegisterType::FloatingPoint, i) = asm_reg
{
Some(*i)
} else {
None
}
})
.collect();
let smallest_a = smallest_missing_integer(&used_asm_a_registers, 0);
if smallest_a <= 7 {
let asm_reg =
asm::Register::arg(asm::RegisterType::FloatingPoint, smallest_a);
let _ = phinode_temp_registers.insert(aid, asm_reg);
let _ = used_asm_registers.insert(asm_reg);
continue;
}
} else {
todo!()
}
// 자리가 없으면 스택에
let _ = phinode_stack_offsets.insert(aid, phinode_stack_allocations); let _ = phinode_stack_offsets.insert(aid, phinode_stack_allocations);
phinode_stack_allocations += phinode_stack_allocations +=
ceil_to_multiple_of_16(get_dtype_size(&arg.dtype(), structs)); ceil_to_multiple_of_16(get_dtype_size(&arg.dtype(), structs));
@@ -2737,32 +2891,50 @@ impl Asmgen {
); );
} }
// Swap Issue를 해결하기 위해 스택에 기존 phinode값 저장 (필요한 것만) // Swap Issue를 해결하기 위해 스택/레지스터에 기존 phinode값 저장 (필요한 것만)
let bid = arg.bid; let bid = arg.bid;
for (aid, arg) in arg.args.iter().enumerate() { for (aid, arg) in arg.args.iter().enumerate() {
if referenced_org_phinodes.contains(&aid) { if referenced_org_phinodes.contains(&aid) {
let rid = ir::RegisterId::arg(bid, aid); let rid = ir::RegisterId::arg(bid, aid);
let arg_dtype = arg.dtype(); let arg_dtype = arg.dtype();
let rs1 = if let Some(rs1) = context.inference_graph.get_register(&rid) { let rs1: asm::Register =
rs1 if let Some(rs1) = context.inference_graph.get_register(&rid) {
rs1
} else {
let rs1 = get_lhs_register(&arg_dtype);
self.translate_load(
asm::IType::load(arg_dtype.clone()),
rs1,
asm::Register::S0,
context.stack_offsets[&rid],
&mut phinode_insts,
);
rs1
};
if let Some(asm_reg) = phinode_temp_registers.get(&aid) {
if is_integer(&arg_dtype) {
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd: *asm_reg,
rs: rs1,
}));
} else if is_float(&arg_dtype) {
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Fmv {
data_size: asm::DataSize::try_from(arg_dtype).unwrap(),
rd: *asm_reg,
rs: rs1,
}));
} else {
unreachable!()
}
} else { } else {
let rs1 = get_lhs_register(&arg_dtype); self.translate_store(
self.translate_load( asm::SType::store(arg_dtype),
asm::IType::load(arg_dtype.clone()), asm::Register::Sp,
rs1, rs1,
asm::Register::S0, phinode_stack_offsets[&aid],
context.stack_offsets[&rid],
&mut phinode_insts, &mut phinode_insts,
); );
rs1 }
};
self.translate_store(
asm::SType::store(arg_dtype),
asm::Register::Sp,
rs1,
phinode_stack_offsets[&aid],
&mut phinode_insts,
);
} }
} }
@@ -2776,6 +2948,23 @@ impl Asmgen {
match arg { match arg {
ir::Operand::Constant(constant) => match constant { ir::Operand::Constant(constant) => match constant {
ir::Constant::Undef { .. } => continue, // Do nothing ir::Constant::Undef { .. } => continue, // Do nothing
ir::Constant::Int { value: 0, .. } => {
if is_spilled {
self.translate_store(
asm::SType::store(arg.dtype()),
asm::Register::S0,
asm::Register::Zero,
context.stack_offsets[&ir::RegisterId::arg(bid, aid)],
&mut phinode_insts,
);
continue;
} else {
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd,
rs: asm::Register::Zero,
}));
}
}
ir::Constant::Int { ir::Constant::Int {
value, value,
width, width,
@@ -2793,13 +2982,32 @@ impl Asmgen {
} = arg_rid } = arg_rid
{ {
if *arg_bid == bid { if *arg_bid == bid {
self.translate_load( if let Some(asm_reg) = phinode_temp_registers.get(arg_aid) {
asm::IType::load(arg_dtype), if is_integer(&arg_dtype) {
rd, phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
asm::Register::Sp, rd,
phinode_stack_offsets[arg_aid], rs: *asm_reg,
&mut phinode_insts, }));
); } else if is_float(&arg_dtype) {
phinode_insts.push(asm::Instruction::Pseudo(
asm::Pseudo::Fmv {
data_size: asm::DataSize::try_from(arg_dtype).unwrap(),
rd,
rs: *asm_reg,
},
));
} else {
unreachable!()
}
} else {
self.translate_load(
asm::IType::load(arg_dtype),
rd,
asm::Register::Sp,
phinode_stack_offsets[arg_aid],
&mut phinode_insts,
);
}
} else if let Some(rs1) = context.inference_graph.get_register(arg_rid) { } else if let Some(rs1) = context.inference_graph.get_register(arg_rid) {
if is_integer(&arg_dtype) { if is_integer(&arg_dtype) {
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv { phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {