diff --git a/src/include/mir/MIR.h b/src/include/mir/MIR.h index 8256978a..8e269b2a 100644 --- a/src/include/mir/MIR.h +++ b/src/include/mir/MIR.h @@ -424,13 +424,34 @@ namespace mir void RunRegAlloc(MachineFunction &function); void RunRegAlloc(MachineModule &module); + void RunLinearScanRegAlloc(MachineFunction &function); + void RunLinearScanRegAlloc(MachineModule &module); + void RunFrameLowering(MachineFunction &function); void RunFrameLowering(MachineModule &module); void RunPeephole(MachineFunction &function); void RunPeephole(MachineModule &module); + void VerifyMIR(MachineFunction &func); + void VerifyMIR(MachineModule &module); + + void VerifyRegAlloc(MachineFunction &func); + void VerifyRegAlloc(MachineModule &module); + void PrintAsm(const MachineFunction &function, std::ostream &os); void PrintAsm(const MachineModule &module, std::ostream &os); + struct LiveInterval + { + int vreg; + int start; // instruction position (global index) + int end; // instruction position + VRegClass vreg_class; + bool spilled = false; + int spill_slot = -1; + }; + + std::vector ComputeInstLiveness(MachineFunction &func); + } // namespace mir diff --git a/src/main.cpp b/src/main.cpp index 4a8dc84a..0c885a5f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,10 +56,33 @@ int main(int argc, char** argv) { // 汇编输出到文件或标准输出 if (opts.emit_asm) { auto machine_module = mir::LowerModuleToMIR(*module); - mir::RunRegAlloc(*machine_module); + +#ifndef NDEBUG + mir::VerifyMIR(*machine_module); +#endif + + if (opts.regalloc == "linear") + mir::RunLinearScanRegAlloc(*machine_module); + else + mir::RunRegAlloc(*machine_module); + +#ifndef NDEBUG + mir::VerifyRegAlloc(*machine_module); + mir::VerifyMIR(*machine_module); +#endif + mir::RunFrameLowering(*machine_module); + +#ifndef NDEBUG + mir::VerifyMIR(*machine_module); +#endif + mir::RunPeephole(*machine_module); +#ifndef NDEBUG + mir::VerifyMIR(*machine_module); +#endif + std::ostringstream asm_ss; mir::PrintAsm(*machine_module, asm_ss); diff --git a/src/mir/CMakeLists.txt b/src/mir/CMakeLists.txt index 0b0996b4..9a423168 100644 --- a/src/mir/CMakeLists.txt +++ b/src/mir/CMakeLists.txt @@ -8,6 +8,10 @@ add_library(mir_core STATIC RegAlloc.cpp FrameLowering.cpp AsmPrinter.cpp + MIRVerifier.cpp + RegAllocVerifier.cpp + InstLiveness.cpp + LinearScanAlloc.cpp ) target_link_libraries(mir_core PUBLIC diff --git a/src/mir/MIRVerifier.cpp b/src/mir/MIRVerifier.cpp new file mode 100644 index 00000000..1e372fc6 --- /dev/null +++ b/src/mir/MIRVerifier.cpp @@ -0,0 +1,184 @@ +// MIR 验证器:校验 MIR 模块的合法性。 +// 检查项: +// 1. VReg 单一定义(按基本块):每个虚拟寄存器在单个基本块中被定义最多一次 +// 2. 基本块终结指令:每个非空基本块以有效终结指令结尾或合法 fallthrough +// +// 注意:MIR 不是全局 SSA 形式——phi-copy 使得同一 VReg 可在多个基本块中定义, +// 因此 VReg 检查范围限定在单个基本块内。 +// +// 验证失败时输出错误信息并 abort()。调用方通过 NDEBUG 控制是否启用。 + +#include "mir/MIR.h" +#include "utils/Log.h" + +#include +#include +#include +#include + +namespace mir { + +namespace { + +// 判断该操作码是否定义 VReg(第一操作数为目标操作数时) +// 对于首位是 VReg 但实际为 use 的操作码返回 false +bool HasVRegDef(Opcode opcode) +{ + switch (opcode) + { + // 存储类指令:第一操作数是源 VReg,不是定义 + case Opcode::StoreStack: + case Opcode::StoreGlobal: + case Opcode::StoreMem: + return false; + + // 比较类指令:设置 CPSR 标志位,不定义 VReg + case Opcode::CmpRR: + case Opcode::CmpImm: + case Opcode::FCmpRR: + return false; + + // 无 VReg 操作数的指令 + case Opcode::Br: + case Opcode::CondBr: + case Opcode::Ret: + case Opcode::Call: + case Opcode::Prologue: + case Opcode::Epilogue: + return false; + + default: + return true; + } +} + +// 判断该指令是否为基本块终结指令 +bool IsTerminator(Opcode opcode) +{ + switch (opcode) + { + case Opcode::Br: + case Opcode::CondBr: + case Opcode::Ret: + case Opcode::Call: + return true; + default: + return false; + } +} + +// 验证单个函数的 VReg 单一定义(按基本块) +void VerifyVRegSingleDef(MachineFunction &func) +{ + for (const auto &block : func.GetBlocks()) + { + if (!block) + continue; + + std::unordered_set defined_vregs; + + for (auto &inst : block->GetInstructions()) + { + const auto &operands = inst.GetOperands(); + if (operands.empty()) + continue; + + const auto &op0 = operands[0]; + if (op0.GetKind() != Operand::Kind::VReg) + continue; + + Opcode opcode = inst.GetOpcode(); + if (!HasVRegDef(opcode)) + continue; + + int vreg_id = op0.GetVRegId(); + + if (defined_vregs.find(vreg_id) != defined_vregs.end()) + { + std::ostringstream oss; + oss << "MIR 验证失败: 函数 '" << func.GetName() + << "' 中虚拟寄存器 v%" << vreg_id + << " 在基本块 '" << block->GetName() + << "' 中被重复定义 (操作码=" << static_cast(opcode) << ")"; + LogError(oss.str(), std::cerr); + std::abort(); + } + + defined_vregs.insert(vreg_id); + } + } +} + +// 验证单个函数的块终结指令 +void VerifyBlockTerminators(MachineFunction &func) +{ + const auto &blocks = func.GetBlocks(); + + for (size_t i = 0; i < blocks.size(); ++i) + { + auto &block = blocks[i]; + if (!block) + continue; + + const auto &insts = block->GetInstructions(); + + // 空块检查:仅打印警告(已知 lowering 在某些优化场景下会产生空非入口块) + if (insts.empty()) + { + if (block.get() != func.GetEntryPtr()) + { + std::cerr << "[warning] MIR: 函数 '" << func.GetName() + << "' 的非入口基本块 '" << block->GetName() + << "' 为空" << std::endl; + } + continue; + } + + // 获取最后一条指令 + const auto &last_inst = insts.back(); + Opcode last_opcode = last_inst.GetOpcode(); + + // 跳过 Prologue/Epilogue 作为最后指令(后续由 FrameLowering 处理) + if (last_opcode == Opcode::Prologue || last_opcode == Opcode::Epilogue) + continue; + + bool is_last_block = (i == blocks.size() - 1); + + if (is_last_block) + { + // 最后一个基本块必须以终结指令结尾 + if (!IsTerminator(last_opcode)) + { + std::ostringstream oss; + oss << "MIR 验证失败: 函数 '" << func.GetName() + << "' 的最后一个基本块 '" << block->GetName() + << "' 未以终结指令结尾,最后指令操作码=" + << static_cast(last_opcode); + LogError(oss.str(), std::cerr); + std::abort(); + } + } + // 非最后块:允许 fallthrough,不做强制检查 + } +} + +} // namespace + +void VerifyMIR(MachineFunction &func) +{ + VerifyVRegSingleDef(func); + VerifyBlockTerminators(func); +} + +void VerifyMIR(MachineModule &module) +{ + for (auto &func : module.GetFunctions()) + { + if (!func) + continue; + + VerifyMIR(*func); + } +} + +} // namespace mir diff --git a/src/mir/RegAllocVerifier.cpp b/src/mir/RegAllocVerifier.cpp new file mode 100644 index 00000000..883d8241 --- /dev/null +++ b/src/mir/RegAllocVerifier.cpp @@ -0,0 +1,57 @@ +// 寄存器分配验证器:在寄存器分配后检查所有物理寄存器赋值是否合法。 +// +// 检查项: +// 1. 所有 Reg 类型操作数的 PhysReg 值在合法范围内(0-96,即 W0..WZR) +// +// 验证失败时输出错误信息并 abort()。调用方通过 NDEBUG 控制是否启用。 + +#include "mir/MIR.h" +#include "utils/Log.h" + +#include +#include +#include + +namespace mir { + +void VerifyRegAlloc(MachineFunction &func) +{ + for (auto &bb : func.GetBlocks()) + { + if (!bb) + continue; + + for (auto &inst : bb->GetInstructions()) + { + for (auto &op : inst.GetOperands()) + { + if (op.GetKind() != Operand::Kind::Reg) + continue; + + int reg = static_cast(op.GetReg()); + if (reg < 0 || reg > 96) + { + std::ostringstream oss; + oss << "RegAllocVerifier: invalid physreg " << reg + << " in function " << func.GetName() + << ", block " << bb->GetName(); + LogError(oss.str(), std::cerr); + std::abort(); + } + } + } + } +} + +void VerifyRegAlloc(MachineModule &module) +{ + for (auto &func : module.GetFunctions()) + { + if (!func) + continue; + + VerifyRegAlloc(*func); + } +} + +} // namespace mir