fix(ir): 规范ir实现

master
jing 1 week ago
parent c72ffa6e39
commit 8f448df4bc

@ -69,3 +69,8 @@ java -jar third_party/antlr-4.13.2-complete.jar \
# 仅输出语法树
./build/bin/compiler --emit-parse-tree test/test_case/simple_add.sy
```
## 7. 关于 AST 的建议
同学们也可以自行设计一层抽象语法树AST将 ANTLR 语法树先转换为 AST再进入后续阶段。
这样可以减少对具体文法细节的依赖使语义分析、IR 生成和后续扩展更清晰。这里不做具体要求。

@ -57,6 +57,9 @@ Lab2 的目标是在该示例基础上扩展语义覆盖范围,逐步把更多
说明:当前阶段变量统一采用内存模型:先 `alloca` 分配栈槽,再通过 `store/load` 读写。即使变量由常量初始化(如 `int a = 1;`),也会先 `store` 到栈槽,而不是直接把变量替换成 SSA 值。后续实验中,同学可按需求再重构。
此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录哪些 `Instruction` 使用了它。
这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。
## 6. 构建与运行
```bash

@ -6,7 +6,18 @@
namespace ir {
Function::Function(std::string name, std::shared_ptr<Type> ret_type)
: Value(std::move(ret_type), std::move(name)),
entry_(std::make_unique<BasicBlock>("entry")) {}
: Value(std::move(ret_type), std::move(name)) {
entry_ = CreateBlock("entry");
}
BasicBlock* Function::CreateBlock(const std::string& name) {
auto block = std::make_unique<BasicBlock>(name);
auto* ptr = block.get();
blocks_.push_back(std::move(block));
if (!entry_) {
entry_ = ptr;
}
return ptr;
}
} // namespace ir

