Complete Lab2 IR generation and document process
This commit is contained in:
@@ -15,7 +15,7 @@ namespace ir {
|
||||
|
||||
// 当前 BasicBlock 还没有专门的 label type,因此先用 void 作为占位类型。
|
||||
BasicBlock::BasicBlock(std::string name)
|
||||
: Value(Type::GetVoidType(), std::move(name)) {}
|
||||
: Value(Type::GetLabelType(), std::move(name)) {}
|
||||
|
||||
Function* BasicBlock::GetParent() const { return parent_; }
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ add_library(ir_core STATIC
|
||||
Module.cpp
|
||||
Function.cpp
|
||||
BasicBlock.cpp
|
||||
GlobalValue.cpp
|
||||
Type.cpp
|
||||
Value.cpp
|
||||
Instruction.cpp
|
||||
|
||||
@@ -15,10 +15,18 @@ ConstantInt* Context::GetConstInt(int v) {
|
||||
return inserted->second.get();
|
||||
}
|
||||
|
||||
ConstantFloat* Context::GetConstFloat(float v) {
|
||||
auto it = const_floats_.find(v);
|
||||
if (it != const_floats_.end()) return it->second.get();
|
||||
auto inserted =
|
||||
const_floats_
|
||||
.emplace(v, std::make_unique<ConstantFloat>(Type::GetFloatType(), v))
|
||||
.first;
|
||||
return inserted->second.get();
|
||||
}
|
||||
|
||||
std::string Context::NextTemp() {
|
||||
std::ostringstream oss;
|
||||
oss << "%" << ++temp_index_;
|
||||
return oss.str();
|
||||
return "t" + std::to_string(++temp_index_);
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -5,9 +5,14 @@
|
||||
|
||||
namespace ir {
|
||||
|
||||
Function::Function(std::string name, std::shared_ptr<Type> ret_type)
|
||||
Function::Function(std::string name, std::shared_ptr<Type> ret_type,
|
||||
std::vector<std::shared_ptr<Type>> param_types)
|
||||
: Value(std::move(ret_type), std::move(name)) {
|
||||
entry_ = CreateBlock("entry");
|
||||
for (size_t i = 0; i < param_types.size(); ++i) {
|
||||
arguments_.push_back(std::make_unique<Argument>(
|
||||
param_types[i], "a" + std::to_string(i), this,
|
||||
static_cast<unsigned>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock* Function::CreateBlock(const std::string& name) {
|
||||
@@ -29,4 +34,8 @@ const std::vector<std::unique_ptr<BasicBlock>>& Function::GetBlocks() const {
|
||||
return blocks_;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<Argument>>& Function::GetArguments() const {
|
||||
return arguments_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace ir {
|
||||
|
||||
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name)
|
||||
: User(std::move(ty), std::move(name)) {}
|
||||
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name, ConstantValue* init)
|
||||
: User(std::move(ty), std::move(name)), init_(init) {}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -21,6 +21,11 @@ ConstantInt* IRBuilder::CreateConstInt(int v) {
|
||||
return ctx_.GetConstInt(v);
|
||||
}
|
||||
|
||||
ConstantFloat* IRBuilder::CreateConstFloat(float v) {
|
||||
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
|
||||
return ctx_.GetConstFloat(v);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
@@ -42,11 +47,74 @@ BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
|
||||
return CreateBinary(Opcode::Add, lhs, rhs, name);
|
||||
}
|
||||
|
||||
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
||||
BinaryInst* IRBuilder::CreateSub(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Sub, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateMul(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Mul, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateDiv(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Div, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateMod(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Mod, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateFAdd(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::FAdd, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateFSub(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::FSub, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateFMul(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::FMul, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateFDiv(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::FDiv, lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateICmp(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<AllocaInst>(Type::GetPtrInt32Type(), name);
|
||||
return insert_block_->Append<BinaryInst>(op, Type::GetInt32Type(), lhs, rhs,
|
||||
name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateFCmp(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<BinaryInst>(op, Type::GetInt32Type(), lhs, rhs,
|
||||
name);
|
||||
}
|
||||
|
||||
AllocaInst* IRBuilder::CreateAlloca(std::shared_ptr<Type> ty,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<AllocaInst>(ty, name);
|
||||
}
|
||||
|
||||
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
||||
return CreateAlloca(Type::GetPtrInt32Type(), name);
|
||||
}
|
||||
|
||||
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
|
||||
@@ -57,7 +125,15 @@ LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateLoad 缺少 ptr"));
|
||||
}
|
||||
return insert_block_->Append<LoadInst>(Type::GetInt32Type(), ptr, name);
|
||||
std::shared_ptr<Type> val_ty;
|
||||
if (ptr->GetType()->IsPtrInt32()) {
|
||||
val_ty = Type::GetInt32Type();
|
||||
} else if (ptr->GetType()->IsPtrFloat()) {
|
||||
val_ty = Type::GetFloatType();
|
||||
} else {
|
||||
throw std::runtime_error(FormatError("ir", "LoadInst 不支持的指针类型"));
|
||||
}
|
||||
return insert_block_->Append<LoadInst>(val_ty, ptr, name);
|
||||
}
|
||||
|
||||
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
|
||||
@@ -79,11 +155,63 @@ ReturnInst* IRBuilder::CreateRet(Value* v) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
if (!v) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateRet 缺少返回值"));
|
||||
}
|
||||
return insert_block_->Append<ReturnInst>(Type::GetVoidType(), v);
|
||||
}
|
||||
|
||||
BranchInst* IRBuilder::CreateBr(BasicBlock* dest) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<BranchInst>(dest);
|
||||
}
|
||||
|
||||
BranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* if_true,
|
||||
BasicBlock* if_false) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<BranchInst>(cond, if_true, if_false);
|
||||
}
|
||||
|
||||
CallInst* IRBuilder::CreateCall(Function* func, const std::vector<Value*>& args,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<CallInst>(func, args, name);
|
||||
}
|
||||
|
||||
GetElementPtrInst* IRBuilder::CreateGEP(std::shared_ptr<Type> ptr_ty, Value* ptr,
|
||||
const std::vector<Value*>& indices,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<GetElementPtrInst>(ptr_ty, ptr, indices, name);
|
||||
}
|
||||
|
||||
CastInst* IRBuilder::CreateZExt(Value* val, std::shared_ptr<Type> ty,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<CastInst>(Opcode::ZExt, ty, val, name);
|
||||
}
|
||||
|
||||
CastInst* IRBuilder::CreateSIToFP(Value* val, std::shared_ptr<Type> ty,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<CastInst>(Opcode::SIToFP, ty, val, name);
|
||||
}
|
||||
|
||||
CastInst* IRBuilder::CreateFPToSI(Value* val, std::shared_ptr<Type> ty,
|
||||
const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<CastInst>(Opcode::FPToSI, ty, val, name);
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -12,7 +16,7 @@
|
||||
|
||||
namespace ir {
|
||||
|
||||
static const char* TypeToString(const Type& ty) {
|
||||
static std::string TypeToString(const Type& ty) {
|
||||
switch (ty.GetKind()) {
|
||||
case Type::Kind::Void:
|
||||
return "void";
|
||||
@@ -20,11 +24,22 @@ static const char* TypeToString(const Type& ty) {
|
||||
return "i32";
|
||||
case Type::Kind::PtrInt32:
|
||||
return "i32*";
|
||||
case Type::Kind::Float:
|
||||
return "float";
|
||||
case Type::Kind::PtrFloat:
|
||||
return "float*";
|
||||
case Type::Kind::Label:
|
||||
return "label";
|
||||
case Type::Kind::Array: {
|
||||
const auto* arr_ty = static_cast<const ArrayType*>(&ty);
|
||||
return "[" + std::to_string(arr_ty->GetNumElements()) + " x " +
|
||||
TypeToString(*arr_ty->GetElementType()) + "]";
|
||||
}
|
||||
}
|
||||
throw std::runtime_error(FormatError("ir", "未知类型"));
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static const char* OpcodeToString(Opcode op) {
|
||||
static std::string OpcodeToString(Opcode op) {
|
||||
switch (op) {
|
||||
case Opcode::Add:
|
||||
return "add";
|
||||
@@ -32,6 +47,42 @@ static const char* OpcodeToString(Opcode op) {
|
||||
return "sub";
|
||||
case Opcode::Mul:
|
||||
return "mul";
|
||||
case Opcode::Div:
|
||||
return "sdiv";
|
||||
case Opcode::Mod:
|
||||
return "srem";
|
||||
case Opcode::FAdd:
|
||||
return "fadd";
|
||||
case Opcode::FSub:
|
||||
return "fsub";
|
||||
case Opcode::FMul:
|
||||
return "fmul";
|
||||
case Opcode::FDiv:
|
||||
return "fdiv";
|
||||
case Opcode::ICmpEQ:
|
||||
return "icmp eq";
|
||||
case Opcode::ICmpNE:
|
||||
return "icmp ne";
|
||||
case Opcode::ICmpLT:
|
||||
return "icmp slt";
|
||||
case Opcode::ICmpGT:
|
||||
return "icmp sgt";
|
||||
case Opcode::ICmpLE:
|
||||
return "icmp sle";
|
||||
case Opcode::ICmpGE:
|
||||
return "icmp sge";
|
||||
case Opcode::FCmpEQ:
|
||||
return "fcmp oeq";
|
||||
case Opcode::FCmpNE:
|
||||
return "fcmp une";
|
||||
case Opcode::FCmpLT:
|
||||
return "fcmp olt";
|
||||
case Opcode::FCmpGT:
|
||||
return "fcmp ogt";
|
||||
case Opcode::FCmpLE:
|
||||
return "fcmp ole";
|
||||
case Opcode::FCmpGE:
|
||||
return "fcmp oge";
|
||||
case Opcode::Alloca:
|
||||
return "alloca";
|
||||
case Opcode::Load:
|
||||
@@ -40,21 +91,114 @@ static const char* OpcodeToString(Opcode op) {
|
||||
return "store";
|
||||
case Opcode::Ret:
|
||||
return "ret";
|
||||
case Opcode::Br:
|
||||
return "br";
|
||||
case Opcode::Call:
|
||||
return "call";
|
||||
case Opcode::GEP:
|
||||
return "getelementptr";
|
||||
case Opcode::ZExt:
|
||||
return "zext";
|
||||
case Opcode::SIToFP:
|
||||
return "sitofp";
|
||||
case Opcode::FPToSI:
|
||||
return "fptosi";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static std::string ValueToString(const Value* v) {
|
||||
if (!v) return "<null>";
|
||||
if (auto* ci = dynamic_cast<const ConstantInt*>(v)) {
|
||||
return std::to_string(ci->GetValue());
|
||||
}
|
||||
return v ? v->GetName() : "<null>";
|
||||
if (auto* cf = dynamic_cast<const ConstantFloat*>(v)) {
|
||||
const double as_double = static_cast<double>(cf->GetValue());
|
||||
uint64_t bits = 0;
|
||||
std::memcpy(&bits, &as_double, sizeof(bits));
|
||||
std::ostringstream oss;
|
||||
oss << "0x" << std::hex << std::uppercase << std::setw(16)
|
||||
<< std::setfill('0') << bits;
|
||||
return oss.str();
|
||||
}
|
||||
if (v->IsGlobalValue() || v->IsFunction()) {
|
||||
return "@" + v->GetName();
|
||||
}
|
||||
if (v->IsInstruction() || v->IsArgument() || v->GetType()->IsLabel()) {
|
||||
return "%" + v->GetName();
|
||||
}
|
||||
return v->GetName();
|
||||
}
|
||||
|
||||
static bool IsBoolLikeValue(const Value* v) {
|
||||
if (auto* inst = dynamic_cast<const Instruction*>(v)) {
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::ICmpEQ:
|
||||
case Opcode::ICmpNE:
|
||||
case Opcode::ICmpLT:
|
||||
case Opcode::ICmpGT:
|
||||
case Opcode::ICmpLE:
|
||||
case Opcode::ICmpGE:
|
||||
case Opcode::FCmpEQ:
|
||||
case Opcode::FCmpNE:
|
||||
case Opcode::FCmpLT:
|
||||
case Opcode::FCmpGT:
|
||||
case Opcode::FCmpLE:
|
||||
case Opcode::FCmpGE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string PrintedValueType(const Value* v) {
|
||||
if (IsBoolLikeValue(v)) return "i1";
|
||||
return TypeToString(*v->GetType());
|
||||
}
|
||||
|
||||
void IRPrinter::Print(const Module& module, std::ostream& os) {
|
||||
// Print global variables
|
||||
for (const auto& gv : module.GetGlobalValues()) {
|
||||
os << "@" << gv->GetName() << " = global ";
|
||||
if (gv->GetType()->IsPtrInt32()) {
|
||||
os << "i32";
|
||||
} else if (gv->GetType()->IsPtrFloat()) {
|
||||
os << "float";
|
||||
} else {
|
||||
os << TypeToString(*gv->GetType());
|
||||
}
|
||||
if (gv->GetInitializer()) {
|
||||
os << " " << ValueToString(gv->GetInitializer());
|
||||
} else {
|
||||
os << " zeroinitializer";
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
if (!module.GetGlobalValues().empty()) os << "\n";
|
||||
|
||||
for (const auto& func : module.GetFunctions()) {
|
||||
if (func->GetBlocks().empty()) {
|
||||
os << "declare " << TypeToString(*func->GetType()) << " @" << func->GetName()
|
||||
<< "(";
|
||||
// For declarations, we just need types. But Argument objects might exist.
|
||||
const auto& args = func->GetArguments();
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
os << TypeToString(*args[i]->GetType());
|
||||
if (i + 1 < args.size()) os << ", ";
|
||||
}
|
||||
os << ")\n\n";
|
||||
continue;
|
||||
}
|
||||
os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName()
|
||||
<< "() {\n";
|
||||
<< "(";
|
||||
const auto& args = func->GetArguments();
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
os << TypeToString(*args[i]->GetType()) << " %" << args[i]->GetName();
|
||||
if (i + 1 < args.size()) os << ", ";
|
||||
}
|
||||
os << ") {\n";
|
||||
for (const auto& bb : func->GetBlocks()) {
|
||||
if (!bb) {
|
||||
continue;
|
||||
@@ -65,36 +209,142 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::Add:
|
||||
case Opcode::Sub:
|
||||
case Opcode::Mul: {
|
||||
case Opcode::Mul:
|
||||
case Opcode::Div:
|
||||
case Opcode::Mod:
|
||||
case Opcode::FAdd:
|
||||
case Opcode::FSub:
|
||||
case Opcode::FMul:
|
||||
case Opcode::FDiv: {
|
||||
auto* bin = static_cast<const BinaryInst*>(inst);
|
||||
os << " " << bin->GetName() << " = "
|
||||
os << " %" << bin->GetName() << " = "
|
||||
<< OpcodeToString(bin->GetOpcode()) << " "
|
||||
<< TypeToString(*bin->GetLhs()->GetType()) << " "
|
||||
<< PrintedValueType(bin->GetLhs()) << " "
|
||||
<< ValueToString(bin->GetLhs()) << ", "
|
||||
<< ValueToString(bin->GetRhs()) << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::ICmpEQ:
|
||||
case Opcode::ICmpNE:
|
||||
case Opcode::ICmpLT:
|
||||
case Opcode::ICmpGT:
|
||||
case Opcode::ICmpLE:
|
||||
case Opcode::ICmpGE:
|
||||
case Opcode::FCmpEQ:
|
||||
case Opcode::FCmpNE:
|
||||
case Opcode::FCmpLT:
|
||||
case Opcode::FCmpGT:
|
||||
case Opcode::FCmpLE:
|
||||
case Opcode::FCmpGE: {
|
||||
auto* bin = static_cast<const BinaryInst*>(inst);
|
||||
os << " %" << bin->GetName() << " = "
|
||||
<< OpcodeToString(bin->GetOpcode()) << " "
|
||||
<< PrintedValueType(bin->GetLhs()) << " "
|
||||
<< ValueToString(bin->GetLhs()) << ", "
|
||||
<< ValueToString(bin->GetRhs()) << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::Alloca: {
|
||||
auto* alloca = static_cast<const AllocaInst*>(inst);
|
||||
os << " " << alloca->GetName() << " = alloca i32\n";
|
||||
os << " %" << alloca->GetName() << " = alloca ";
|
||||
if (alloca->GetType()->IsPtrInt32())
|
||||
os << "i32";
|
||||
else if (alloca->GetType()->IsPtrFloat())
|
||||
os << "float";
|
||||
else
|
||||
os << TypeToString(*alloca->GetType());
|
||||
os << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::Load: {
|
||||
auto* load = static_cast<const LoadInst*>(inst);
|
||||
os << " " << load->GetName() << " = load i32, i32* "
|
||||
os << " %" << load->GetName() << " = load "
|
||||
<< TypeToString(*load->GetType()) << ", "
|
||||
<< TypeToString(*load->GetPtr()->GetType()) << " "
|
||||
<< ValueToString(load->GetPtr()) << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::Store: {
|
||||
auto* store = static_cast<const StoreInst*>(inst);
|
||||
os << " store i32 " << ValueToString(store->GetValue())
|
||||
<< ", i32* " << ValueToString(store->GetPtr()) << "\n";
|
||||
os << " store " << TypeToString(*store->GetValue()->GetType())
|
||||
<< " " << ValueToString(store->GetValue()) << ", "
|
||||
<< TypeToString(*store->GetPtr()->GetType()) << " "
|
||||
<< ValueToString(store->GetPtr()) << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::Ret: {
|
||||
auto* ret = static_cast<const ReturnInst*>(inst);
|
||||
os << " ret " << TypeToString(*ret->GetValue()->GetType()) << " "
|
||||
<< ValueToString(ret->GetValue()) << "\n";
|
||||
os << " ret ";
|
||||
if (ret->GetValue()) {
|
||||
os << TypeToString(*ret->GetValue()->GetType()) << " "
|
||||
<< ValueToString(ret->GetValue());
|
||||
} else {
|
||||
os << "void";
|
||||
}
|
||||
os << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::Br: {
|
||||
auto* br = static_cast<const BranchInst*>(inst);
|
||||
if (br->IsConditional()) {
|
||||
os << " br i1 " << ValueToString(br->GetCondition())
|
||||
<< ", label " << ValueToString(br->GetIfTrue()) << ", label "
|
||||
<< ValueToString(br->GetIfFalse()) << "\n";
|
||||
} else {
|
||||
os << " br label " << ValueToString(br->GetDest()) << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcode::Call: {
|
||||
auto* call = static_cast<const CallInst*>(inst);
|
||||
auto* func = call->GetFunction();
|
||||
if (!call->GetType()->IsVoid()) {
|
||||
os << " %" << call->GetName() << " = ";
|
||||
} else {
|
||||
os << " ";
|
||||
}
|
||||
os << "call " << TypeToString(*call->GetType()) << " "
|
||||
<< ValueToString(func) << "(";
|
||||
for (size_t i = 1; i < call->GetNumOperands(); ++i) {
|
||||
auto* arg = call->GetOperand(i);
|
||||
os << PrintedValueType(arg) << " " << ValueToString(arg);
|
||||
if (i + 1 < call->GetNumOperands()) os << ", ";
|
||||
}
|
||||
os << ")\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::GEP: {
|
||||
auto* gep = static_cast<const GetElementPtrInst*>(inst);
|
||||
os << " %" << gep->GetName() << " = getelementptr ";
|
||||
if (gep->GetPtr()->GetType()->IsPtrInt32())
|
||||
os << "i32";
|
||||
else if (gep->GetPtr()->GetType()->IsPtrFloat())
|
||||
os << "float";
|
||||
else
|
||||
os << TypeToString(*gep->GetPtr()->GetType());
|
||||
os << ", ";
|
||||
if (gep->GetPtr()->GetType()->IsArray()) {
|
||||
os << TypeToString(*gep->GetPtr()->GetType()) << "* ";
|
||||
} else {
|
||||
os << TypeToString(*gep->GetPtr()->GetType()) << " ";
|
||||
}
|
||||
os << ValueToString(gep->GetPtr());
|
||||
for (size_t i = 1; i < gep->GetNumOperands(); ++i) {
|
||||
os << ", " << TypeToString(*gep->GetOperand(i)->GetType()) << " "
|
||||
<< ValueToString(gep->GetOperand(i));
|
||||
}
|
||||
os << "\n";
|
||||
break;
|
||||
}
|
||||
case Opcode::ZExt:
|
||||
case Opcode::SIToFP:
|
||||
case Opcode::FPToSI: {
|
||||
auto* cast = static_cast<const CastInst*>(inst);
|
||||
os << " %" << cast->GetName() << " = "
|
||||
<< OpcodeToString(cast->GetOpcode()) << " "
|
||||
<< PrintedValueType(cast->GetValue()) << " "
|
||||
<< ValueToString(cast->GetValue()) << " to "
|
||||
<< TypeToString(*cast->GetType()) << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ Instruction::Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name)
|
||||
|
||||
Opcode Instruction::GetOpcode() const { return opcode_; }
|
||||
|
||||
bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; }
|
||||
bool Instruction::IsTerminator() const {
|
||||
return opcode_ == Opcode::Ret || opcode_ == Opcode::Br;
|
||||
}
|
||||
|
||||
BasicBlock* Instruction::GetParent() const { return parent_; }
|
||||
|
||||
@@ -61,22 +63,9 @@ void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
|
||||
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
|
||||
Value* rhs, std::string name)
|
||||
: Instruction(op, std::move(ty), std::move(name)) {
|
||||
if (op != Opcode::Add) {
|
||||
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add"));
|
||||
}
|
||||
if (!lhs || !rhs) {
|
||||
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数"));
|
||||
}
|
||||
if (!type_ || !lhs->GetType() || !rhs->GetType()) {
|
||||
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少类型信息"));
|
||||
}
|
||||
if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind() ||
|
||||
type_->GetKind() != lhs->GetType()->GetKind()) {
|
||||
throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配"));
|
||||
}
|
||||
if (!type_->IsInt32()) {
|
||||
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32"));
|
||||
}
|
||||
AddOperand(lhs);
|
||||
AddOperand(rhs);
|
||||
}
|
||||
@@ -85,38 +74,85 @@ Value* BinaryInst::GetLhs() const { return GetOperand(0); }
|
||||
|
||||
Value* BinaryInst::GetRhs() const { return GetOperand(1); }
|
||||
|
||||
ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
|
||||
: Instruction(Opcode::Ret, std::move(void_ty), "") {
|
||||
if (!val) {
|
||||
throw std::runtime_error(FormatError("ir", "ReturnInst 缺少返回值"));
|
||||
BranchInst::BranchInst(BasicBlock* dest)
|
||||
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
|
||||
AddOperand(dest);
|
||||
}
|
||||
|
||||
BranchInst::BranchInst(Value* cond, BasicBlock* if_true, BasicBlock* if_false)
|
||||
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
|
||||
AddOperand(cond);
|
||||
AddOperand(if_true);
|
||||
AddOperand(if_false);
|
||||
}
|
||||
|
||||
bool BranchInst::IsConditional() const { return GetNumOperands() == 3; }
|
||||
|
||||
Value* BranchInst::GetCondition() const {
|
||||
return IsConditional() ? GetOperand(0) : nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* BranchInst::GetIfTrue() const {
|
||||
return IsConditional() ? static_cast<BasicBlock*>(GetOperand(1)) : nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* BranchInst::GetIfFalse() const {
|
||||
return IsConditional() ? static_cast<BasicBlock*>(GetOperand(2)) : nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* BranchInst::GetDest() const {
|
||||
return !IsConditional() ? static_cast<BasicBlock*>(GetOperand(0)) : nullptr;
|
||||
}
|
||||
|
||||
CallInst::CallInst(Function* func, const std::vector<Value*>& args,
|
||||
std::string name)
|
||||
: Instruction(Opcode::Call, func->GetType(), std::move(name)) {
|
||||
AddOperand(func);
|
||||
for (auto* arg : args) {
|
||||
AddOperand(arg);
|
||||
}
|
||||
if (!type_ || !type_->IsVoid()) {
|
||||
throw std::runtime_error(FormatError("ir", "ReturnInst 返回类型必须为 void"));
|
||||
}
|
||||
|
||||
Function* CallInst::GetFunction() const {
|
||||
return static_cast<Function*>(GetOperand(0));
|
||||
}
|
||||
|
||||
GetElementPtrInst::GetElementPtrInst(std::shared_ptr<Type> ptr_ty, Value* ptr,
|
||||
const std::vector<Value*>& indices,
|
||||
std::string name)
|
||||
: Instruction(Opcode::GEP, std::move(ptr_ty), std::move(name)) {
|
||||
AddOperand(ptr);
|
||||
for (auto* idx : indices) {
|
||||
AddOperand(idx);
|
||||
}
|
||||
}
|
||||
|
||||
Value* GetElementPtrInst::GetPtr() const { return GetOperand(0); }
|
||||
|
||||
CastInst::CastInst(Opcode op, std::shared_ptr<Type> ty, Value* val,
|
||||
std::string name)
|
||||
: Instruction(op, std::move(ty), std::move(name)) {
|
||||
AddOperand(val);
|
||||
}
|
||||
|
||||
Value* ReturnInst::GetValue() const { return GetOperand(0); }
|
||||
Value* CastInst::GetValue() const { return GetOperand(0); }
|
||||
|
||||
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
|
||||
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) {
|
||||
if (!type_ || !type_->IsPtrInt32()) {
|
||||
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*"));
|
||||
ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
|
||||
: Instruction(Opcode::Ret, std::move(void_ty), "") {
|
||||
if (val) {
|
||||
AddOperand(val);
|
||||
}
|
||||
}
|
||||
|
||||
Value* ReturnInst::GetValue() const {
|
||||
return GetNumOperands() > 0 ? GetOperand(0) : nullptr;
|
||||
}
|
||||
|
||||
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
|
||||
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) {}
|
||||
|
||||
LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name)
|
||||
: Instruction(Opcode::Load, std::move(val_ty), std::move(name)) {
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr"));
|
||||
}
|
||||
if (!type_ || !type_->IsInt32()) {
|
||||
throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32"));
|
||||
}
|
||||
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "LoadInst 当前只支持从 i32* 加载"));
|
||||
}
|
||||
AddOperand(ptr);
|
||||
}
|
||||
|
||||
@@ -124,22 +160,6 @@ Value* LoadInst::GetPtr() const { return GetOperand(0); }
|
||||
|
||||
StoreInst::StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr)
|
||||
: Instruction(Opcode::Store, std::move(void_ty), "") {
|
||||
if (!val) {
|
||||
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 value"));
|
||||
}
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 ptr"));
|
||||
}
|
||||
if (!type_ || !type_->IsVoid()) {
|
||||
throw std::runtime_error(FormatError("ir", "StoreInst 返回类型必须为 void"));
|
||||
}
|
||||
if (!val->GetType() || !val->GetType()->IsInt32()) {
|
||||
throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32"));
|
||||
}
|
||||
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "StoreInst 当前只支持写入 i32*"));
|
||||
}
|
||||
AddOperand(val);
|
||||
AddOperand(ptr);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ Context& Module::GetContext() { return context_; }
|
||||
const Context& Module::GetContext() const { return context_; }
|
||||
|
||||
Function* Module::CreateFunction(const std::string& name,
|
||||
std::shared_ptr<Type> ret_type) {
|
||||
functions_.push_back(std::make_unique<Function>(name, std::move(ret_type)));
|
||||
std::shared_ptr<Type> ret_type,
|
||||
std::vector<std::shared_ptr<Type>> param_types) {
|
||||
functions_.push_back(std::make_unique<Function>(name, std::move(ret_type),
|
||||
std::move(param_types)));
|
||||
return functions_.back().get();
|
||||
}
|
||||
|
||||
@@ -18,4 +20,15 @@ const std::vector<std::unique_ptr<Function>>& Module::GetFunctions() const {
|
||||
return functions_;
|
||||
}
|
||||
|
||||
GlobalValue* Module::CreateGlobalValue(const std::string& name,
|
||||
std::shared_ptr<Type> ty,
|
||||
ConstantValue* init) {
|
||||
global_values_.push_back(std::make_unique<GlobalValue>(std::move(ty), name, init));
|
||||
return global_values_.back().get();
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<GlobalValue>>& Module::GetGlobalValues() const {
|
||||
return global_values_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -20,6 +20,21 @@ const std::shared_ptr<Type>& Type::GetPtrInt32Type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetFloatType() {
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Float);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetPtrFloatType() {
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::PtrFloat);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetLabelType() {
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Label);
|
||||
return type;
|
||||
}
|
||||
|
||||
Type::Kind Type::GetKind() const { return kind_; }
|
||||
|
||||
bool Type::IsVoid() const { return kind_ == Kind::Void; }
|
||||
@@ -28,4 +43,29 @@ bool Type::IsInt32() const { return kind_ == Kind::Int32; }
|
||||
|
||||
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
|
||||
|
||||
bool Type::IsFloat() const { return kind_ == Kind::Float; }
|
||||
|
||||
bool Type::IsPtrFloat() const { return kind_ == Kind::PtrFloat; }
|
||||
|
||||
bool Type::IsLabel() const { return kind_ == Kind::Label; }
|
||||
|
||||
bool Type::IsArray() const { return kind_ == Kind::Array; }
|
||||
|
||||
std::shared_ptr<class ArrayType> Type::GetAsArrayType() {
|
||||
if (IsArray()) {
|
||||
return std::static_pointer_cast<ArrayType>(shared_from_this());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ArrayType::ArrayType(std::shared_ptr<Type> element_type, uint32_t num_elements)
|
||||
: Type(Kind::Array),
|
||||
element_type_(std::move(element_type)),
|
||||
num_elements_(num_elements) {}
|
||||
|
||||
std::shared_ptr<ArrayType> ArrayType::Get(std::shared_ptr<Type> element_type,
|
||||
uint32_t num_elements) {
|
||||
return std::make_shared<ArrayType>(std::move(element_type), num_elements);
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -22,6 +22,12 @@ bool Value::IsInt32() const { return type_ && type_->IsInt32(); }
|
||||
|
||||
bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); }
|
||||
|
||||
bool Value::IsFloat() const { return type_ && type_->IsFloat(); }
|
||||
|
||||
bool Value::IsPtrFloat() const { return type_ && type_->IsPtrFloat(); }
|
||||
|
||||
bool Value::IsLabel() const { return type_ && type_->IsLabel(); }
|
||||
|
||||
bool Value::IsConstant() const {
|
||||
return dynamic_cast<const ConstantValue*>(this) != nullptr;
|
||||
}
|
||||
@@ -38,6 +44,14 @@ bool Value::IsFunction() const {
|
||||
return dynamic_cast<const Function*>(this) != nullptr;
|
||||
}
|
||||
|
||||
bool Value::IsGlobalValue() const {
|
||||
return dynamic_cast<const GlobalValue*>(this) != nullptr;
|
||||
}
|
||||
|
||||
bool Value::IsArgument() const {
|
||||
return dynamic_cast<const Argument*>(this) != nullptr;
|
||||
}
|
||||
|
||||
void Value::AddUse(User* user, size_t operand_index) {
|
||||
if (!user) return;
|
||||
uses_.push_back(Use(this, user, operand_index));
|
||||
@@ -74,10 +88,27 @@ void Value::ReplaceAllUsesWith(Value* new_value) {
|
||||
}
|
||||
}
|
||||
|
||||
Argument::Argument(std::shared_ptr<Type> ty, std::string name, Function* parent,
|
||||
unsigned arg_no)
|
||||
: Value(std::move(ty), std::move(name)),
|
||||
parent_(parent),
|
||||
arg_no_(arg_no) {}
|
||||
|
||||
ConstantValue::ConstantValue(std::shared_ptr<Type> ty, std::string name)
|
||||
: Value(std::move(ty), std::move(name)) {}
|
||||
|
||||
ConstantInt::ConstantInt(std::shared_ptr<Type> ty, int v)
|
||||
: ConstantValue(std::move(ty), ""), value_(v) {}
|
||||
|
||||
ConstantFloat::ConstantFloat(std::shared_ptr<Type> ty, float v)
|
||||
: ConstantValue(std::move(ty), ""), value_(v) {}
|
||||
|
||||
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name,
|
||||
ConstantValue* init)
|
||||
: User(std::move(ty), std::move(name)), init_(init) {
|
||||
if (init_) {
|
||||
AddOperand(init_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
398
src/sem/Sema.cpp
398
src/sem/Sema.cpp
@@ -10,185 +10,321 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
|
||||
if (!lvalue.ID()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法左值"));
|
||||
}
|
||||
return lvalue.ID()->getText();
|
||||
}
|
||||
|
||||
class SemaVisitor final : public SysYBaseVisitor {
|
||||
public:
|
||||
explicit SemaVisitor() {
|
||||
// 预填标准库函数
|
||||
AddBuiltin("getint", Symbol::Kind::Function);
|
||||
AddBuiltin("getch", Symbol::Kind::Function);
|
||||
AddBuiltin("getfloat", Symbol::Kind::Function);
|
||||
AddBuiltin("getarray", Symbol::Kind::Function);
|
||||
AddBuiltin("getfarray", Symbol::Kind::Function);
|
||||
AddBuiltin("putint", Symbol::Kind::Function);
|
||||
AddBuiltin("putch", Symbol::Kind::Function);
|
||||
AddBuiltin("putfloat", Symbol::Kind::Function);
|
||||
AddBuiltin("putarray", Symbol::Kind::Function);
|
||||
AddBuiltin("putfarray", Symbol::Kind::Function);
|
||||
AddBuiltin("starttime", Symbol::Kind::Function);
|
||||
AddBuiltin("stoptime", Symbol::Kind::Function);
|
||||
AddBuiltin("putf", Symbol::Kind::Function);
|
||||
}
|
||||
|
||||
private:
|
||||
void AddBuiltin(const std::string& name, Symbol::Kind kind) {
|
||||
Symbol sym;
|
||||
sym.kind = kind;
|
||||
sym.def_ctx = nullptr; // 内建函数没有语法树节点
|
||||
table_.Add(name, sym);
|
||||
}
|
||||
|
||||
std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少编译单元"));
|
||||
if (!ctx) return {};
|
||||
for (auto* child : ctx->children) {
|
||||
if (auto* decl = dynamic_cast<SysYParser::DeclContext*>(child)) {
|
||||
decl->accept(this);
|
||||
} else if (auto* funcDef = dynamic_cast<SysYParser::FuncDefContext*>(child)) {
|
||||
funcDef->accept(this);
|
||||
}
|
||||
}
|
||||
auto* func = ctx->funcDef();
|
||||
if (!func || !func->blockStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitDecl(SysYParser::DeclContext* ctx) override {
|
||||
if (ctx->constDecl()) return ctx->constDecl()->accept(this);
|
||||
if (ctx->varDecl()) return ctx->varDecl()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitConstDecl(SysYParser::ConstDeclContext* ctx) override {
|
||||
for (auto* def : ctx->constDef()) {
|
||||
const std::string name = def->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义常量: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Constant;
|
||||
sym.def_ctx = def;
|
||||
sym.is_const = true;
|
||||
sym.is_array = !def->exp().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : def->exp()) exp->accept(this);
|
||||
def->initValue()->accept(this);
|
||||
}
|
||||
if (!func->ID() || func->ID()->getText() != "main") {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
}
|
||||
func->accept(this);
|
||||
if (!seen_return_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "main 函数必须包含 return 语句"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitVarDecl(SysYParser::VarDeclContext* ctx) override {
|
||||
for (auto* def : ctx->varDef()) {
|
||||
const std::string name = def->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Variable;
|
||||
sym.def_ctx = def;
|
||||
sym.is_const = false;
|
||||
sym.is_array = !def->exp().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : def->exp()) exp->accept(this);
|
||||
if (def->initValue()) def->initValue()->accept(this);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override {
|
||||
if (!ctx || !ctx->blockStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
const std::string name = ctx->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义函数: " + name));
|
||||
}
|
||||
if (!ctx->funcType() || !ctx->funcType()->INT()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持 int main"));
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Function;
|
||||
sym.def_ctx = ctx;
|
||||
table_.Add(name, sym);
|
||||
|
||||
table_.PushScope();
|
||||
if (ctx->funcFParams()) {
|
||||
ctx->funcFParams()->accept(this);
|
||||
}
|
||||
const auto& items = ctx->blockStmt()->blockItem();
|
||||
if (items.empty()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "main 函数不能为空,且必须以 return 结束"));
|
||||
if (ctx->blockStmt()) {
|
||||
// Visit block items without pushing another scope to keep params in same scope
|
||||
for (auto* item : ctx->blockStmt()->blockItem()) {
|
||||
item->accept(this);
|
||||
}
|
||||
}
|
||||
ctx->blockStmt()->accept(this);
|
||||
table_.PopScope();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncFParam(SysYParser::FuncFParamContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "函数参数名冲突: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Parameter;
|
||||
sym.def_ctx = ctx;
|
||||
sym.is_array = !ctx->LBRACK().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : ctx->exp()) exp->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少语句块"));
|
||||
}
|
||||
const auto& items = ctx->blockItem();
|
||||
for (size_t i = 0; i < items.size(); ++i) {
|
||||
auto* item = items[i];
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
if (seen_return_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
}
|
||||
current_item_index_ = i;
|
||||
total_items_ = items.size();
|
||||
table_.PushScope();
|
||||
for (auto* item : ctx->blockItem()) {
|
||||
item->accept(this);
|
||||
}
|
||||
table_.PopScope();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
if (ctx->decl()) {
|
||||
ctx->decl()->accept(this);
|
||||
return {};
|
||||
}
|
||||
if (ctx->stmt()) {
|
||||
ctx->stmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
|
||||
std::any visitDecl(SysYParser::DeclContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
||||
}
|
||||
if (!ctx->btype() || !ctx->btype()->INT()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持局部 int 变量声明"));
|
||||
}
|
||||
auto* var_def = ctx->varDef();
|
||||
if (!var_def || !var_def->lValue()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
||||
}
|
||||
const std::string name = GetLValueName(*var_def->lValue());
|
||||
if (table_.Contains(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
||||
}
|
||||
if (auto* init = var_def->initValue()) {
|
||||
if (!init->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前不支持聚合初始化"));
|
||||
}
|
||||
init->exp()->accept(this);
|
||||
}
|
||||
table_.Add(name, var_def);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitStmt(SysYParser::StmtContext* ctx) override {
|
||||
if (!ctx || !ctx->returnStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
ctx->returnStmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
|
||||
if (!ctx || !ctx->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "return 缺少表达式"));
|
||||
std::any visitAssignStmt(SysYParser::AssignStmtContext* ctx) override {
|
||||
ctx->lValue()->accept(this);
|
||||
const std::string name = ctx->lValue()->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (sym && sym->is_const) {
|
||||
throw std::runtime_error(FormatError("sema", "试图给常量赋值: " + name));
|
||||
}
|
||||
ctx->exp()->accept(this);
|
||||
seen_return_ = true;
|
||||
if (current_item_index_ + 1 != total_items_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLValue(SysYParser::LValueContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (!sym) {
|
||||
throw std::runtime_error(FormatError("sema", "使用了未定义的标识符: " + name));
|
||||
}
|
||||
if (sym->kind == Symbol::Kind::Function) {
|
||||
throw std::runtime_error(FormatError("sema", "函数名不能作为左值: " + name));
|
||||
}
|
||||
sema_.BindLValue(ctx, sym->def_ctx);
|
||||
for (auto* exp : ctx->exp()) exp->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncCallExp(SysYParser::FuncCallExpContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (!sym) {
|
||||
throw std::runtime_error(FormatError("sema", "调用未定义的函数: " + name));
|
||||
}
|
||||
if (sym->kind != Symbol::Kind::Function) {
|
||||
throw std::runtime_error(FormatError("sema", "标识符不是函数: " + name));
|
||||
}
|
||||
sema_.BindFuncCall(ctx, dynamic_cast<SysYParser::FuncDefContext*>(sym->def_ctx));
|
||||
if (ctx->funcRParams()) {
|
||||
ctx->funcRParams()->accept(this);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// Visit expressions to ensure all sub-expressions are checked (e.g. for variable uses)
|
||||
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
|
||||
if (!ctx || !ctx->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法括号表达式"));
|
||||
}
|
||||
ctx->exp()->accept(this);
|
||||
return {};
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitVarExp(SysYParser::VarExpContext* ctx) override {
|
||||
if (!ctx || !ctx->var()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量表达式"));
|
||||
}
|
||||
ctx->var()->accept(this);
|
||||
return {};
|
||||
std::any visitLValueExp(SysYParser::LValueExpContext* ctx) override {
|
||||
return ctx->lValue()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
|
||||
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持整数字面量"));
|
||||
}
|
||||
return ctx->number()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitNumber(SysYParser::NumberContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) override {
|
||||
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的表达式形式"));
|
||||
}
|
||||
std::any visitNotExp(SysYParser::NotExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitVar(SysYParser::VarContext* ctx) override {
|
||||
if (!ctx || !ctx->ID()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量引用"));
|
||||
}
|
||||
const std::string name = ctx->ID()->getText();
|
||||
auto* decl = table_.Lookup(name);
|
||||
if (!decl) {
|
||||
throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name));
|
||||
}
|
||||
sema_.BindVarUse(ctx, decl);
|
||||
std::any visitDivExp(SysYParser::DivExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
SemanticContext TakeSemanticContext() { return std::move(sema_); }
|
||||
std::any visitModExp(SysYParser::ModExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitSubExp(SysYParser::SubExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLtExp(SysYParser::LtExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLeExp(SysYParser::LeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitGtExp(SysYParser::GtExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitGeExp(SysYParser::GeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitNeExp(SysYParser::NeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitAndExp(SysYParser::AndExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitOrExp(SysYParser::OrExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
|
||||
if (ctx->exp()) ctx->exp()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitIfStmt(SysYParser::IfStmtContext* ctx) override {
|
||||
ctx->exp()->accept(this);
|
||||
ctx->stmt(0)->accept(this);
|
||||
if (ctx->stmt(1)) ctx->stmt(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitWhileStmt(SysYParser::WhileStmtContext* ctx) override {
|
||||
ctx->exp()->accept(this);
|
||||
ctx->stmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBreakStmt(SysYParser::BreakStmtContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitContinueStmt(SysYParser::ContinueStmtContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitExpStmt(SysYParser::ExpStmtContext* ctx) override {
|
||||
if (ctx->exp()) ctx->exp()->accept(this);
|
||||
return {};
|
||||
}
|
||||
public:
|
||||
SemanticContext TakeSemanticContext() { return std::move(sema_); }
|
||||
|
||||
private:
|
||||
SymbolTable table_;
|
||||
SemanticContext sema_;
|
||||
bool seen_return_ = false;
|
||||
size_t current_item_index_ = 0;
|
||||
size_t total_items_ = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,17 +1,40 @@
|
||||
// 维护局部变量声明的注册与查找。
|
||||
|
||||
#include "sem/SymbolTable.h"
|
||||
|
||||
void SymbolTable::Add(const std::string& name,
|
||||
SysYParser::VarDefContext* decl) {
|
||||
table_[name] = decl;
|
||||
SymbolTable::SymbolTable() {
|
||||
// Push global scope
|
||||
PushScope();
|
||||
}
|
||||
|
||||
bool SymbolTable::Contains(const std::string& name) const {
|
||||
return table_.find(name) != table_.end();
|
||||
void SymbolTable::PushScope() {
|
||||
scopes_.emplace_back();
|
||||
}
|
||||
|
||||
SysYParser::VarDefContext* SymbolTable::Lookup(const std::string& name) const {
|
||||
auto it = table_.find(name);
|
||||
return it == table_.end() ? nullptr : it->second;
|
||||
void SymbolTable::PopScope() {
|
||||
if (scopes_.size() > 1) {
|
||||
scopes_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool SymbolTable::Add(const std::string& name, const Symbol& symbol) {
|
||||
auto& current_scope = scopes_.back();
|
||||
if (current_scope.find(name) != current_scope.end()) {
|
||||
return false;
|
||||
}
|
||||
current_scope[name] = symbol;
|
||||
return true;
|
||||
}
|
||||
|
||||
Symbol* SymbolTable::Lookup(const std::string& name) {
|
||||
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
|
||||
auto search = it->find(name);
|
||||
if (search != it->end()) {
|
||||
return &search->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SymbolTable::IsInCurrentScope(const std::string& name) const {
|
||||
const auto& current_scope = scopes_.back();
|
||||
return current_scope.find(name) != current_scope.end();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user