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