feat(mir): 添加 MIR 验证器和寄存器分配验证器

- MIRVerifier: vreg 单定义(逐块)检查、块终止指令检查
- RegAllocVerifier: 物理寄存器有效性检查(范围 0-96)
- Debug 构建中每个 MIR pass 后自动运行(#ifndef NDEBUG)
lzk
lzkk 4 days ago
parent fb77d7e03c
commit 6c5441ff43

@ -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<LiveInterval> ComputeInstLiveness(MachineFunction &func);
} // namespace mir

@ -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);

@ -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

@ -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 <cstdlib>
#include <iostream>
#include <sstream>
#include <unordered_set>
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<int> 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<int>(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<int>(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

@ -0,0 +1,57 @@
// 寄存器分配验证器:在寄存器分配后检查所有物理寄存器赋值是否合法。
//
// 检查项:
// 1. 所有 Reg 类型操作数的 PhysReg 值在合法范围内0-96即 W0..WZR
//
// 验证失败时输出错误信息并 abort()。调用方通过 NDEBUG 控制是否启用。
#include "mir/MIR.h"
#include "utils/Log.h"
#include <cstdlib>
#include <iostream>
#include <sstream>
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<int>(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
Loading…
Cancel
Save