Complete Lab2 IR generation and document process

This commit is contained in:
2026-04-16 00:21:35 +08:00
parent 6fc0c89072
commit 979d271ebe
23 changed files with 2583 additions and 471 deletions

View File

@@ -1,6 +1,7 @@
#include "irgen/IRGen.h"
#include <stdexcept>
#include <vector>
#include "SysYParser.h"
#include "ir/IR.h"
@@ -8,100 +9,209 @@
namespace {
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
if (!lvalue.ID()) {
throw std::runtime_error(FormatError("irgen", "非法左值"));
}
return lvalue.ID()->getText();
std::shared_ptr<ir::Type> BaseTypeFromDecl(SysYParser::BtypeContext* btype) {
return (btype && btype->FLOAT()) ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
}
std::shared_ptr<ir::Type> StorageType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
size_t CountScalars(const std::shared_ptr<ir::Type>& ty) {
if (!ty->IsArray()) return 1;
auto arr_ty = ty->GetAsArrayType();
return arr_ty->GetNumElements() * CountScalars(arr_ty->GetElementType());
}
} // namespace
std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
void IRGenImpl::ZeroInitializeLocal(ir::Value* ptr, std::shared_ptr<ir::Type> ty) {
if (ty->IsArray()) {
auto arr_ty = ty->GetAsArrayType();
for (uint32_t i = 0; i < arr_ty->GetNumElements(); ++i) {
auto* elem_ptr = builder_.CreateGEP(StorageType(arr_ty->GetElementType()), ptr,
{builder_.CreateConstInt(0),
builder_.CreateConstInt(static_cast<int>(i))},
module_.GetContext().NextTemp());
ZeroInitializeLocal(elem_ptr, arr_ty->GetElementType());
}
return;
}
for (auto* item : ctx->blockItem()) {
if (item) {
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
// 当前语法要求 return 为块内最后一条语句;命中后可停止生成。
break;
ir::Value* zero = ty->IsFloat() ? static_cast<ir::Value*>(builder_.CreateConstFloat(0.0f))
: static_cast<ir::Value*>(builder_.CreateConstInt(0));
builder_.CreateStore(zero, ptr);
}
void IRGenImpl::EmitLocalInitValue(ir::Value* ptr, std::shared_ptr<ir::Type> ty,
SysYParser::InitValueContext* init) {
if (!init) return;
auto build_flat_scalar_ptr = [&](ir::Value* base_ptr,
const std::shared_ptr<ir::Type>& base_ty,
size_t flat_index) -> ir::Value* {
if (!base_ty->IsArray()) return base_ptr;
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
auto cur_ty = base_ty;
size_t offset = flat_index;
while (cur_ty->IsArray()) {
auto arr_ty = cur_ty->GetAsArrayType();
const size_t step = CountScalars(arr_ty->GetElementType());
const size_t idx = step == 0 ? 0 : offset / step;
offset = step == 0 ? 0 : offset % step;
indices.push_back(builder_.CreateConstInt(static_cast<int>(idx)));
cur_ty = arr_ty->GetElementType();
}
return builder_.CreateGEP(StorageType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
};
if (ty->IsArray()) {
auto arr_ty = ty->GetAsArrayType();
const auto elem_ty = arr_ty->GetElementType();
const size_t elem_step = CountScalars(elem_ty);
if (init->exp()) {
auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, 0);
EmitLocalInitValue(elem_ptr, elem_ty, init);
return;
}
const auto& children = init->initValue();
size_t scalar_cursor = 0;
for (auto* child : children) {
if (scalar_cursor >= CountScalars(ty)) break;
if (child->exp()) {
auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, scalar_cursor);
auto scalar_ty = elem_ty;
while (scalar_ty->IsArray()) {
scalar_ty = scalar_ty->GetAsArrayType()->GetElementType();
}
EmitLocalInitValue(elem_ptr, scalar_ty, child);
++scalar_cursor;
continue;
}
const size_t elem_index = elem_step == 0 ? 0 : scalar_cursor / elem_step;
if (elem_index >= arr_ty->GetNumElements()) break;
auto* elem_ptr = builder_.CreateGEP(StorageType(elem_ty), ptr,
{builder_.CreateConstInt(0),
builder_.CreateConstInt(static_cast<int>(elem_index))},
module_.GetContext().NextTemp());
EmitLocalInitValue(elem_ptr, elem_ty, child);
scalar_cursor = (elem_index + 1) * elem_step;
}
return;
}
if (!init->exp()) {
return;
}
ir::Value* value = EvalExpr(*init->exp());
if (ty->IsFloat() && value->GetType()->IsInt32()) {
value = builder_.CreateSIToFP(value, ty, module_.GetContext().NextTemp());
} else if (ty->IsInt32() && value->GetType()->IsFloat()) {
value = builder_.CreateFPToSI(value, ty, module_.GetContext().NextTemp());
}
builder_.CreateStore(value, ptr);
}
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
if (ctx->constDecl()) return ctx->constDecl()->accept(this);
if (ctx->varDecl()) return ctx->varDecl()->accept(this);
return {};
}
std::any IRGenImpl::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
for (auto* def : ctx->constDef()) {
def->accept(this);
}
return {};
}
std::any IRGenImpl::visitVarDecl(SysYParser::VarDeclContext* ctx) {
for (auto* def : ctx->varDef()) {
def->accept(this);
}
return {};
}
std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
const std::string name = ctx->ID()->getText();
auto ty = BaseTypeFromDecl(
dynamic_cast<SysYParser::ConstDeclContext*>(ctx->parent)->btype());
const auto dims = ctx->exp();
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
auto* dim = EvalConstExpr(**it);
if (auto* ci = dynamic_cast<ir::ConstantInt*>(dim)) {
ty = ir::ArrayType::Get(ty, ci->GetValue());
continue;
}
throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量"));
}
ir::Value* slot = nullptr;
if (is_global_scope_) {
ir::ConstantValue* init = nullptr;
if (ctx->initValue() && ctx->initValue()->exp()) {
init = EvalConstExpr(*ctx->initValue()->exp());
if (ty->IsInt32() && init->GetType()->IsFloat()) {
init = module_.GetContext().GetConstInt(
static_cast<int>(static_cast<ir::ConstantFloat*>(init)->GetValue()));
} else if (ty->IsFloat() && init->GetType()->IsInt32()) {
init = module_.GetContext().GetConstFloat(
static_cast<float>(static_cast<ir::ConstantInt*>(init)->GetValue()));
}
}
}
return {};
}
IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
SysYParser::BlockItemContext& item) {
return std::any_cast<BlockFlow>(item.accept(this));
}
std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少块内项"));
}
if (ctx->decl()) {
ctx->decl()->accept(this);
return BlockFlow::Continue;
}
if (ctx->stmt()) {
return ctx->stmt()->accept(this);
}
throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
}
// 变量声明的 IR 生成目前也是最小实现:
// - 先检查声明的基础类型,当前仅支持局部 int
// - 再把 Decl 中的变量定义交给 visitVarDef 继续处理。
//
// 和更完整的版本相比,这里还没有:
// - 一个 Decl 中多个变量定义的顺序处理;
// - const、数组、全局变量等不同声明形态
// - 更丰富的类型系统。
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
}
if (!ctx->btype() || !ctx->btype()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
}
auto* var_def = ctx->varDef();
if (!var_def) {
throw std::runtime_error(FormatError("irgen", "非法变量声明"));
}
var_def->accept(this);
return {};
}
// 当前仍是教学用的最小版本,因此这里只支持:
// - 局部 int 变量;
// - 标量初始化;
// - 一个 VarDef 对应一个槽位。
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量定义"));
}
if (!ctx->lValue()) {
throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
}
GetLValueName(*ctx->lValue());
if (storage_map_.find(ctx) != storage_map_.end()) {
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
}
auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
storage_map_[ctx] = slot;
ir::Value* init = nullptr;
if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) {
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
}
init = EvalExpr(*init_value->exp());
slot = module_.CreateGlobalValue(name, StorageType(ty), init);
} else {
init = builder_.CreateConstInt(0);
slot = builder_.CreateAlloca(StorageType(ty), name);
ZeroInitializeLocal(slot, ty);
EmitLocalInitValue(slot, ty, ctx->initValue());
}
builder_.CreateStore(init, slot);
storage_map_[ctx] = slot;
return {};
}
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
const std::string name = ctx->ID()->getText();
auto ty = BaseTypeFromDecl(
dynamic_cast<SysYParser::VarDeclContext*>(ctx->parent)->btype());
const auto dims = ctx->exp();
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
auto* dim = EvalConstExpr(**it);
if (auto* ci = dynamic_cast<ir::ConstantInt*>(dim)) {
ty = ir::ArrayType::Get(ty, ci->GetValue());
continue;
}
throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量"));
}
ir::Value* slot = nullptr;
if (is_global_scope_) {
ir::ConstantValue* init = nullptr;
if (ctx->initValue() && ctx->initValue()->exp()) {
init = EvalConstExpr(*ctx->initValue()->exp());
if (ty->IsInt32() && init->GetType()->IsFloat()) {
init = module_.GetContext().GetConstInt(
static_cast<int>(static_cast<ir::ConstantFloat*>(init)->GetValue()));
} else if (ty->IsFloat() && init->GetType()->IsInt32()) {
init = module_.GetContext().GetConstFloat(
static_cast<float>(static_cast<ir::ConstantInt*>(init)->GetValue()));
}
}
slot = module_.CreateGlobalValue(name, StorageType(ty), init);
} else {
slot = builder_.CreateAlloca(StorageType(ty), name);
ZeroInitializeLocal(slot, ty);
if (ctx->initValue()) EmitLocalInitValue(slot, ty, ctx->initValue());
}
storage_map_[ctx] = slot;
return {};
}

