// IR 文本输出: // - 将 IR 打印为 .ll 风格的文本 // - 支撑调试与测试对比(diff) #include "ir/IR.h" #include #include #include #include "utils/Log.h" namespace ir { static const char* TypeToString(const Type& ty) { switch (ty.GetKind()) { case Type::Kind::Void: return "void"; case Type::Kind::Int1: return "i1"; case Type::Kind::Int32: return "i32"; case Type::Kind::PtrInt32: return "i32*"; } throw std::runtime_error(FormatError("ir", "未知类型")); } 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::Div: return "sdiv"; case Opcode::Mod: return "srem"; case Opcode::Neg: return "neg"; case Opcode::Alloca: return "alloca"; case Opcode::Load: return "load"; case Opcode::Store: return "store"; case Opcode::Ret: return "ret"; case Opcode::Cmp: return "icmp"; case Opcode::Zext: return "zext"; case Opcode::Br: case Opcode::CondBr: return "br"; } return "?"; } static const char* CmpOpToString(CmpOp op) { switch (op) { case CmpOp::Eq: return "eq"; case CmpOp::Ne: return "ne"; case CmpOp::Lt: return "slt"; case CmpOp::Gt: return "sgt"; case CmpOp::Le: return "sle"; case CmpOp::Ge: return "sge"; } return "?"; } static std::string ValueToString(const Value* v) { if (auto* ci = dynamic_cast(v)) { return std::to_string(ci->GetValue()); } return v ? v->GetName() : ""; } static std::string PrintLabel(const Value* bb) { if (!bb) return ""; std::string name = bb->GetName(); if (name.empty()) return ""; if (name[0] == '%') return name; return "%" + name; } static std::string PrintLabelDef(const Value* bb) { if (!bb) return ""; std::string name = bb->GetName(); if (!name.empty() && name[0] == '%') return name.substr(1); return name; } void IRPrinter::Print(const Module& module, std::ostream& os) { for (const auto& func : module.GetFunctions()) { os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName() << "() {\n"; for (const auto& bb : func->GetBlocks()) { if (!bb) { continue; } os << PrintLabelDef(bb.get()) << ":\n"; for (const auto& instPtr : bb->GetInstructions()) { const auto* inst = instPtr.get(); switch (inst->GetOpcode()) { case Opcode::Add: case Opcode::Sub: case Opcode::Mul: case Opcode::Div: case Opcode::Mod: { auto* bin = static_cast(inst); os << " " << bin->GetName() << " = " << OpcodeToString(bin->GetOpcode()) << " " << TypeToString(*bin->GetLhs()->GetType()) << " " << ValueToString(bin->GetLhs()) << ", " << ValueToString(bin->GetRhs()) << "\n"; break; } case Opcode::Neg: { auto* unary = static_cast(inst); os << " " << unary->GetName() << " = " << OpcodeToString(unary->GetOpcode()) << " " << TypeToString(*unary->GetUnaryOperand()->GetType()) << " " << ValueToString(unary->GetUnaryOperand()) << "\n"; break; } case Opcode::Alloca: { auto* alloca = static_cast(inst); os << " " << alloca->GetName() << " = alloca i32\n"; break; } case Opcode::Load: { auto* load = static_cast(inst); os << " " << load->GetName() << " = load i32, i32* " << ValueToString(load->GetPtr()) << "\n"; break; } case Opcode::Store: { auto* store = static_cast(inst); os << " store i32 " << ValueToString(store->GetValue()) << ", i32* " << ValueToString(store->GetPtr()) << "\n"; break; } case Opcode::Ret: { auto* ret = static_cast(inst); os << " ret " << TypeToString(*ret->GetValue()->GetType()) << " " << ValueToString(ret->GetValue()) << "\n"; break; } case Opcode::Cmp: { auto* cmp = static_cast(inst); os << " " << cmp->GetName() << " = icmp " << CmpOpToString(cmp->GetCmpOp()) << " " << TypeToString(*cmp->GetLhs()->GetType()) << " " << ValueToString(cmp->GetLhs()) << ", " << ValueToString(cmp->GetRhs()) << "\n"; break; } case Opcode::Zext: { auto* zext = static_cast(inst); os << " " << zext->GetName() << " = zext " << TypeToString(*zext->GetOperand(0)->GetType()) << " " << ValueToString(zext->GetOperand(0)) << " to " << TypeToString(*zext->GetType()) << "\n"; break; } case Opcode::Br: { auto* br = static_cast(inst); os << " br label " << PrintLabel(br->GetDest()) << "\n"; break; } case Opcode::CondBr: { auto* cbr = static_cast(inst); os << " br i1 " << ValueToString(cbr->GetCond()) << ", label " << PrintLabel(cbr->GetTrueBlock()) << ", label " << PrintLabel(cbr->GetFalseBlock()) << "\n"; break; } } } } os << "}\n"; } } } // namespace ir