Files
nudt-compiler-cpp/src/irgen/IRGenDecl.cpp

220 lines
7.7 KiB
C++

#include "irgen/IRGen.h"
#include <stdexcept>
#include <vector>
#include "SysYParser.h"
#include "ir/IR.h"
#include "utils/Log.h"
namespace {
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
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;
}
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()));
}
}
slot = module_.CreateGlobalValue(name, StorageType(ty), init);
} else {
slot = builder_.CreateAlloca(StorageType(ty), name);
ZeroInitializeLocal(slot, ty);
EmitLocalInitValue(slot, ty, ctx->initValue());
}
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);
if (ctx->initValue()) {
ZeroInitializeLocal(slot, ty);
EmitLocalInitValue(slot, ty, ctx->initValue());
}
}
storage_map_[ctx] = slot;
return {};
}