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 {};
}