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 {};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user