Lab4: Implement basic scalar optimizations and lower Phi nodes to assembly

This commit is contained in:
2026-05-05 10:20:15 +08:00
committed by CGH0S7
parent 0b0bc04be3
commit 8f7e0ac5b4
17 changed files with 1318 additions and 35 deletions

View File

@@ -31,6 +31,26 @@ uint32_t GetTypeSize(const ir::Type* type) {
uint32_t GetAllocaSize(const ir::Instruction& inst) {
auto type = inst.GetType();
if (type->IsPtrInt32() || type->IsPtrFloat()) {
// Check if any StoreInst in the parent function stores a pointer to this alloca
auto* parent_bb = inst.GetParent();
if (parent_bb) {
auto* parent_func = parent_bb->GetParent();
if (parent_func) {
for (const auto& bbPtr : parent_func->GetBlocks()) {
for (const auto& other_inst : bbPtr->GetInstructions()) {
if (other_inst->GetOpcode() == ir::Opcode::Store) {
auto* store = static_cast<const ir::StoreInst*>(other_inst.get());
if (store->GetPtr() == &inst) {
auto val_ty = store->GetValue()->GetType();
if (val_ty->IsPtrInt32() || val_ty->IsPtrFloat()) {
return 8; // Stores a 64-bit pointer
}
}
}
}
}
}
}
return 4;
}
return GetTypeSize(type.get());
@@ -120,7 +140,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
if (alloca->GetOpcode() == ir::Opcode::Alloca) {
auto it = slots.find(alloca);
if (it != slots.end()) {
PhysReg val_reg = store.GetValue()->GetType()->IsFloat() ? PhysReg::S8 : PhysReg::W8;
PhysReg val_reg = store.GetValue()->GetType()->IsFloat() ? PhysReg::S8 :
(store.GetValue()->GetType()->IsPtrInt32() || store.GetValue()->GetType()->IsPtrFloat()) ? PhysReg::X8 : PhysReg::W8;
EmitValueToReg(store.GetValue(), val_reg, slots, block);
block.Append(Opcode::StoreStack, {Operand::Reg(val_reg), Operand::FrameIndex(it->second)});
return;
@@ -129,7 +150,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
}
// Dynamic store
PhysReg val_reg = store.GetValue()->GetType()->IsFloat() ? PhysReg::S8 : PhysReg::W8;
PhysReg val_reg = store.GetValue()->GetType()->IsFloat() ? PhysReg::S8 :
(store.GetValue()->GetType()->IsPtrInt32() || store.GetValue()->GetType()->IsPtrFloat()) ? PhysReg::X8 : PhysReg::W8;
EmitValueToReg(store.GetValue(), val_reg, slots, block);
EmitAddressToReg(store.GetPtr(), PhysReg::X9, slots, block);
block.Append(Opcode::StrRegReg, {Operand::Reg(val_reg), Operand::Reg(PhysReg::X9)});
@@ -144,7 +166,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
if (alloca->GetOpcode() == ir::Opcode::Alloca) {
auto it = slots.find(alloca);
if (it != slots.end()) {
PhysReg val_reg = load.GetType()->IsFloat() ? PhysReg::S8 : PhysReg::W8;
PhysReg val_reg = load.GetType()->IsFloat() ? PhysReg::S8 :
(load.GetType()->IsPtrInt32() || load.GetType()->IsPtrFloat()) ? PhysReg::X8 : PhysReg::W8;
block.Append(Opcode::LoadStack, {Operand::Reg(val_reg), Operand::FrameIndex(it->second)});
block.Append(Opcode::StoreStack, {Operand::Reg(val_reg), Operand::FrameIndex(dst_slot)});
return;
@@ -153,7 +176,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
}
// Dynamic load
PhysReg val_reg = load.GetType()->IsFloat() ? PhysReg::S8 : PhysReg::W8;
PhysReg val_reg = load.GetType()->IsFloat() ? PhysReg::S8 :
(load.GetType()->IsPtrInt32() || load.GetType()->IsPtrFloat()) ? PhysReg::X8 : PhysReg::W8;
EmitAddressToReg(load.GetPtr(), PhysReg::X9, slots, block);
block.Append(Opcode::LdrRegReg, {Operand::Reg(val_reg), Operand::Reg(PhysReg::X9)});
block.Append(Opcode::StoreStack, {Operand::Reg(val_reg), Operand::FrameIndex(dst_slot)});
@@ -301,22 +325,50 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
}
case ir::Opcode::Br: {
auto& br = static_cast<const ir::BranchInst&>(inst);
std::cerr << "DEBUG: Br is_conditional=" << br.IsConditional() << std::endl;
auto emit_phi_copies = [&](const ir::BasicBlock* succ) {
if (!succ) return;
for (const auto& succ_inst : succ->GetInstructions()) {
if (succ_inst->GetOpcode() == ir::Opcode::Phi) {
auto* phi = static_cast<const ir::PhiInst*>(succ_inst.get());
const ir::Value* incoming_val = nullptr;
for (size_t i = 0; i < phi->GetNumIncoming(); ++i) {
if (phi->GetIncomingBlock(i) == inst.GetParent()) {
incoming_val = phi->GetIncomingValue(i);
break;
}
}
if (incoming_val) {
auto slot_it = slots.find(phi);
if (slot_it != slots.end()) {
int phi_slot = slot_it->second;
PhysReg val_reg = phi->GetType()->IsFloat() ? PhysReg::S8 :
(phi->GetType()->IsPtrInt32() || phi->GetType()->IsPtrFloat()) ? PhysReg::X8 : PhysReg::W8;
EmitValueToReg(incoming_val, val_reg, slots, block);
block.Append(Opcode::StoreStack, {Operand::Reg(val_reg), Operand::FrameIndex(phi_slot)});
}
}
}
}
};
if (br.IsConditional()) {
std::cerr << "DEBUG: Cond pointer=" << br.GetCondition() << std::endl;
std::cerr << "DEBUG: True pointer=" << br.GetIfTrue() << " name=" << (br.GetIfTrue() ? br.GetIfTrue()->GetName() : "<null>") << std::endl;
std::cerr << "DEBUG: False pointer=" << br.GetIfFalse() << " name=" << (br.GetIfFalse() ? br.GetIfFalse()->GetName() : "<null>") << std::endl;
emit_phi_copies(br.GetIfTrue());
emit_phi_copies(br.GetIfFalse());
EmitValueToReg(br.GetCondition(), PhysReg::W8, slots, block);
block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::W9), Operand::Imm(0)});
block.Append(Opcode::CmpRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)});
block.Append(Opcode::BCond, {Operand::Cond("ne"), Operand::Label(br.GetIfTrue()->GetName())});
block.Append(Opcode::B, {Operand::Label(br.GetIfFalse()->GetName())});
} else {
std::cerr << "DEBUG: Dest pointer=" << br.GetDest() << " name=" << (br.GetDest() ? br.GetDest()->GetName() : "<null>") << std::endl;
emit_phi_copies(br.GetDest());
block.Append(Opcode::B, {Operand::Label(br.GetDest()->GetName())});
}
return;
}
case ir::Opcode::Phi: {
return;
}
case ir::Opcode::Ret: {
auto& ret = static_cast<const ir::ReturnInst&>(inst);
if (ret.GetValue()) {
@@ -369,8 +421,14 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
slots.emplace(&inst, dst_slot);
// Load base pointer address into X8
if (dynamic_cast<const ir::AllocaInst*>(gep.GetPtr()) || gep.GetPtr()->IsGlobalValue()) {
if (gep.GetPtr()->IsGlobalValue()) {
EmitAddressToReg(gep.GetPtr(), PhysReg::X8, slots, block);
} else if (auto* alloca = dynamic_cast<const ir::AllocaInst*>(gep.GetPtr())) {
if (alloca->GetType()->IsArray()) {
EmitAddressToReg(gep.GetPtr(), PhysReg::X8, slots, block);
} else {
EmitValueToReg(gep.GetPtr(), PhysReg::X8, slots, block);
}
} else {
EmitValueToReg(gep.GetPtr(), PhysReg::X8, slots, block);
}
@@ -428,6 +486,16 @@ std::vector<std::unique_ptr<MachineFunction>> LowerToMIR(const ir::Module& modul
bb_map[bbPtr.get()] = &mbb;
}
// Pre-allocate stack slots for all Phi instructions in the function
for (const auto& bbPtr : func.GetBlocks()) {
for (const auto& inst : bbPtr->GetInstructions()) {
if (inst->GetOpcode() == ir::Opcode::Phi) {
int slot = machine_func->CreateFrameIndex(GetTypeSize(inst->GetType().get()));
slots.emplace(inst.get(), slot);
}
}
}
auto& entry_block = *bb_map.at(func.GetEntry());
// Lower function arguments at the start of the entry block