|
|
|
|
@ -69,22 +69,59 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
|
|
|
|
|
}
|
|
|
|
|
if (!ctx->block()) {
|
|
|
|
|
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 函数"));
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<ir::Type> ret_type;
|
|
|
|
|
if (ctx->funcType()->INT()) {
|
|
|
|
|
ret_type = ir::Type::GetInt32Type();
|
|
|
|
|
} else if (ctx->funcType()->FLOAT()) {
|
|
|
|
|
ret_type = ir::Type::GetFloatType();
|
|
|
|
|
} else if (ctx->funcType()->VOID()) {
|
|
|
|
|
ret_type = ir::Type::GetVoidType();
|
|
|
|
|
} else {
|
|
|
|
|
throw std::runtime_error(FormatError("irgen", "未知的函数返回类型"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type());
|
|
|
|
|
func_ = module_.CreateFunction(ctx->ID()->getText(), ret_type);
|
|
|
|
|
builder_.SetInsertPoint(func_->GetEntry());
|
|
|
|
|
storage_map_.clear();
|
|
|
|
|
|
|
|
|
|
ctx->block()->accept(this);
|
|
|
|
|
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
|
|
|
|
|
if (ctx->funcFParams()) {
|
|
|
|
|
for (auto* paramCtx : ctx->funcFParams()->funcFParam()) {
|
|
|
|
|
std::shared_ptr<ir::Type> param_type;
|
|
|
|
|
bool is_array = !paramCtx->LBRACK().empty();
|
|
|
|
|
|
|
|
|
|
if (paramCtx->bType()->INT()) {
|
|
|
|
|
param_type = is_array ? ir::Type::GetPtrInt32Type() : ir::Type::GetInt32Type();
|
|
|
|
|
} else if (paramCtx->bType()->FLOAT()) {
|
|
|
|
|
param_type = is_array ? ir::Type::GetPtrFloatType() : ir::Type::GetFloatType();
|
|
|
|
|
} else {
|
|
|
|
|
throw std::runtime_error(FormatError("irgen", "未知的参数类型"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string arg_name = paramCtx->ID()->getText();
|
|
|
|
|
auto* arg = func_->AddArgument(param_type, "%arg" + std::to_string(func_->GetArgs().size()));
|
|
|
|
|
|
|
|
|
|
ir::Instruction* alloca_inst;
|
|
|
|
|
if (param_type->IsInt32() || param_type->IsPtrInt32()) {
|
|
|
|
|
alloca_inst = builder_.CreateAllocaI32(arg_name + ".addr");
|
|
|
|
|
} else {
|
|
|
|
|
alloca_inst = builder_.CreateAllocaFloat(arg_name + ".addr");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder_.CreateStore(arg, alloca_inst);
|
|
|
|
|
storage_map_[arg_name] = alloca_inst;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx->blockStmt()->accept(this);
|
|
|
|
|
|
|
|
|
|
VerifyFunctionStructure(*func_);
|
|
|
|
|
func_ = nullptr;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|