You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
6.4 KiB

#include "irgen/IRGen.h"
#include <stdexcept>
#include "utils/Log.h"
namespace {
using ir::Type;
std::shared_ptr<Type> BuiltinFn(std::shared_ptr<Type> ret,
std::vector<std::shared_ptr<Type>> params) {
return Type::GetFunctionType(std::move(ret), std::move(params));
}
bool SameType(const std::shared_ptr<Type>& lhs, const std::shared_ptr<Type>& rhs) {
return lhs && rhs && lhs->Equals(*rhs);
}
} // namespace
IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
: module_(module),
sema_(sema),
current_return_type_(Type::GetVoidType()),
builder_(module.GetContext(), nullptr) {}
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) {
DeclareBuiltins();
GenGlobals(cu);
GenFunctionDecls(cu);
GenFunctionBodies(cu);
}
void IRGenImpl::DeclareBuiltins() {
const auto i32 = Type::GetInt32Type();
const auto f32 = Type::GetFloatType();
const auto void_ty = Type::GetVoidType();
const struct {
const char* name;
std::shared_ptr<Type> type;
} builtins[] = {
{"getint", BuiltinFn(i32, {})},
{"getch", BuiltinFn(i32, {})},
{"getfloat", BuiltinFn(f32, {})},
{"getarray", BuiltinFn(i32, {Type::GetPointerType(i32)})},
{"getfarray", BuiltinFn(i32, {Type::GetPointerType(f32)})},
{"putint", BuiltinFn(void_ty, {i32})},
{"putch", BuiltinFn(void_ty, {i32})},
{"putfloat", BuiltinFn(void_ty, {f32})},
{"putarray", BuiltinFn(void_ty, {i32, Type::GetPointerType(i32)})},
{"putfarray", BuiltinFn(void_ty, {i32, Type::GetPointerType(f32)})},
{"starttime", BuiltinFn(void_ty, {})},
{"stoptime", BuiltinFn(void_ty, {})},
};
for (const auto& builtin : builtins) {
if (!module_.FindFunction(builtin.name)) {
module_.CreateFunction(builtin.name, builtin.type, true);
}
}
}
void IRGenImpl::GenFunctionDecls(SysYParser::CompUnitContext& cu) {
for (auto* func : cu.funcDef()) {
if (!func || !func->Ident()) {
continue;
}
auto* symbol = sema_.ResolveFuncDef(func);
if (!symbol) {
throw std::runtime_error(FormatError("irgen", "缺少函数语义信息"));
}
auto* ir_func = module_.FindFunction(symbol->name);
if (ir_func) {
continue;
}
ir_func = module_.CreateFunction(symbol->name, symbol->type, false);
const auto& params = symbol->type->GetParamTypes();
for (size_t i = 0; i < params.size(); ++i) {
ir_func->AddArgument(params[i], "%arg" + std::to_string(i));
}
}
}
void IRGenImpl::GenFunctionBodies(SysYParser::CompUnitContext& cu) {
for (auto* func : cu.funcDef()) {
if (func) {
GenFuncDef(*func);
}
}
}
void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
auto* symbol = sema_.ResolveFuncDef(&func);
if (!symbol) {
throw std::runtime_error(FormatError("irgen", "函数缺少语义绑定"));
}
current_function_ = module_.FindFunction(symbol->name);
if (!current_function_) {
throw std::runtime_error(FormatError("irgen", "函数声明缺失: " + symbol->name));
}
current_return_type_ = symbol->type->GetReturnType();
auto* entry = current_function_->CreateBlock("entry");
auto* body = current_function_->CreateBlock("entry.body");
builder_.SetInsertPoint(body);
local_scopes_.clear();
break_targets_.clear();
continue_targets_.clear();
EnterScope();
if (auto* params = func.funcFParams()) {
const auto& args = current_function_->GetArguments();
for (size_t i = 0; i < params->funcFParam().size(); ++i) {
auto* param = params->funcFParam(i);
const auto* arg = args.at(i).get();
const std::string name = param->Ident()->getText();
auto* slot = builder_.CreateAlloca(arg->GetType(), module_.GetContext().NextTemp());
builder_.CreateStore(const_cast<ir::Argument*>(arg), slot);
DeclareLocal(name, {slot, arg->GetType(), !param->L_BRACK().empty(), false, false});
}
}
GenBlock(*func.block());
ExitScope();
ir::IRBuilder entry_builder(module_.GetContext(), entry);
entry_builder.CreateBr(body);
if (builder_.GetInsertBlock() && !builder_.GetInsertBlock()->HasTerminator()) {
if (current_return_type_->IsVoid()) {
builder_.CreateRetVoid();
} else if (current_return_type_->IsFloat32()) {
builder_.CreateRet(builder_.CreateConstFloat(0.0f));
} else {
builder_.CreateRet(builder_.CreateConstInt(0));
}
}
}
void IRGenImpl::EnterScope() { local_scopes_.emplace_back(); }
void IRGenImpl::ExitScope() {
if (!local_scopes_.empty()) {
local_scopes_.pop_back();
}
}
void IRGenImpl::EnsureInsertableBlock() {
if (!builder_.GetInsertBlock()) {
auto* block = current_function_->CreateBlock(module_.GetContext().NextBlock("dead"));
builder_.SetInsertPoint(block);
return;
}
if (builder_.GetInsertBlock()->HasTerminator()) {
auto* block = current_function_->CreateBlock(module_.GetContext().NextBlock("dead"));
builder_.SetInsertPoint(block);
}
}
void IRGenImpl::DeclareLocal(const std::string& name, StorageEntry entry) {
if (local_scopes_.empty()) {
EnterScope();
}
local_scopes_.back()[name] = std::move(entry);
}
IRGenImpl::StorageEntry* IRGenImpl::LookupStorage(const std::string& name) {
for (auto it = local_scopes_.rbegin(); it != local_scopes_.rend(); ++it) {
auto found = it->find(name);
if (found != it->end()) {
return &found->second;
}
}
auto global = globals_.find(name);
return global == globals_.end() ? nullptr : &global->second;
}
const IRGenImpl::StorageEntry* IRGenImpl::LookupStorage(const std::string& name) const {
for (auto it = local_scopes_.rbegin(); it != local_scopes_.rend(); ++it) {
auto found = it->find(name);
if (found != it->end()) {
return &found->second;
}
}
auto global = globals_.find(name);
return global == globals_.end() ? nullptr : &global->second;
}
size_t IRGenImpl::CountScalars(const std::shared_ptr<Type>& type) const {
if (!type->IsArray()) {
return 1;
}
return type->GetArraySize() * CountScalars(type->GetElementType());
}
std::vector<int> IRGenImpl::FlatIndexToIndices(const std::shared_ptr<Type>& type,
size_t flat_index) const {
if (!type->IsArray()) {
return {};
}
size_t inner = CountScalars(type->GetElementType());
int current = static_cast<int>(flat_index / inner);
auto tail = FlatIndexToIndices(type->GetElementType(), flat_index % inner);
tail.insert(tail.begin(), current);
return tail;
}