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

227 lines
5.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 极简 IR 定义:当前只支撑 i32 和加法,演示用。
// 可在此基础上扩展更多类型/指令
#pragma once
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace ir {
class Type;
class ConstantInt;
class Instruction;
class BasicBlock;
// IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。
class Context {
public:
~Context();
const std::shared_ptr<Type>& Void();
const std::shared_ptr<Type>& Int32();
const std::shared_ptr<Type>& PtrInt32();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
std::string NextTemp();
private:
std::shared_ptr<Type> void_;
std::shared_ptr<Type> int32_;
std::shared_ptr<Type> ptr_i32_;
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
int temp_index_ = -1;
};
Context& DefaultContext();
class Type {
public:
enum class Kind { Void, Int32, PtrInt32 };
explicit Type(Kind k) : kind_(k) {}
Kind kind() const { return kind_; }
static std::shared_ptr<Type> Void();
static std::shared_ptr<Type> Int32();
static std::shared_ptr<Type> PtrInt32();
private:
Kind kind_;
};
class Value {
public:
Value(std::shared_ptr<Type> ty, std::string name)
: type_(std::move(ty)), name_(std::move(name)) {}
virtual ~Value() = default;
const std::shared_ptr<Type>& type() const { return type_; }
const std::string& name() const { return name_; }
void set_name(std::string n) { name_ = std::move(n); }
void AddUser(Instruction* user) { users_.push_back(user); }
const std::vector<Instruction*>& users() const { return users_; }
protected:
std::shared_ptr<Type> type_;
std::string name_;
std::vector<Instruction*> users_;
};
class ConstantInt : public Value {
public:
explicit ConstantInt(int v);
int value() const { return value_; }
private:
int value_{};
};
enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
class Instruction : public Value {
public:
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 {
public:
BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
std::string name);
Value* lhs() const { return lhs_; }
Value* rhs() const { return rhs_; }
private:
Value* lhs_;
Value* rhs_;
};
class ReturnInst : public Instruction {
public:
explicit ReturnInst(Value* val);
Value* value() const { return value_; }
private:
Value* value_;
};
class AllocaInst : public Instruction {
public:
explicit AllocaInst(std::string name);
};
class LoadInst : public Instruction {
public:
LoadInst(Value* ptr, std::string name);
Value* ptr() const { return ptr_; }
private:
Value* ptr_;
};
class StoreInst : public Instruction {
public:
StoreInst(Value* val, Value* ptr);
Value* value() const { return value_; }
Value* ptr() const { return ptr_; }
private:
Value* value_;
Value* ptr_;
};
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;
}
private:
std::string name_;
std::vector<std::unique_ptr<Instruction>> instructions_;
};
class Function : public Value {
public:
// 允许显式指定返回类型,便于后续扩展多种函数签名。
Function(std::string name, std::shared_ptr<Type> ret_type);
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:
BasicBlock* entry_ = nullptr;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
};
class Module {
public:
// 创建函数时显式传入返回类型,便于在 IRGen 中根据语法树信息选择类型。
Function* CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type);
const std::vector<std::unique_ptr<Function>>& functions() const {
return functions_;
}
private:
std::vector<std::unique_ptr<Function>> functions_;
};
class IRBuilder {
public:
explicit IRBuilder(BasicBlock* bb) : insertBlock_(bb) {}
void SetInsertPoint(BasicBlock* bb) { insertBlock_ = bb; }
BasicBlock* GetInsertBlock() const { return insertBlock_; }
// 构造常量、二元运算、返回指令的最小集合。
ConstantInt* CreateConstInt(int v);
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name);
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name) {
return CreateBinary(Opcode::Add, lhs, rhs, name);
}
AllocaInst* CreateAllocaI32(const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
private:
BasicBlock* insertBlock_;
};
class IRPrinter {
public:
void Print(const Module& module);
};
} // namespace ir