|
|
// IR 文本输出:
|
|
|
// - 将 IR 打印为 .ll 风格的文本
|
|
|
// - 支撑调试与测试对比(diff)
|
|
|
|
|
|
#include "ir/IR.h"
|
|
|
|
|
|
#include <iostream>
|
|
|
#include <string>
|
|
|
#include <stdexcept>
|
|
|
|
|
|
namespace ir {
|
|
|
|
|
|
static const char* TypeToString(const Type& ty) {
|
|
|
switch (ty.kind()) {
|
|
|
case Type::Kind::Void:
|
|
|
return "void";
|
|
|
case Type::Kind::Int32:
|
|
|
return "i32";
|
|
|
case Type::Kind::PtrInt32:
|
|
|
return "i32*";
|
|
|
}
|
|
|
throw std::runtime_error("未知类型");
|
|
|
}
|
|
|
|
|
|
static const char* OpcodeToString(Opcode op) {
|
|
|
switch (op) {
|
|
|
case Opcode::Add:
|
|
|
return "add";
|
|
|
case Opcode::Sub:
|
|
|
return "sub";
|
|
|
case Opcode::Mul:
|
|
|
return "mul";
|
|
|
case Opcode::Alloca:
|
|
|
return "alloca";
|
|
|
case Opcode::Load:
|
|
|
return "load";
|
|
|
case Opcode::Store:
|
|
|
return "store";
|
|
|
case Opcode::Ret:
|
|
|
return "ret";
|
|
|
}
|
|
|
return "?";
|
|
|
}
|
|
|
|
|
|
static std::string ValueToString(const Value* v) {
|
|
|
if (auto* ci = dynamic_cast<const ConstantInt*>(v)) {
|
|
|
return std::to_string(ci->value());
|
|
|
}
|
|
|
return v ? v->name() : "<null>";
|
|
|
}
|
|
|
|
|
|
void IRPrinter::Print(const Module& module) {
|
|
|
for (const auto& func : module.functions()) {
|
|
|
std::cout << "define " << TypeToString(*func->type()) << " @"
|
|
|
<< func->name() << "() {\n";
|
|
|
const auto* bb = func->entry();
|
|
|
if (!bb) {
|
|
|
std::cout << "}\n";
|
|
|
continue;
|
|
|
}
|
|
|
std::cout << "entry:\n";
|
|
|
for (const auto& instPtr : bb->instructions()) {
|
|
|
const auto* inst = instPtr.get();
|
|
|
switch (inst->opcode()) {
|
|
|
case Opcode::Add:
|
|
|
case Opcode::Sub:
|
|
|
case Opcode::Mul: {
|
|
|
auto* bin = static_cast<const BinaryInst*>(inst);
|
|
|
std::cout << " " << bin->name() << " = " << OpcodeToString(bin->opcode())
|
|
|
<< " " << TypeToString(*bin->lhs()->type()) << " "
|
|
|
<< ValueToString(bin->lhs()) << ", "
|
|
|
<< ValueToString(bin->rhs()) << "\n";
|
|
|
break;
|
|
|
}
|
|
|
case Opcode::Alloca: {
|
|
|
auto* alloca = static_cast<const AllocaInst*>(inst);
|
|
|
std::cout << " " << alloca->name() << " = alloca i32\n";
|
|
|
break;
|
|
|
}
|
|
|
case Opcode::Load: {
|
|
|
auto* load = static_cast<const LoadInst*>(inst);
|
|
|
std::cout << " " << load->name() << " = load i32, i32* "
|
|
|
<< ValueToString(load->ptr()) << "\n";
|
|
|
break;
|
|
|
}
|
|
|
case Opcode::Store: {
|
|
|
auto* store = static_cast<const StoreInst*>(inst);
|
|
|
std::cout << " store i32 " << ValueToString(store->value()) << ", i32* "
|
|
|
<< ValueToString(store->ptr()) << "\n";
|
|
|
break;
|
|
|
}
|
|
|
case Opcode::Ret: {
|
|
|
auto* ret = static_cast<const ReturnInst*>(inst);
|
|
|
std::cout << " ret " << TypeToString(*ret->value()->type()) << " "
|
|
|
<< ValueToString(ret->value()) << "\n";
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
std::cout << "}\n";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} // namespace ir
|