@ -3,6 +3,7 @@
#pragma once
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
@ -13,6 +14,7 @@ namespace ir {
class Type;
class ConstantInt;
class Instruction;
class BasicBlock;
// IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。
class Context {
@ -82,9 +84,13 @@ class Instruction : public Value {
Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name = "")
: Value(std::move(ty), std::move(name)), opcode_(op) {}
Opcode opcode() const { return opcode_; }
bool IsTerminator() const { return opcode_ == Opcode::Ret; }
BasicBlock* parent() const { return parent_; }
void set_parent(BasicBlock* parent) { parent_ = parent; }
private:
Opcode opcode_;
BasicBlock* parent_ = nullptr;
};
class BinaryInst : public Instruction {
@ -137,13 +143,21 @@ class BasicBlock {
public:
explicit BasicBlock(std::string name) : name_(std::move(name)) {}
const std::string& name() const { return name_; }
bool HasTerminator() const {
return !instructions_.empty() && instructions_.back()->IsTerminator();
}
const std::vector<std::unique_ptr<Instruction>>& instructions() const {
return instructions_;
}
template <typename T, typename... Args>
T* Append(Args&&... args) {
if (HasTerminator()) {
throw std::runtime_error("BasicBlock 已有 terminator不能继续追加指令: " +
name_);
}
auto inst = std::make_unique<T>(std::forward<Args>(args)...);
auto* ptr = inst.get();
ptr->set_parent(this);
instructions_.push_back(std::move(inst));
return ptr;
}
@ -157,11 +171,16 @@ class Function : public Value {
public:
// 允许显式指定返回类型,便于后续扩展多种函数签名。
Function(std::string name, std::shared_ptr<Type> ret_type);
BasicBlock* entry() { return entry_.get(); }
const BasicBlock* entry() const { return entry_.get(); }
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* entry() { return entry_; }
const BasicBlock* entry() const { return entry_; }
const std::vector<std::unique_ptr<BasicBlock>>& blocks() const {
return blocks_;
}
private:
std::unique_ptr<BasicBlock> entry_;
BasicBlock* entry_ = nullptr;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
};
class Module {

@ -12,6 +12,10 @@ bool IsArithmeticType(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::Int32;
}
bool IsPtrInt32Type(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::PtrInt32;
}
} // namespace
ConstantInt* IRBuilder::CreateConstInt(int v) {
@ -54,6 +58,12 @@ LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
if (!ptr) {
throw std::runtime_error("IRBuilder::CreateLoad 缺少 ptr");
}
if (!IsPtrInt32Type(ptr->type())) {
throw std::runtime_error("IRBuilder::CreateLoad 当前只支持从 i32* 加载");
}
return insertBlock_->Append<LoadInst>(ptr, name);
}
@ -61,6 +71,18 @@ StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
if (!val) {
throw std::runtime_error("IRBuilder::CreateStore 缺少 val");
}
if (!ptr) {
throw std::runtime_error("IRBuilder::CreateStore 缺少 ptr");
}
if (!IsArithmeticType(val->type())) {
throw std::runtime_error("IRBuilder::CreateStore 当前只支持存储 i32");
}
if (!IsPtrInt32Type(ptr->type())) {
throw std::runtime_error("IRBuilder::CreateStore 当前只支持写入 i32*");
}
return insertBlock_->Append<StoreInst>(val, ptr);
}
@ -68,6 +90,9 @@ ReturnInst* IRBuilder::CreateRet(Value* v) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
if (!v) {
throw std::runtime_error("IRBuilder::CreateRet 缺少返回值");
}
return insertBlock_->Append<ReturnInst>(v);
}

@ -5,6 +5,7 @@
#include "ir/IR.h"
#include <iostream>
#include <string>
#include <stdexcept>
namespace ir {
@ -41,6 +42,13 @@ static const char* OpcodeToString(Opcode op) {
return "?";
}
static std::string ValueToString(const Value* v) {
if (auto* ci = dynamic_cast<const ConstantInt*>(v)) {
return std::to_string(ci->value());
}
return v ? v->name() : "<null>";
}
void IRPrinter::Print(const Module& module) {
for (const auto& func : module.functions()) {
std::cout << "define " << TypeToString(*func->type()) << " @"
@ -60,7 +68,8 @@ void IRPrinter::Print(const Module& module) {
auto* bin = static_cast<const BinaryInst*>(inst);
std::cout << " " << bin->name() << " = " << OpcodeToString(bin->opcode())
<< " " << TypeToString(*bin->lhs()->type()) << " "
<< bin->lhs()->name() << ", " << bin->rhs()->name() << "\n";
<< ValueToString(bin->lhs()) << ", "
<< ValueToString(bin->rhs()) << "\n";
break;
}
case Opcode::Alloca: {
@ -71,19 +80,19 @@ void IRPrinter::Print(const Module& module) {
case Opcode::Load: {
auto* load = static_cast<const LoadInst*>(inst);
std::cout << " " << load->name() << " = load i32, i32* "
<< load->ptr()->name() << "\n";
<< ValueToString(load->ptr()) << "\n";
break;
}
case Opcode::Store: {
auto* store = static_cast<const StoreInst*>(inst);
std::cout << " store i32 " << store->value()->name() << ", i32* "
<< store->ptr()->name() << "\n";
std::cout << " store i32 " << ValueToString(store->value()) << ", i32* "
<< ValueToString(store->ptr()) << "\n";
break;
}
case Opcode::Ret: {
auto* ret = static_cast<const ReturnInst*>(inst);
std::cout << " ret " << TypeToString(*ret->value()->type()) << " "
<< ret->value()->name() << "\n";
<< ValueToString(ret->value()) << "\n";
break;
}
}

@ -3,11 +3,40 @@
// - 指令操作数与结果类型管理,支持打印与优化
#include "ir/IR.h"
#include <stdexcept>
namespace ir {
namespace {
bool IsArithmeticType(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::Int32;
}
bool IsPtrInt32Type(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::PtrInt32;
}
} // namespace
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
Value* rhs, std::string name)
: Instruction(op, std::move(ty), std::move(name)), lhs_(lhs), rhs_(rhs) {
if (op != Opcode::Add) {
throw std::runtime_error("BinaryInst 当前只支持 Add");
}
if (!lhs_ || !rhs_) {
throw std::runtime_error("BinaryInst 缺少操作数");
}
if (!type_ || !lhs_->type() || !rhs_->type()) {
throw std::runtime_error("BinaryInst 缺少类型信息");
}
if (lhs_->type()->kind() != rhs_->type()->kind() ||
type_->kind() != lhs_->type()->kind()) {
throw std::runtime_error("BinaryInst 类型不匹配");
}
if (!IsArithmeticType(type_)) {
throw std::runtime_error("BinaryInst 当前只支持 i32");
}
if (lhs_) {
lhs_->AddUser(this);
}
@ -18,9 +47,10 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
ReturnInst::ReturnInst(Value* val)
: Instruction(Opcode::Ret, Type::Void(), ""), value_(val) {
if (value_) {
value_->AddUser(this);
if (!value_) {
throw std::runtime_error("ReturnInst 缺少返回值");
}
value_->AddUser(this);
}
AllocaInst::AllocaInst(std::string name)
@ -28,19 +58,31 @@ AllocaInst::AllocaInst(std::string name)
LoadInst::LoadInst(Value* ptr, std::string name)
: Instruction(Opcode::Load, Type::Int32(), std::move(name)), ptr_(ptr) {
if (ptr_) {
ptr_->AddUser(this);
if (!ptr_) {
throw std::runtime_error("LoadInst 缺少 ptr");
}
if (!IsPtrInt32Type(ptr_->type())) {
throw std::runtime_error("LoadInst 当前只支持从 i32* 加载");
}
ptr_->AddUser(this);
}
StoreInst::StoreInst(Value* val, Value* ptr)
: Instruction(Opcode::Store, Type::Void(), ""), value_(val), ptr_(ptr) {
if (value_) {
value_->AddUser(this);
if (!value_) {
throw std::runtime_error("StoreInst 缺少 value");
}
if (!ptr_) {
throw std::runtime_error("StoreInst 缺少 ptr");
}
if (!IsArithmeticType(value_->type())) {
throw std::runtime_error("StoreInst 当前只支持存储 i32");
}
if (ptr_) {
ptr_->AddUser(this);
if (!IsPtrInt32Type(ptr_->type())) {
throw std::runtime_error("StoreInst 当前只支持写入 i32*");
}
value_->AddUser(this);
ptr_->AddUser(this);
}
} // namespace ir

@ -6,10 +6,6 @@
#include "ir/IR.h"
bool IRGenImpl::GenStmt(SysYParser::StmtContext& stmt) {
if (stmt.varDecl()) {
GenVarDecl(*stmt.varDecl());
return false;
}
if (stmt.returnStmt()) {
GenReturnStmt(*stmt.returnStmt());
return true;

Loading…
Cancel
Save