Complete Lab2 IR generation and document process
This commit is contained in:
@@ -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 {};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user