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.

474 lines
14 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.

// 当前只支撑 i32、i32*、void 以及最小的内存/算术指令,演示用。
//
// 当前已经实现:
// 1. 基础类型系统void / i32 / i32* / float / float* / array / pointer
// 2. Value 体系Value / ConstantValue / ConstantInt / ConstantFloat / ConstantArray / ConstantZero / Function / BasicBlock / User / GlobalValue / Instruction
// 3. 最小指令集Add / Sub / Mul / Div / Mod / Neg / Alloca / Load / Store / Ret / Cmp / FCmp / Zext / Br / CondBr / Call / GEP / SIToFP / FPToSI
// 4. BasicBlock / Function / Module 三层组织结构
// 5. IRBuilder便捷创建常量和各类指令
// 6. def-use 关系的轻量实现:
// - Instruction 保存 operand 列表
// - Value 保存 uses
// - 支持 ReplaceAllUsesWith 的简化实现
//
// 当前尚未实现或只做了最小占位:
// 1. 完整类型系统label 类型等
// 2. 更成熟的 Use 管理(例如 LLVM 风格的双向链式结构)
// 3. 更完整的 IR verifier 和优化基础设施
//
// 当前需要特别说明的两个简化点:
// 1. BasicBlock 虽然已经纳入 Value 体系,但其类型目前仍用 void 作为占位,
// 后续如果补 label type可以再改成更合理的块标签类型。
//
// 建议的扩展顺序:
// 1. 先补更多指令和类型
// 2. 再补控制流相关 IR
// 3. 最后再考虑把 Value/User/Use 进一步抽象成更完整的框架
#pragma once
#include <iosfwd>
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace ir {
class Type;
class Value;
class User;
class ConstantValue;
class ConstantInt;
class ConstantFloat;
class ConstantArray;
class ConstantZero;
class GlobalValue;
class Instruction;
class BasicBlock;
class Function;
// --- Type System ---
class Type {
public:
enum class Kind { Void, Int1, Int32, PtrInt32, Float, PtrFloat, Array, Pointer };
explicit Type(Kind k);
Type(Kind k, std::shared_ptr<Type> elem_ty, int num_elems);
Type(Kind k, std::shared_ptr<Type> pointed_ty);
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt1Type();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
static const std::shared_ptr<Type>& GetFloatType();
static const std::shared_ptr<Type>& GetPtrFloatType();
static std::shared_ptr<Type> GetArrayType(std::shared_ptr<Type> elem_ty, int num_elems);
static std::shared_ptr<Type> GetPointerType(std::shared_ptr<Type> pointed_ty);
Kind GetKind() const;
bool IsVoid() const;
bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat() const;
bool IsPtrFloat() const;
bool IsArray() const;
bool IsPointer() const;
std::shared_ptr<Type> GetElementType() const { return elem_ty_; }
int GetNumElements() const { return num_elems_; }
std::shared_ptr<Type> GetPointedType() const { return elem_ty_; }
private:
Kind kind_;
std::shared_ptr<Type> elem_ty_;
int num_elems_ = 0;
};
// --- Value & Use ---
class Use {
public:
Use() = default;
Use(Value* value, User* user, size_t operand_index)
: value_(value), user_(user), operand_index_(operand_index) {}
Value* GetValue() const { return value_; }
User* GetUser() const { return user_; }
size_t GetOperandIndex() const { return operand_index_; }
void SetValue(Value* value) { value_ = value; }
void SetUser(User* user) { user_ = user; }
void SetOperandIndex(size_t operand_index) { operand_index_ = operand_index; }
private:
Value* value_ = nullptr;
User* user_ = nullptr;
size_t operand_index_ = 0;
};
class Value {
public:
Value(std::shared_ptr<Type> ty, std::string name);
virtual ~Value() = default;
const std::shared_ptr<Type>& GetType() const;
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat() const;
bool IsPtrFloat() const;
bool IsConstant() const;
bool IsInstruction() const;
bool IsUser() const;
bool IsFunction() const;
bool IsArgument() const;
void AddUse(User* user, size_t operand_index);
void RemoveUse(User* user, size_t operand_index);
const std::vector<Use>& GetUses() const;
void ReplaceAllUsesWith(Value* new_value);
protected:
std::shared_ptr<Type> type_;
std::string name_;
std::vector<Use> uses_;
};
class Argument : public Value {
public:
Argument(std::shared_ptr<Type> ty, std::string name, Function* parent, size_t arg_no);
Function* GetParent() const;
size_t GetArgNo() const;
private:
Function* parent_;
size_t arg_no_;
};
// --- Constants ---
class ConstantValue : public Value {
public:
ConstantValue(std::shared_ptr<Type> ty, std::string name = "");
};
class ConstantInt : public ConstantValue {
public:
ConstantInt(std::shared_ptr<Type> ty, int v);
int GetValue() const { return value_; }
private:
int value_{};
};
class ConstantFloat : public ConstantValue {
public:
ConstantFloat(std::shared_ptr<Type> ty, float v);
float GetValue() const { return value_; }
private:
float value_{};
};
class ConstantArray : public ConstantValue {
public:
ConstantArray(std::shared_ptr<Type> ty, std::vector<ConstantValue*> elements);
const std::vector<ConstantValue*>& GetElements() const { return elements_; }
private:
std::vector<ConstantValue*> elements_;
};
class ConstantZero : public ConstantValue {
public:
explicit ConstantZero(std::shared_ptr<Type> ty);
};
// --- Context ---
class Context {
public:
Context() = default;
~Context();
ConstantInt* GetConstInt(int v);
ConstantFloat* GetConstFloat(float v);
ConstantArray* GetConstArray(std::shared_ptr<Type> ty, std::vector<ConstantValue*> elements);
ConstantZero* GetConstZero(std::shared_ptr<Type> ty);
std::string NextTemp();
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
std::unordered_map<float, std::unique_ptr<ConstantFloat>> const_floats_;
std::vector<std::unique_ptr<ConstantArray>> const_arrays_;
std::vector<std::unique_ptr<ConstantZero>> const_zeros_;
int temp_index_ = -1;
};
// --- Instructions ---
enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, FCmp, Zext, Br, CondBr, Call, GEP, SIToFP, FPToSI };
enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge };
class User : public Value {
public:
User(std::shared_ptr<Type> ty, std::string name);
size_t GetNumOperands() const;
Value* GetOperand(size_t index) const;
void SetOperand(size_t index, Value* value);
protected:
void AddOperand(Value* value);
private:
std::vector<Value*> operands_;
};
class GlobalValue : public User {
public:
GlobalValue(std::shared_ptr<Type> ty, std::string name);
};
class GlobalVariable : public GlobalValue {
public:
GlobalVariable(std::string name, std::shared_ptr<Type> type, ConstantValue* init);
ConstantValue* GetInitializer() const { return init_; }
private:
ConstantValue* init_ = nullptr;
};
class Instruction : public User {
public:
Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name = "");
Opcode GetOpcode() const;
bool IsTerminator() const;
BasicBlock* GetParent() const;
void SetParent(BasicBlock* 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* GetLhs() const;
Value* GetRhs() const;
};
class UnaryInst : public Instruction {
public:
UnaryInst(Opcode op, std::shared_ptr<Type> ty, Value* operand,
std::string name);
Value* GetUnaryOperand() const;
};
class ReturnInst : public Instruction {
public:
ReturnInst(std::shared_ptr<Type> void_ty, Value* val);
Value* GetValue() const;
};
class AllocaInst : public Instruction {
public:
AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name);
};
class LoadInst : public Instruction {
public:
LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name);
Value* GetPtr() const;
};
class StoreInst : public Instruction {
public:
StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr);
Value* GetValue() const;
Value* GetPtr() const;
};
class CmpInst : public Instruction {
public:
CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
CmpOp GetCmpOp() const;
Value* GetLhs() const;
Value* GetRhs() const;
private:
CmpOp cmp_op_;
};
class FCmpInst : public Instruction {
public:
FCmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
CmpOp GetCmpOp() const;
Value* GetLhs() const;
Value* GetRhs() const;
private:
CmpOp cmp_op_;
};
class ZextInst : public Instruction {
public:
ZextInst(std::shared_ptr<Type> dest_ty, Value* val, std::string name);
Value* GetValue() const;
};
class BranchInst : public Instruction {
public:
BranchInst(BasicBlock* dest);
BasicBlock* GetDest() const;
};
class CondBranchInst : public Instruction {
public:
CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
Value* GetCond() const;
BasicBlock* GetTrueBlock() const;
BasicBlock* GetFalseBlock() const;
};
class CallInst : public Instruction {
public:
CallInst(Function* func, std::vector<Value*> args, std::string name = "");
Function* GetFunc() const;
const std::vector<Value*>& GetArgs() const;
private:
Function* func_;
std::vector<Value*> args_;
};
class GEPInst : public Instruction {
public:
GEPInst(std::shared_ptr<Type> ty, Value* ptr, std::vector<Value*> indices, std::string name = "");
Value* GetPtr() const;
const std::vector<Value*>& GetIndices() const;
private:
std::vector<Value*> indices_;
};
class SIToFPInst : public Instruction {
public:
SIToFPInst(std::shared_ptr<Type> ty, Value* val, std::string name = "");
};
class FPToSIInst : public Instruction {
public:
FPToSIInst(std::shared_ptr<Type> ty, Value* val, std::string name = "");
};
// --- Structure ---
class BasicBlock : public Value {
public:
explicit BasicBlock(std::string name);
Function* GetParent() const;
void SetParent(Function* parent);
bool HasTerminator() const;
const std::vector<std::unique_ptr<Instruction>>& GetInstructions() const;
const std::vector<BasicBlock*>& GetPredecessors() const;
const std::vector<BasicBlock*>& GetSuccessors() const;
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->SetParent(this);
instructions_.push_back(std::move(inst));
return ptr;
}
private:
Function* parent_ = nullptr;
std::vector<std::unique_ptr<Instruction>> instructions_;
std::vector<BasicBlock*> predecessors_;
std::vector<BasicBlock*> successors_;
};
class Function : public Value {
public:
Function(std::string name, std::shared_ptr<Type> ret_type);
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* GetEntry();
const BasicBlock* GetEntry() const;
const std::vector<std::unique_ptr<BasicBlock>>& GetBlocks() const;
Argument* AddArgument(std::shared_ptr<Type> ty, std::string name);
const std::vector<std::unique_ptr<Argument>>& GetArgs() const;
private:
BasicBlock* entry_ = nullptr;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
std::vector<std::unique_ptr<Argument>> args_;
};
class Module {
public:
Module() = default;
Context& GetContext();
const Context& GetContext() const;
Function* CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type);
const std::vector<std::unique_ptr<Function>>& GetFunctions() const;
GlobalVariable* CreateGlobalVariable(const std::string& name, std::shared_ptr<Type> type, ConstantValue* init);
const std::vector<std::unique_ptr<GlobalVariable>>& GetGlobalVariables() const;
private:
Context context_;
std::vector<std::unique_ptr<Function>> functions_;
std::vector<std::unique_ptr<GlobalVariable>> global_variables_;
};
class IRBuilder {
public:
IRBuilder(Context& ctx, BasicBlock* bb);
void SetInsertPoint(BasicBlock* bb);
BasicBlock* GetInsertBlock() const;
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);
BinaryInst* CreateSub(Value* lhs, Value* rhs, const std::string& name);
BinaryInst* CreateMul(Value* lhs, Value* rhs, const std::string& name);
UnaryInst* CreateNeg(Value* operand, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
AllocaInst* CreateAllocaFloat(const std::string& name);
AllocaInst* CreateAlloca(std::shared_ptr<Type> ty, const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
Instruction* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
ZextInst* CreateZext(Value* val, const std::string& name);
BranchInst* CreateBr(BasicBlock* dest);
CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
CallInst* CreateCall(Function* func, std::vector<Value*> args, const std::string& name);
GEPInst* CreateGEP(std::shared_ptr<Type> ty, Value* ptr, std::vector<Value*> indices, const std::string& name);
SIToFPInst* CreateSIToFP(Value* val, const std::string& name);
FPToSIInst* CreateFPToSI(Value* val, const std::string& name);
private:
Context& ctx_;
BasicBlock* insert_block_;
};
class IRPrinter {
public:
void Print(const Module& module, std::ostream& os);
};
} // namespace ir