220 lines
7.7 KiB
C++
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 {};
|
|
}
|