View File

@@ -6,9 +6,27 @@
#include "ir/IR.h"
#include "utils/Log.h"
static void PredeclareLibraryFunctions(ir::Module& module) {
module.CreateFunction("getint", ir::Type::GetInt32Type(), {});
module.CreateFunction("getch", ir::Type::GetInt32Type(), {});
module.CreateFunction("getfloat", ir::Type::GetFloatType(), {});
module.CreateFunction("getarray", ir::Type::GetInt32Type(), {ir::Type::GetPtrInt32Type()});
module.CreateFunction("getfarray", ir::Type::GetInt32Type(), {ir::Type::GetPtrFloatType()});
module.CreateFunction("putint", ir::Type::GetVoidType(), {ir::Type::GetInt32Type()});
module.CreateFunction("putch", ir::Type::GetVoidType(), {ir::Type::GetInt32Type()});
module.CreateFunction("putfloat", ir::Type::GetVoidType(), {ir::Type::GetFloatType()});
module.CreateFunction("putarray", ir::Type::GetVoidType(), {ir::Type::GetInt32Type(), ir::Type::GetPtrInt32Type()});
module.CreateFunction("putfarray", ir::Type::GetVoidType(), {ir::Type::GetInt32Type(), ir::Type::GetPtrFloatType()});
module.CreateFunction("starttime", ir::Type::GetVoidType(), {});
module.CreateFunction("stoptime", ir::Type::GetVoidType(), {});
// putf is special, but for now we might not support it fully or just declare it simply
// module.CreateFunction("putf", ...);
}
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
const SemanticContext& sema) {
auto module = std::make_unique<ir::Module>();
PredeclareLibraryFunctions(*module);
IRGenImpl gen(*module, sema);
tree.accept(&gen);
return module;

View File

@@ -1,80 +1,724 @@
#include "irgen/IRGen.h"
#include <cmath>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "SysYParser.h"
#include "ir/IR.h"
#include "utils/Log.h"
// 表达式生成当前也只实现了很小的一个子集。
// 目前支持:
// - 整数字面量
// - 普通局部变量读取
// - 括号表达式
// - 二元加法
//
// 还未支持:
// - 减乘除与一元运算
// - 赋值表达式
// - 函数调用
// - 数组、指针、下标访问
// - 条件与比较表达式
// - ...
namespace {
bool IsZero(const ir::ConstantValue* value) {
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return ci->GetValue() == 0;
}
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return cf->GetValue() == 0.0f;
}
return false;
}
bool IsTruthy(const ir::ConstantValue* value) {
return !IsZero(value);
}
int AsInt(const ir::ConstantValue* value) {
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return ci->GetValue();
}
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return static_cast<int>(cf->GetValue());
}
throw std::runtime_error(FormatError("irgen", "无法将常量转换为 int"));
}
float AsFloat(const ir::ConstantValue* value) {
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return cf->GetValue();
}
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return static_cast<float>(ci->GetValue());
}
throw std::runtime_error(FormatError("irgen", "无法将常量转换为 float"));
}
std::shared_ptr<ir::Type> ScalarPointerType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
std::shared_ptr<ir::Type> CommonArithType(ir::Value* lhs, ir::Value* rhs) {
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return ir::Type::GetFloatType();
}
return ir::Type::GetInt32Type();
}
} // namespace
ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
return std::any_cast<ir::Value*>(expr.accept(this));
}
ir::ConstantValue* IRGenImpl::EvalConstExpr(SysYParser::ExpContext& expr) {
class ConstExprVisitor final : public SysYBaseVisitor {
public:
ConstExprVisitor(ir::Module& module, const SemanticContext& sema)
: module_(module), sema_(sema) {}
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
return Eval(*ctx->exp());
}
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
if (ctx->number()->ILITERAL()) {
const std::string text = ctx->number()->ILITERAL()->getText();
int value = 0;
if (text.size() > 2 && (text[1] == 'x' || text[1] == 'X')) {
value = std::stoi(text, nullptr, 16);
} else if (text.size() > 1 && text[0] == '0') {
value = std::stoi(text, nullptr, 8);
} else {
value = std::stoi(text, nullptr, 10);
}
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(value));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(std::stof(ctx->number()->FLITERAL()->getText())));
}
std::any visitLValueExp(SysYParser::LValueExpContext* ctx) override {
auto* def = sema_.ResolveLValue(ctx->lValue());
if (!def) {
throw std::runtime_error(FormatError("irgen", "常量表达式引用了未绑定左值"));
}
if (!ctx->lValue()->exp().empty()) {
throw std::runtime_error(
FormatError("irgen", "暂不支持在常量表达式中访问数组元素"));
}
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
if (!const_def->initValue() || !const_def->initValue()->exp()) {
throw std::runtime_error(
FormatError("irgen", "常量缺少标量初始化表达式"));
}
return Eval(*const_def->initValue()->exp());
}
throw std::runtime_error(
FormatError("irgen", "全局/常量表达式必须是编译期常量"));
}
std::any visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) override {
return Eval(*ctx->exp());
}
std::any visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) override {
auto* value = Eval(*ctx->exp());
if (value->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(-AsFloat(value)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(-AsInt(value)));
}
std::any visitNotExp(SysYParser::NotExpContext* ctx) override {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp())) ? 0 : 1));
}
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) + AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) + AsInt(rhs)));
}
std::any visitSubExp(SysYParser::SubExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) - AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) - AsInt(rhs)));
}
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) * AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) * AsInt(rhs)));
}
std::any visitDivExp(SysYParser::DivExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
const float rv = AsFloat(rhs);
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstFloat(
rv == 0.0f ? 0.0f : AsFloat(lhs) / rv));
}
const int rv = AsInt(rhs);
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(rv == 0 ? 0 : AsInt(lhs) / rv));
}
std::any visitModExp(SysYParser::ModExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(
AsInt(rhs) == 0 ? 0 : AsInt(lhs) % AsInt(rhs)));
}
std::any visitLtExp(SysYParser::LtExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpLT);
}
std::any visitLeExp(SysYParser::LeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpLE);
}
std::any visitGtExp(SysYParser::GtExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpGT);
}
std::any visitGeExp(SysYParser::GeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpGE);
}
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpEQ);
}
std::any visitNeExp(SysYParser::NeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpNE);
}
std::any visitAndExp(SysYParser::AndExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
if (!IsTruthy(lhs)) {
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(0));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp(1))) ? 1 : 0));
}
std::any visitOrExp(SysYParser::OrExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
if (IsTruthy(lhs)) {
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(1));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp(1))) ? 1 : 0));
}
ir::ConstantValue* Eval(SysYParser::ExpContext& ctx) {
return std::any_cast<ir::ConstantValue*>(ctx.accept(this));
}
private:
ir::ConstantValue* EvalCmpImpl(SysYParser::ExpContext& lhs_ctx,
SysYParser::ExpContext& rhs_ctx,
ir::Opcode op) {
auto* lhs = Eval(lhs_ctx);
auto* rhs = Eval(rhs_ctx);
bool result = false;
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
const float a = AsFloat(lhs);
const float b = AsFloat(rhs);
switch (op) {
case ir::Opcode::ICmpLT: result = a < b; break;
case ir::Opcode::ICmpLE: result = a <= b; break;
case ir::Opcode::ICmpGT: result = a > b; break;
case ir::Opcode::ICmpGE: result = a >= b; break;
case ir::Opcode::ICmpEQ: result = a == b; break;
case ir::Opcode::ICmpNE: result = a != b; break;
default: break;
}
} else {
const int a = AsInt(lhs);
const int b = AsInt(rhs);
switch (op) {
case ir::Opcode::ICmpLT: result = a < b; break;
case ir::Opcode::ICmpLE: result = a <= b; break;
case ir::Opcode::ICmpGT: result = a > b; break;
case ir::Opcode::ICmpGE: result = a >= b; break;
case ir::Opcode::ICmpEQ: result = a == b; break;
case ir::Opcode::ICmpNE: result = a != b; break;
default: break;
}
}
return module_.GetContext().GetConstInt(result ? 1 : 0);
}
ir::Module& module_;
const SemanticContext& sema_;
};
ConstExprVisitor visitor(module_, sema_);
return visitor.Eval(expr);
}
static ir::Value* CastValue(IRGenImpl& gen, ir::IRBuilder& builder, ir::Module& module,
ir::Value* value, std::shared_ptr<ir::Type> target_ty) {
if (value->GetType() == target_ty) return value;
if (target_ty->IsFloat() && value->GetType()->IsInt32()) {
if (auto* ci = dynamic_cast<ir::ConstantInt*>(value)) {
return module.GetContext().GetConstFloat(static_cast<float>(ci->GetValue()));
}
return builder.CreateSIToFP(value, target_ty, module.GetContext().NextTemp());
}
if (target_ty->IsInt32() && value->GetType()->IsFloat()) {
if (auto* cf = dynamic_cast<ir::ConstantFloat*>(value)) {
return module.GetContext().GetConstInt(static_cast<int>(cf->GetValue()));
}
return builder.CreateFPToSI(value, target_ty, module.GetContext().NextTemp());
}
return value;
}
std::any IRGenImpl::visitParenExp(SysYParser::ParenExpContext* ctx) {
if (!ctx || !ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "非法括号表达式"));
}
return EvalExpr(*ctx->exp());
}
std::any IRGenImpl::visitLValueExp(SysYParser::LValueExpContext* ctx) {
auto* def = sema_.ResolveLValue(ctx->lValue());
if (def && IsArrayLikeDef(def) && ctx->lValue()->exp().size() < GetArrayRank(def)) {
return DecayArrayPtr(ctx->lValue());
}
ir::Value* ptr = GetLValuePtr(ctx->lValue());
return static_cast<ir::Value*>(
builder_.CreateLoad(ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) {
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
}
return static_cast<ir::Value*>(
builder_.CreateConstInt(std::stoi(ctx->number()->getText())));
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
// 变量使用的处理流程:
// 1. 先通过语义分析结果把变量使用绑定回声明;
// 2. 再通过 storage_map_ 找到该声明对应的栈槽位;
// 3. 最后生成 load把内存中的值读出来。
//
// 因此当前 IRGen 自己不再做名字查找,而是直接消费 Sema 的绑定结果。
std::any IRGenImpl::visitVarExp(SysYParser::VarExpContext* ctx) {
if (!ctx || !ctx->var() || !ctx->var()->ID()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
std::any IRGenImpl::visitFuncCallExp(SysYParser::FuncCallExpContext* ctx) {
ir::Function* target_func = nullptr;
if (auto* def = sema_.ResolveFuncCall(ctx)) {
const std::string func_name = def->ID()->getText();
for (const auto& f : module_.GetFunctions()) {
if (f->GetName() == func_name) {
target_func = f.get();
break;
}
}
} else {
const std::string func_name = ctx->ID()->getText();
for (const auto& f : module_.GetFunctions()) {
if (f->GetName() == func_name) {
target_func = f.get();
break;
}
}
}
auto* decl = sema_.ResolveVarUse(ctx->var());
if (!decl) {
throw std::runtime_error(
FormatError("irgen",
"变量使用缺少语义绑定: " + ctx->var()->ID()->getText()));
if (!target_func) {
throw std::runtime_error(FormatError("irgen", "找不到函数: " + ctx->ID()->getText()));
}
auto it = storage_map_.find(decl);
std::vector<ir::Value*> args;
const auto& arg_types = target_func->GetArguments();
if (ctx->funcRParams()) {
const auto& exps = ctx->funcRParams()->exp();
for (size_t i = 0; i < exps.size(); ++i) {
ir::Value* arg = EvalExpr(*exps[i]);
if (i < arg_types.size()) {
arg = CastValue(*this, builder_, module_, arg, arg_types[i]->GetType());
}
args.push_back(arg);
}
}
return static_cast<ir::Value*>(
builder_.CreateCall(target_func, args,
target_func->GetType()->IsVoid()
? ""
: module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitNotExp(SysYParser::NotExpContext* ctx) {
ir::Value* val = EvalExpr(*ctx->exp());
if (auto* cv = dynamic_cast<ir::ConstantValue*>(val)) {
return static_cast<ir::Value*>(
module_.GetContext().GetConstInt(IsTruthy(cv) ? 0 : 1));
}
ir::Value* cond = ToI1(val);
ir::Value* res =
builder_.CreateICmp(ir::Opcode::ICmpEQ, cond, builder_.CreateConstInt(0),
module_.GetContext().NextTemp());
return ToI32(res);
}
std::any IRGenImpl::visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) {
return EvalExpr(*ctx->exp());
}
std::any IRGenImpl::visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) {
ir::Value* val = EvalExpr(*ctx->exp());
if (auto* ci = dynamic_cast<ir::ConstantInt*>(val)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(-ci->GetValue()));
}
if (auto* cf = dynamic_cast<ir::ConstantFloat*>(val)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(-cf->GetValue()));
}
if (val->GetType()->IsFloat()) {
return static_cast<ir::Value*>(builder_.CreateFSub(
builder_.CreateConstFloat(0.0f), val, module_.GetContext().NextTemp()));
}
return static_cast<ir::Value*>(builder_.CreateSub(
builder_.CreateConstInt(0), val, module_.GetContext().NextTemp()));
}
#define DEFINE_ARITH_VISITOR(name, int_opcode, float_opcode) \
std::any IRGenImpl::visit##name##Exp(SysYParser::name##ExpContext* ctx) { \
ir::Value* lhs = EvalExpr(*ctx->exp(0)); \
ir::Value* rhs = EvalExpr(*ctx->exp(1)); \
const auto common_ty = CommonArithType(lhs, rhs); \
lhs = CastValue(*this, builder_, module_, lhs, common_ty); \
rhs = CastValue(*this, builder_, module_, rhs, common_ty); \
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) { \
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) { \
if (common_ty->IsFloat()) { \
const float lv = AsFloat(lconst); \
const float rv = AsFloat(rconst); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FAdd) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv + rv)); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FSub) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv - rv)); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FMul) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv * rv)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(rv == 0.0f ? 0.0f : lv / rv)); \
} \
const int lv = AsInt(lconst); \
const int rv = AsInt(rconst); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Add) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv + rv)); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Sub) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv - rv)); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Mul) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv * rv)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(rv == 0 ? 0 : lv / rv)); \
} \
} \
if (common_ty->IsFloat()) { \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FAdd) \
return static_cast<ir::Value*>(builder_.CreateFAdd(lhs, rhs, module_.GetContext().NextTemp())); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FSub) \
return static_cast<ir::Value*>(builder_.CreateFSub(lhs, rhs, module_.GetContext().NextTemp())); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FMul) \
return static_cast<ir::Value*>(builder_.CreateFMul(lhs, rhs, module_.GetContext().NextTemp())); \
return static_cast<ir::Value*>(builder_.CreateFDiv(lhs, rhs, module_.GetContext().NextTemp())); \
} \
return static_cast<ir::Value*>(builder_.CreateBinary(ir::Opcode::int_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
}
DEFINE_ARITH_VISITOR(Add, Add, FAdd)
DEFINE_ARITH_VISITOR(Sub, Sub, FSub)
DEFINE_ARITH_VISITOR(Mul, Mul, FMul)
DEFINE_ARITH_VISITOR(Div, Div, FDiv)
std::any IRGenImpl::visitModExp(SysYParser::ModExpContext* ctx) {
ir::Value* lhs = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(0)),
ir::Type::GetInt32Type());
ir::Value* rhs = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(1)),
ir::Type::GetInt32Type());
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) {
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) {
const int rv = AsInt(rconst);
return static_cast<ir::Value*>(
module_.GetContext().GetConstInt(rv == 0 ? 0 : AsInt(lconst) % rv));
}
}
return static_cast<ir::Value*>(
builder_.CreateMod(lhs, rhs, module_.GetContext().NextTemp()));
}
#define DEFINE_CMP_VISITOR(name, int_opcode, float_opcode, cmp_op) \
std::any IRGenImpl::visit##name##Exp(SysYParser::name##ExpContext* ctx) { \
ir::Value* lhs = EvalExpr(*ctx->exp(0)); \
ir::Value* rhs = EvalExpr(*ctx->exp(1)); \
const auto common_ty = CommonArithType(lhs, rhs); \
lhs = CastValue(*this, builder_, module_, lhs, common_ty); \
rhs = CastValue(*this, builder_, module_, rhs, common_ty); \
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) { \
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) { \
const bool result = common_ty->IsFloat() ? (AsFloat(lconst) cmp_op AsFloat(rconst)) \
: (AsInt(lconst) cmp_op AsInt(rconst)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(result ? 1 : 0)); \
} \
} \
if (common_ty->IsFloat()) { \
return static_cast<ir::Value*>(builder_.CreateFCmp(ir::Opcode::float_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
} \
return static_cast<ir::Value*>(builder_.CreateICmp(ir::Opcode::int_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
}
DEFINE_CMP_VISITOR(Lt, ICmpLT, FCmpLT, <)
DEFINE_CMP_VISITOR(Le, ICmpLE, FCmpLE, <=)
DEFINE_CMP_VISITOR(Gt, ICmpGT, FCmpGT, >)
DEFINE_CMP_VISITOR(Ge, ICmpGE, FCmpGE, >=)
DEFINE_CMP_VISITOR(Eq, ICmpEQ, FCmpEQ, ==)
DEFINE_CMP_VISITOR(Ne, ICmpNE, FCmpNE, !=)
std::any IRGenImpl::visitAndExp(SysYParser::AndExpContext* ctx) {
if (!builder_.GetInsertBlock()) {
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
if (auto* c = dynamic_cast<ir::ConstantValue*>(lhs); c && !IsTruthy(c)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(0));
}
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* rhs_bb = func_->CreateBlock("and.rhs." + suffix);
ir::BasicBlock* merge_bb = func_->CreateBlock("and.merge." + suffix);
auto* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
builder_.CreateStore(ToI32(ToI1(lhs)), res_ptr);
builder_.CreateCondBr(ToI1(lhs), rhs_bb, merge_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = EvalExpr(*ctx->exp(1));
builder_.CreateStore(ToI32(ToI1(rhs)), res_ptr);
builder_.CreateBr(merge_bb);
builder_.SetInsertPoint(merge_bb);
return static_cast<ir::Value*>(
builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitOrExp(SysYParser::OrExpContext* ctx) {
if (!builder_.GetInsertBlock()) {
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
if (auto* c = dynamic_cast<ir::ConstantValue*>(lhs); c && IsTruthy(c)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(1));
}
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* rhs_bb = func_->CreateBlock("or.rhs." + suffix);
ir::BasicBlock* merge_bb = func_->CreateBlock("or.merge." + suffix);
auto* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
builder_.CreateStore(ToI32(ToI1(lhs)), res_ptr);
builder_.CreateCondBr(ToI1(lhs), merge_bb, rhs_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = EvalExpr(*ctx->exp(1));
builder_.CreateStore(ToI32(ToI1(rhs)), res_ptr);
builder_.CreateBr(merge_bb);
builder_.SetInsertPoint(merge_bb);
return static_cast<ir::Value*>(
builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
bool IRGenImpl::IsArrayLikeDef(antlr4::ParserRuleContext* def) const {
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
return !const_def->exp().empty();
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
return !var_def->exp().empty();
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return !param->LBRACK().empty();
}
return false;
}
size_t IRGenImpl::GetArrayRank(antlr4::ParserRuleContext* def) const {
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
return const_def->exp().size();
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
return var_def->exp().size();
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return param->LBRACK().size();
}
return 0;
}
std::shared_ptr<ir::Type> IRGenImpl::GetDefType(antlr4::ParserRuleContext* def) const {
std::shared_ptr<ir::Type> ty = ir::Type::GetInt32Type();
auto apply_dims = [&](const auto& dims) {
auto result = ty;
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
if constexpr (std::is_pointer_v<typename std::decay_t<decltype(*it)>>) {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(**it);
result = ir::ArrayType::Get(result, AsInt(dim_val));
} else {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(*it);
result = ir::ArrayType::Get(result, AsInt(dim_val));
}
}
return result;
};
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
auto* decl = dynamic_cast<SysYParser::ConstDeclContext*>(const_def->parent);
ty = (decl && decl->btype() && decl->btype()->FLOAT()) ? ir::Type::GetFloatType()
: ir::Type::GetInt32Type();
return apply_dims(const_def->exp());
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
auto* decl = dynamic_cast<SysYParser::VarDeclContext*>(var_def->parent);
ty = (decl && decl->btype() && decl->btype()->FLOAT()) ? ir::Type::GetFloatType()
: ir::Type::GetInt32Type();
return apply_dims(var_def->exp());
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
ty = param->btype()->FLOAT() ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
if (param->LBRACK().empty()) return ty;
for (int i = static_cast<int>(param->exp().size()) - 1; i >= 0; --i) {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(*param->exp(i));
ty = ir::ArrayType::Get(ty, AsInt(dim_val));
}
return ty;
}
return ty;
}
ir::Value* IRGenImpl::DecayArrayPtr(SysYParser::LValueContext* ctx) {
auto* def = sema_.ResolveLValue(ctx);
if (!def) {
throw std::runtime_error(FormatError("irgen", "数组退化失败: 未绑定定义"));
}
ir::Value* base_ptr = storage_map_.at(def);
const auto base_ty = GetDefType(def);
if (dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
if (ctx->exp().empty()) return base_ptr;
ir::Value* offset = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(0)),
ir::Type::GetInt32Type());
auto cur_ty = base_ty;
for (size_t i = 1; i < ctx->exp().size(); ++i) {
if (!cur_ty->IsArray()) break;
auto arr_ty = cur_ty->GetAsArrayType();
ir::Value* stride = builder_.CreateConstInt(static_cast<int>(arr_ty->GetNumElements()));
offset = builder_.CreateMul(offset, stride, module_.GetContext().NextTemp());
offset = builder_.CreateAdd(
offset,
CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(i)),
ir::Type::GetInt32Type()),
module_.GetContext().NextTemp());
cur_ty = arr_ty->GetElementType();
}
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, {offset},
module_.GetContext().NextTemp());
}
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
for (auto* exp : ctx->exp()) {
indices.push_back(
CastValue(*this, builder_, module_, EvalExpr(*exp), ir::Type::GetInt32Type()));
}
auto cur_ty = base_ty;
while (cur_ty->IsArray()) {
cur_ty = cur_ty->GetAsArrayType()->GetElementType();
}
if (!ctx->exp().empty()) {
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
indices.push_back(builder_.CreateConstInt(0));
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
ir::Value* IRGenImpl::GetLValuePtr(SysYParser::LValueContext* ctx) {
auto* def = sema_.ResolveLValue(ctx);
if (!def) {
throw std::runtime_error(FormatError("irgen", "未定义的左值: " + ctx->ID()->getText()));
}
auto it = storage_map_.find(def);
if (it == storage_map_.end()) {
throw std::runtime_error(
FormatError("irgen",
"变量声明缺少存储槽位: " + ctx->var()->ID()->getText()));
FormatError("irgen", "左值缺少存储槽位: " + ctx->ID()->getText()));
}
return static_cast<ir::Value*>(
builder_.CreateLoad(it->second, module_.GetContext().NextTemp()));
ir::Value* base_ptr = it->second;
if (ctx->exp().empty()) return base_ptr;
if (dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return DecayArrayPtr(ctx);
}
const auto base_ty = GetDefType(def);
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
for (auto* exp : ctx->exp()) {
indices.push_back(
CastValue(*this, builder_, module_, EvalExpr(*exp), ir::Type::GetInt32Type()));
}
auto cur_ty = base_ty;
for (size_t i = 0; i < ctx->exp().size(); ++i) {
if (!cur_ty->IsArray()) {
throw std::runtime_error(FormatError("irgen", "数组下标层数超出定义"));
}
cur_ty = cur_ty->GetAsArrayType()->GetElementType();
}
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
std::any IRGenImpl::visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) {
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
ir::Value* IRGenImpl::ToI1(ir::Value* v) {
if (auto* cv = dynamic_cast<ir::ConstantValue*>(v)) {
return module_.GetContext().GetConstInt(IsTruthy(cv) ? 1 : 0);
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
ir::Value* rhs = EvalExpr(*ctx->exp(1));
return static_cast<ir::Value*>(
builder_.CreateBinary(ir::Opcode::Add, lhs, rhs,
module_.GetContext().NextTemp()));
if (auto* inst = dynamic_cast<ir::Instruction*>(v)) {
switch (inst->GetOpcode()) {
case ir::Opcode::ICmpEQ:
case ir::Opcode::ICmpNE:
case ir::Opcode::ICmpLT:
case ir::Opcode::ICmpGT:
case ir::Opcode::ICmpLE:
case ir::Opcode::ICmpGE:
case ir::Opcode::FCmpEQ:
case ir::Opcode::FCmpNE:
case ir::Opcode::FCmpLT:
case ir::Opcode::FCmpGT:
case ir::Opcode::FCmpLE:
case ir::Opcode::FCmpGE:
return v;
default:
break;
}
}
if (v->GetType()->IsFloat()) {
return builder_.CreateFCmp(ir::Opcode::FCmpNE, v, builder_.CreateConstFloat(0.0f),
module_.GetContext().NextTemp());
}
if (v->GetType()->IsInt32()) {
return builder_.CreateICmp(ir::Opcode::ICmpNE, v, builder_.CreateConstInt(0),
module_.GetContext().NextTemp());
}
return v;
}
ir::Value* IRGenImpl::ToI32(ir::Value* v) {
if (v->GetType()->IsInt32()) return v;
if (v->GetType()->IsFloat()) {
return builder_.CreateFPToSI(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
return builder_.CreateZExt(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}

View File

@@ -8,10 +8,18 @@
namespace {
std::shared_ptr<ir::Type> StorageType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
void VerifyFunctionStructure(const ir::Function& func) {
// 当前 IRGen 仍是单入口、顺序生成;这里在生成结束后补一层块终结校验。
for (const auto& bb : func.GetBlocks()) {
if (!bb || !bb->HasTerminator()) {
// If a block doesn't have a terminator, it might be an empty function or
// missing a return in a path. For SysY, we should at least have a default return for void.
// But IRGen should have handled it.
throw std::runtime_error(
FormatError("irgen", "基本块未正确终结: " +
(bb ? bb->GetName() : std::string("<null>"))));
@@ -25,63 +33,83 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
: module_(module),
sema_(sema),
func_(nullptr),
builder_(module.GetContext(), nullptr) {}
builder_(module.GetContext(), nullptr),
is_global_scope_(true) {}
// 编译单元的 IR 生成当前只实现了最小功能:
// - Module 已在 GenerateIR 中创建,这里只负责继续生成其中的内容;
// - 当前会读取编译单元中的函数定义,并交给 visitFuncDef 生成函数 IR
//
// 当前还没有实现:
// - 多个函数定义的遍历与生成;
// - 全局变量、全局常量的 IR 生成。
std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少编译单元"));
if (!ctx) return {};
is_global_scope_ = true;
for (auto* decl : ctx->decl()) {
decl->accept(this);
}
auto* func = ctx->funcDef();
if (!func) {
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
for (auto* funcDef : ctx->funcDef()) {
funcDef->accept(this);
}
func->accept(this);
return {};
}
// 函数 IR 生成当前实现了:
// 1. 获取函数名;
// 2. 检查函数返回类型;
// 3. 在 Module 中创建 Function
// 4. 将 builder 插入点设置到入口基本块;
// 5. 继续生成函数体。
//
// 当前还没有实现:
// - 通用函数返回类型处理;
// - 形参列表遍历与参数类型收集;
// - FunctionType 这样的函数类型对象;
// - Argument/形式参数 IR 对象;
// - 入口块中的参数初始化逻辑。
// ...
// 因此这里目前只支持最小的“无参 int 函数”生成。
std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
}
if (!ctx->blockStmt()) {
throw std::runtime_error(FormatError("irgen", "函数体为空"));
}
if (!ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "缺少函数名"));
}
if (!ctx->funcType() || !ctx->funcType()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持无参 int 函数"));
is_global_scope_ = false;
std::shared_ptr<ir::Type> ret_ty;
if (ctx->funcType()->INT()) {
ret_ty = ir::Type::GetInt32Type();
} else if (ctx->funcType()->FLOAT()) {
ret_ty = ir::Type::GetFloatType();
} else {
ret_ty = ir::Type::GetVoidType();
}
func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type());
builder_.SetInsertPoint(func_->GetEntry());
storage_map_.clear();
std::string func_name = ctx->ID()->getText();
std::vector<std::shared_ptr<ir::Type>> param_types;
if (ctx->funcFParams()) {
for (auto* fparam : ctx->funcFParams()->funcFParam()) {
if (fparam->LBRACK().empty()) {
param_types.push_back(fparam->btype()->INT() ? ir::Type::GetInt32Type() : ir::Type::GetFloatType());
} else {
// Array param is a pointer
param_types.push_back(fparam->btype()->INT() ? ir::Type::GetPtrInt32Type() : ir::Type::GetPtrFloatType());
}
}
}
func_ = module_.CreateFunction(func_name, ret_ty, param_types);
builder_.SetInsertPoint(func_->CreateBlock("entry"));
// Handle parameters: alloca and store
if (ctx->funcFParams()) {
const auto& fparams = ctx->funcFParams()->funcFParam();
const auto& args = func_->GetArguments();
for (size_t i = 0; i < fparams.size(); ++i) {
auto* fparam = fparams[i];
auto* arg = args[i].get();
auto* slot = builder_.CreateAlloca(StorageType(arg->GetType()), fparam->ID()->getText());
builder_.CreateStore(arg, slot);
storage_map_[fparam] = slot;
}
}
ctx->blockStmt()->accept(this);
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
// Default return for void functions if not terminated
if (!builder_.GetInsertBlock()->HasTerminator()) {
if (ret_ty->IsVoid()) {
builder_.CreateRet(nullptr);
} else if (ret_ty->IsInt32()) {
builder_.CreateRet(builder_.CreateConstInt(0));
} else if (ret_ty->IsFloat()) {
builder_.CreateRet(builder_.CreateConstFloat(0.0f));
}
}
VerifyFunctionStructure(*func_);
is_global_scope_ = true;
return {};
}
std::any IRGenImpl::visitFuncFParam(SysYParser::FuncFParamContext* ctx) {
// We handle fparams in visitFuncDef directly.
return {};
}

View File

@@ -6,34 +6,146 @@
#include "ir/IR.h"
#include "utils/Log.h"
// 语句生成当前只实现了最小子集。
// 目前支持:
// - return <exp>;
//
// 还未支持:
// - 赋值语句
// - if / while 等控制流
// - 空语句、块语句嵌套分发之外的更多语句形态
// 语句生成
std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句"));
}
if (ctx->returnStmt()) {
return ctx->returnStmt()->accept(this);
}
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
if (!ctx) return BlockFlow::Continue;
if (ctx->assignStmt()) return ctx->assignStmt()->accept(this);
if (ctx->returnStmt()) return ctx->returnStmt()->accept(this);
if (ctx->blockStmt()) return ctx->blockStmt()->accept(this);
if (ctx->ifStmt()) return ctx->ifStmt()->accept(this);
if (ctx->whileStmt()) return ctx->whileStmt()->accept(this);
if (ctx->breakStmt()) return ctx->breakStmt()->accept(this);
if (ctx->continueStmt()) return ctx->continueStmt()->accept(this);
if (ctx->expStmt()) return ctx->expStmt()->accept(this);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
for (auto* item : ctx->blockItem()) {
if (std::any_cast<BlockFlow>(item->accept(this)) == BlockFlow::Terminated) {
return BlockFlow::Terminated;
}
}
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
if (ctx->decl()) {
ctx->decl()->accept(this);
return BlockFlow::Continue;
}
if (ctx->stmt()) {
return ctx->stmt()->accept(this);
}
return BlockFlow::Continue;
}
std::any IRGenImpl::visitAssignStmt(SysYParser::AssignStmtContext* ctx) {
ir::Value* ptr = GetLValuePtr(ctx->lValue());
ir::Value* val = EvalExpr(*ctx->exp());
if (ptr->GetType()->IsPtrFloat() && val->GetType()->IsInt32()) {
val = builder_.CreateSIToFP(val, ir::Type::GetFloatType(),
module_.GetContext().NextTemp());
} else if (ptr->GetType()->IsPtrInt32() && val->GetType()->IsFloat()) {
val = builder_.CreateFPToSI(val, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
builder_.CreateStore(val, ptr);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少 return 语句"));
if (ctx->exp()) {
ir::Value* v = EvalExpr(*ctx->exp());
if (func_->GetType()->IsFloat() && v->GetType()->IsInt32()) {
v = builder_.CreateSIToFP(v, ir::Type::GetFloatType(),
module_.GetContext().NextTemp());
} else if (func_->GetType()->IsInt32() && v->GetType()->IsFloat()) {
v = builder_.CreateFPToSI(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
builder_.CreateRet(v);
} else {
builder_.CreateRet(nullptr);
}
if (!ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
}
ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v);
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitIfStmt(SysYParser::IfStmtContext* ctx) {
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* true_bb = func_->CreateBlock("if.true." + suffix);
ir::BasicBlock* false_bb =
ctx->ELSE() ? func_->CreateBlock("if.false." + suffix) : nullptr;
ir::BasicBlock* merge_bb = func_->CreateBlock("if.merge." + suffix);
ir::Value* cond = EvalExpr(*ctx->exp());
builder_.CreateCondBr(ToI1(cond), true_bb, false_bb ? false_bb : merge_bb);
// True block
builder_.SetInsertPoint(true_bb);
if (std::any_cast<BlockFlow>(ctx->stmt(0)->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
// False block
if (false_bb) {
builder_.SetInsertPoint(false_bb);
if (std::any_cast<BlockFlow>(ctx->stmt(1)->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
}
builder_.SetInsertPoint(merge_bb);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitWhileStmt(SysYParser::WhileStmtContext* ctx) {
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* cond_bb = func_->CreateBlock("while.cond." + suffix);
ir::BasicBlock* body_bb = func_->CreateBlock("while.body." + suffix);
ir::BasicBlock* end_bb = func_->CreateBlock("while.end." + suffix);
builder_.CreateBr(cond_bb);
builder_.SetInsertPoint(cond_bb);
ir::Value* cond = EvalExpr(*ctx->exp());
builder_.CreateCondBr(ToI1(cond), body_bb, end_bb);
break_stack_.push(end_bb);
continue_stack_.push(cond_bb);
builder_.SetInsertPoint(body_bb);
if (std::any_cast<BlockFlow>(ctx->stmt()->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(cond_bb);
}
break_stack_.pop();
continue_stack_.pop();
builder_.SetInsertPoint(end_bb);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBreakStmt(SysYParser::BreakStmtContext* ctx) {
if (break_stack_.empty()) {
throw std::runtime_error(FormatError("irgen", "break 语句不在循环内"));
}
builder_.CreateBr(break_stack_.top());
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitContinueStmt(SysYParser::ContinueStmtContext* ctx) {
if (continue_stack_.empty()) {
throw std::runtime_error(FormatError("irgen", "continue 语句不在循环内"));
}
builder_.CreateBr(continue_stack_.top());
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitExpStmt(SysYParser::ExpStmtContext* ctx) {
if (ctx->exp()) {
EvalExpr(*ctx->exp());
}
return BlockFlow::Continue;
}