fix(ir): 规范ir实现
This commit is contained in:
@@ -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
|
||||
|
||||
25
src/ir/IR.h
25
src/ir/IR.h
@@ -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_) {
|
||||
ptr_->AddUser(this);
|
||||
if (!ptr_) {
|
||||
throw std::runtime_error("StoreInst 缺少 ptr");
|
||||
}
|
||||
if (!IsArithmeticType(value_->type())) {
|
||||
throw std::runtime_error("StoreInst 当前只支持存储 i32");
|
||||
}
|
||||
if (!IsPtrInt32Type(ptr_->type())) {
|
||||
throw std::runtime_error("StoreInst 当前只支持写入 i32*");
|
||||
}
|
||||
value_->AddUser(this);
|
||||
ptr_->AddUser(this);
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
Reference in New Issue
Block a user