支配树分析

mirror
mirror 1 week ago
parent 41be171f0a
commit 996e0a8092

@ -1,533 +0,0 @@
// 当前只支撑 i32、i32*、void 以及最小的内存/算术指令,演示用。
//
// 当前已经实现:
// 1. 基础类型系统void / i32 / i32*
// 2. Value 体系Value / ConstantValue / ConstantInt / Function / BasicBlock / User / GlobalValue / Instruction
// 3. 最小指令集Add / Alloca / Load / Store / Ret
// 4. BasicBlock / Function / Module 三层组织结构
// 5. IRBuilder便捷创建常量和最小指令
// 6. def-use 关系的轻量实现:
// - Instruction 保存 operand 列表
// - Value 保存 uses
// - 支持 ReplaceAllUsesWith 的简化实现
//
// 当前尚未实现或只做了最小占位:
// 1. 完整类型系统数组、函数类型、label 类型等
// 2. 更完整的指令系统br / condbr / call / phi / gep 等
// 3. 更成熟的 Use 管理(例如 LLVM 风格的双向链式结构)
// 4. 更完整的 IR verifier 和优化基础设施
//
// 当前需要特别说明的两个简化点:
// 1. BasicBlock 虽然已经纳入 Value 体系,但其类型目前仍用 void 作为占位,
// 后续如果补 label type可以再改成更合理的块标签类型。
// 2. ConstantValue 体系目前只实现了 ConstantInt后续可以继续补 ConstantFloat、
// ConstantArray等更完整的常量种类。
//
// 建议的扩展顺序:
// 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 GlobalValue;
class Instruction;
class BasicBlock;
class Function;
// Use 表示一个 Value 的一次使用记录。
// 当前实现设计:
// - value被使用的值
// - user使用该值的 User
// - operand_index该值在 user 操作数列表中的位置
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;
};
// IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。
class Context {
public:
Context() = default;
~Context();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
// 去重创建 float 常量。
ConstantFloat* GetConstFloat(float v);
std::string NextTemp();
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
std::unordered_map<float, std::unique_ptr<ConstantFloat>> const_floats_;
int temp_index_ = -1;
};
class Type {
public:
enum class Kind { Void, Int32, PtrInt32, Float32, PtrFloat32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
// Type::GetInt32Type() == Type::GetInt32Type()
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
static const std::shared_ptr<Type>& GetFloat32Type();
static const std::shared_ptr<Type>& GetPtrFloat32Type();
Kind GetKind() const;
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat32() const;
bool IsPtrFloat32() const;
private:
Kind kind_;
};
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 IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat32() const;
bool IsPtrFloat32() const;
bool IsConstant() const;
bool IsInstruction() const;
bool IsUser() const;
bool IsFunction() 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_;
};
// ConstantValue 是常量体系的基类。
// 当前只实现了 ConstantInt后续可继续扩展更多常量种类。
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_{};
};
// Argument 表示函数的形式参数,作为 Value 在函数体内直接被引用。
class Argument : public Value {
public:
Argument(std::shared_ptr<Type> ty, std::string name, size_t index);
size_t GetArgIndex() const { return arg_index_; }
private:
size_t arg_index_;
};
// 第一版 Lab2 需要的指令集合。
enum class Opcode {
Add,
Sub,
Mul,
Div,
Mod,
Cmp,
Cast,
Br,
CondBr,
Call,
Alloca,
Load,
Store,
Ret,
Gep, // getelementptr数组元素地址计算
Phi, // SSA phi 节点
};
enum class CmpOp { Eq, Ne, Lt, Le, Gt, Ge };
enum class CastOp { IntToFloat, FloatToInt };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
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:
// 统一的 operand 入口。
void AddOperand(Value* value);
// 清空所有 operand不清除 use 关系,调用者需自行处理)。
void ClearOperands();
private:
std::vector<Value*> operands_;
};
// GlobalValue 是全局值/全局变量体系的空壳占位类。
// 当前只补齐类层次,具体初始化器、打印和链接语义后续再补。
class GlobalValue : public User {
public:
GlobalValue(std::shared_ptr<Type> ty, std::string name);
};
// GlobalVariable 代表一个全局整型变量、常量或数组。
// 标量:打印为 @name = global i32 N。
// 数组:打印为 @name = global [count x i32] zeroinitializer。
class GlobalVariable : public GlobalValue {
public:
GlobalVariable(std::string name, std::shared_ptr<Type> ptr_ty,
int init_val = 0, int count = 1,
std::vector<int> init_elems = {});
int GetInitValue() const { return init_val_; }
int GetCount() const { return count_; }
bool IsArray() const { return count_ > 1; }
bool IsFloat() const { return GetType() && GetType()->IsPtrFloat32(); }
const std::vector<int>& GetInitElements() const { return init_elems_; }
private:
int init_val_;
int count_;
std::vector<int> init_elems_;
};
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 CmpInst : public Instruction {
public:
CmpInst(CmpOp op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
std::string name);
CmpOp GetCmpOp() const;
Value* GetLhs() const;
Value* GetRhs() const;
private:
CmpOp cmp_op_;
};
class CastInst : public Instruction {
public:
CastInst(CastOp op, std::shared_ptr<Type> ty, Value* val, std::string name);
CastOp GetCastOp() const;
Value* GetValue() const;
private:
CastOp cast_op_;
};
class ReturnInst : public Instruction {
public:
ReturnInst(std::shared_ptr<Type> void_ty, Value* val);
Value* GetValue() const;
};
class AllocaInst : public Instruction {
public:
// 标量 alloca分配 1 个 i32
AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name);
// 数组 alloca分配 count 个 i32count 为编译期常量)
AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name, int count);
int GetCount() const { return count_; }
bool IsArray() const { return count_ > 1; }
private:
int count_ = 1;
};
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 BranchInst : public Instruction {
public:
BranchInst(std::shared_ptr<Type> void_ty, BasicBlock* target);
BasicBlock* GetTarget() const;
};
class CondBranchInst : public Instruction {
public:
CondBranchInst(std::shared_ptr<Type> void_ty, Value* cond,
BasicBlock* true_bb, BasicBlock* false_bb);
Value* GetCond() const;
BasicBlock* GetTrueBlock() const;
BasicBlock* GetFalseBlock() const;
};
class CallInst : public Instruction {
public:
CallInst(std::shared_ptr<Type> ret_ty, Function* callee,
std::vector<Value*> args, std::string name);
Function* GetCallee() const;
size_t GetNumArgs() const;
Value* GetArg(size_t index) const;
};
// GepInstgetelementptr i32, i32* base, i32 index
// 用于从数组基址 + 线性偏移量计算元素指针。
class GepInst : public Instruction {
public:
GepInst(std::shared_ptr<Type> ptr_ty, Value* base, Value* index,
std::string name);
Value* GetBase() const;
Value* GetIndex() const;
};
// PhiInstSSA phi 节点,用于控制流汇合点合并不同前驱传来的值。
// 操作数布局:[val_0, bb_0, val_1, bb_1, ...]
class PhiInst : public Instruction {
public:
PhiInst(std::shared_ptr<Type> ty, std::string name);
// 添加一组 (value, incoming_block) 入边。
void AddIncoming(Value* val, BasicBlock* bb);
size_t GetNumIncoming() const;
Value* GetIncomingValue(size_t i) const;
BasicBlock* GetIncomingBlock(size_t i) const;
void SetIncomingValue(size_t i, Value* val);
// 移除来自指定前驱块的入边。
void RemoveIncomingBlock(BasicBlock* bb);
};
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
// 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。
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;
std::vector<std::unique_ptr<Instruction>>& MutableInstructions();
const std::vector<BasicBlock*>& GetPredecessors() const;
const std::vector<BasicBlock*>& GetSuccessors() const;
std::vector<BasicBlock*>& MutablePredecessors();
std::vector<BasicBlock*>& MutableSuccessors();
void AddPredecessor(BasicBlock* pred);
void AddSuccessor(BasicBlock* succ);
void RemovePredecessor(BasicBlock* pred);
void RemoveSuccessor(BasicBlock* succ);
// 在块头部(所有 phi 之后)插入指令。
template <typename T, typename... Args>
T* Prepend(Args&&... args) {
auto inst = std::make_unique<T>(std::forward<Args>(args)...);
auto* ptr = inst.get();
ptr->SetParent(this);
// 插入到第一条非-phi 指令之前
auto it = instructions_.begin();
while (it != instructions_.end() &&
(*it)->GetOpcode() == Opcode::Phi) {
++it;
}
instructions_.insert(it, std::move(inst));
return ptr;
}
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;
}
// 在块的最前面插入 phi 节点。
PhiInst* PrependPhi(std::shared_ptr<Type> ty, const std::string& name);
// 删除指定指令(从块中移除 ownership
void RemoveInstruction(Instruction* inst);
// 判断块是否为空(不含任何指令)。
bool IsEmpty() const { return instructions_.empty(); }
private:
Function* parent_ = nullptr;
std::vector<std::unique_ptr<Instruction>> instructions_;
std::vector<BasicBlock*> predecessors_;
std::vector<BasicBlock*> successors_;
};
// Function 当前也采用了最小实现。
// 需要特别注意:由于项目里还没有单独的 FunctionType
// Function 继承自 Value 后,其 type_ 目前只保存”返回类型”,
// 并不能完整表达”返回类型 + 形参列表”这一整套函数签名。
class Function : public Value {
public:
Function(std::string name, std::shared_ptr<Type> ret_type,
std::vector<std::shared_ptr<Type>> param_types = {});
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* GetEntry();
const BasicBlock* GetEntry() const;
const std::vector<std::shared_ptr<Type>>& GetParamTypes() const;
size_t GetNumParams() const;
Argument* GetArgument(size_t index) const;
const std::vector<std::unique_ptr<BasicBlock>>& GetBlocks() const;
std::vector<std::unique_ptr<BasicBlock>>& MutableBlocks();
// 删除指定基本块(从函数中移除 ownership
void RemoveBlock(BasicBlock* bb);
// 外部函数声明(无函数体,打印为 declare
void SetExternal(bool v) { is_external_ = v; }
bool IsExternal() const { return is_external_; }
private:
BasicBlock* entry_ = nullptr;
std::vector<std::shared_ptr<Type>> param_types_;
std::vector<std::unique_ptr<Argument>> args_;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
bool is_external_ = false;
};
class Module {
public:
Module() = default;
Context& GetContext();
const Context& GetContext() const;
Function* CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type,
std::vector<std::shared_ptr<Type>> param_types = {});
Function* FindFunction(const std::string& name) const;
const std::vector<std::unique_ptr<Function>>& GetFunctions() const;
GlobalVariable* CreateGlobalVar(const std::string& name, int init_val = 0,
int count = 1,
std::shared_ptr<Type> ptr_ty = Type::GetPtrInt32Type(),
std::vector<int> init_elems = {});
GlobalVariable* FindGlobalVar(const std::string& name) const;
const std::vector<std::unique_ptr<GlobalVariable>>& GetGlobalVars() const;
private:
Context context_;
std::vector<std::unique_ptr<GlobalVariable>> global_vars_;
std::vector<std::unique_ptr<Function>> functions_;
};
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);
BinaryInst* CreateDiv(Value* lhs, Value* rhs, const std::string& name);
BinaryInst* CreateMod(Value* lhs, Value* rhs, const std::string& name);
CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
CastInst* CreateSIToFP(Value* v, const std::string& name);
CastInst* CreateFPToSI(Value* v, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
AllocaInst* CreateAllocaArray(int count, const std::string& name);
AllocaInst* CreateAllocaF32(const std::string& name);
AllocaInst* CreateAllocaF32Array(int count, const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
BranchInst* CreateBr(BasicBlock* target);
CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb,
BasicBlock* false_bb);
CallInst* CreateCall(Function* callee, const std::vector<Value*>& args,
const std::string& name);
GepInst* CreateGep(Value* base, Value* index, const std::string& name);
ReturnInst* CreateRet(Value* v);
ReturnInst* CreateRetVoid();
private:
Context& ctx_;
BasicBlock* insert_block_;
};
class IRPrinter {
public:
void Print(const Module& module, std::ostream& os);
};
} // namespace ir

@ -169,3 +169,4 @@ class DominatorTree {
} // namespace analysis
} // namespace ir

@ -1,130 +0,0 @@
// 死代码删除DCE
// - 删除无用指令与无用基本块
// - 通常与 CFG 简化配合使用
//
// 算法:标记 + 清扫
// 1. 标记所有有副作用的指令为"有用"ret, br, condbr, store, call
// 2. 沿数据依赖反向传播,将有用指令依赖的定义也标记为有用
// 3. 删除所有未被标记的非终结指令
#include "ir/IR.h"
#include <queue>
#include <unordered_set>
#include <vector>
namespace ir {
namespace passes {
// 判断一条指令是否有副作用(不可随意删除)
static bool HasSideEffect(Instruction* inst) {
Opcode op = inst->GetOpcode();
// 终结指令、store、call 均有副作用
if (op == Opcode::Ret || op == Opcode::Br || op == Opcode::CondBr ||
op == Opcode::Store || op == Opcode::Call) {
return true;
}
return false;
}
bool RunDCE(Function& func) {
if (func.IsExternal()) return false;
bool changed = false;
// 标记阶段
std::unordered_set<Instruction*> useful;
std::queue<Instruction*> worklist;
// 初始标记:所有有副作用的指令
for (const auto& bb : func.GetBlocks()) {
if (!bb) continue;
for (const auto& inst_ptr : bb->GetInstructions()) {
auto* inst = inst_ptr.get();
if (HasSideEffect(inst)) {
useful.insert(inst);
worklist.push(inst);
}
}
}
// 反向传播:有用指令的操作数定义也标记为有用
while (!worklist.empty()) {
auto* inst = worklist.front();
worklist.pop();
for (size_t i = 0; i < inst->GetNumOperands(); ++i) {
auto* operand = inst->GetOperand(i);
if (!operand) continue;
auto* def_inst = dynamic_cast<Instruction*>(operand);
if (def_inst && !useful.count(def_inst)) {
useful.insert(def_inst);
worklist.push(def_inst);
}
}
}
// 清扫阶段:删除未标记为有用的指令
for (const auto& bb : func.GetBlocks()) {
if (!bb) continue;
std::vector<Instruction*> to_remove;
for (const auto& inst_ptr : bb->GetInstructions()) {
auto* inst = inst_ptr.get();
if (!useful.count(inst)) {
to_remove.push_back(inst);
}
}
for (auto* inst : to_remove) {
// 如果还有使用者,不能直接删除(用 undef/0 替换)
// 在标记-清扫正确的前提下,未标记的指令不应有有用的使用者
// 但安全起见,先检查
if (!inst->GetUses().empty()) {
// 仍有使用者 —— 跳过(可能是循环引用的 phi
continue;
}
bb->RemoveInstruction(inst);
changed = true;
}
}
return changed;
}
// 简化版 DCE只删除没有使用者且无副作用的指令更安全的实现
bool RunSimpleDCE(Function& func) {
if (func.IsExternal()) return false;
bool changed = false;
bool local_changed = true;
while (local_changed) {
local_changed = false;
for (const auto& bb : func.GetBlocks()) {
if (!bb) continue;
std::vector<Instruction*> to_remove;
for (const auto& inst_ptr : bb->GetInstructions()) {
auto* inst = inst_ptr.get();
// 跳过有副作用的指令
if (HasSideEffect(inst)) continue;
// 跳过 alloca可能后续还会用到
if (inst->GetOpcode() == Opcode::Alloca) continue;
// 如果没有使用者,可以安全删除
if (inst->GetUses().empty()) {
to_remove.push_back(inst);
}
}
for (auto* inst : to_remove) {
bb->RemoveInstruction(inst);
local_changed = true;
changed = true;
}
}
}
return changed;
}
} // namespace passes
} // namespace ir

@ -1,336 +0,0 @@
// Mem2RegSSA 构造):
// - 将局部变量的 alloca/load/store 提升为 SSA 形式
// - 插入 PHI 并重写使用,依赖支配树等分析
//
// 算法流程:
// 1. 识别可提升的 alloca标量仅通过 load/store 访问)
// 2. 计算支配树与支配边界
// 3. 在支配边界处插入 phi
// 4. 沿支配树重命名变量
// 5. 删除冗余 alloca/load/store
#include "ir/IR.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace ir {
namespace passes {
// ============ 内联支配树(与 analysis 版本相同) ============
namespace {
class DomTree {
public:
explicit DomTree(Function& func) : func_(func) { Compute(); }
BasicBlock* GetIDom(BasicBlock* bb) const {
auto it = idom_.find(bb);
return it != idom_.end() ? it->second : nullptr;
}
const std::vector<BasicBlock*>& GetDF(BasicBlock* bb) const {
static const std::vector<BasicBlock*> empty;
auto it = df_.find(bb);
return it != df_.end() ? it->second : empty;
}
const std::vector<BasicBlock*>& GetChildren(BasicBlock* bb) const {
static const std::vector<BasicBlock*> empty;
auto it = children_.find(bb);
return it != children_.end() ? it->second : empty;
}
const std::vector<BasicBlock*>& GetRPO() const { return rpo_; }
private:
void Compute() {
auto* entry = func_.GetEntry();
if (!entry) return;
ComputeRPO(entry);
if (rpo_.empty()) return;
for (auto* bb : rpo_) {
idom_[bb] = nullptr;
rpo_index_[bb] = 0;
}
for (size_t i = 0; i < rpo_.size(); ++i) {
rpo_index_[rpo_[i]] = i;
}
idom_[entry] = entry;
bool changed = true;
while (changed) {
changed = false;
for (auto* bb : rpo_) {
if (bb == entry) continue;
BasicBlock* new_idom = nullptr;
for (auto* pred : bb->GetPredecessors()) {
if (idom_.count(pred) && idom_[pred] != nullptr) {
if (!new_idom) {
new_idom = pred;
} else {
new_idom = Intersect(new_idom, pred);
}
}
}
if (new_idom && idom_[bb] != new_idom) {
idom_[bb] = new_idom;
changed = true;
}
}
}
for (auto* bb : rpo_) {
auto* p = GetIDom(bb);
if (p && p != bb) {
children_[p].push_back(bb);
}
}
ComputeDF();
}
void ComputeRPO(BasicBlock* entry) {
std::unordered_set<BasicBlock*> visited;
std::vector<BasicBlock*> post_order;
std::function<void(BasicBlock*)> dfs = [&](BasicBlock* bb) {
visited.insert(bb);
for (auto* succ : bb->GetSuccessors()) {
if (!visited.count(succ)) {
dfs(succ);
}
}
post_order.push_back(bb);
};
dfs(entry);
rpo_.assign(post_order.rbegin(), post_order.rend());
}
BasicBlock* Intersect(BasicBlock* b1, BasicBlock* b2) {
while (b1 != b2) {
while (rpo_index_[b1] > rpo_index_[b2]) b1 = idom_[b1];
while (rpo_index_[b2] > rpo_index_[b1]) b2 = idom_[b2];
}
return b1;
}
void ComputeDF() {
for (auto* bb : rpo_) {
df_[bb] = {};
}
for (auto* bb : rpo_) {
if (bb->GetPredecessors().size() < 2) continue;
for (auto* pred : bb->GetPredecessors()) {
auto* runner = pred;
while (runner && runner != idom_[bb]) {
auto& df_set = df_[runner];
if (std::find(df_set.begin(), df_set.end(), bb) == df_set.end()) {
df_set.push_back(bb);
}
if (runner == idom_[runner]) break;
runner = idom_[runner];
}
}
}
}
Function& func_;
std::vector<BasicBlock*> rpo_;
std::unordered_map<BasicBlock*, size_t> rpo_index_;
std::unordered_map<BasicBlock*, BasicBlock*> idom_;
std::unordered_map<BasicBlock*, std::vector<BasicBlock*>> children_;
std::unordered_map<BasicBlock*, std::vector<BasicBlock*>> df_;
};
// 判断一个 alloca 是否可以被提升为寄存器:
// - 必须是标量count == 1
// - 只被 load 和 store 使用
bool IsPromotable(AllocaInst* alloca) {
if (alloca->IsArray()) return false;
for (const auto& use : alloca->GetUses()) {
auto* user = use.GetUser();
if (!user) return false;
auto* inst = dynamic_cast<Instruction*>(user);
if (!inst) return false;
if (inst->GetOpcode() != Opcode::Load &&
inst->GetOpcode() != Opcode::Store) {
return false;
}
// store 只能把 alloca 作为 ptroperand 1不能作为 valoperand 0
if (inst->GetOpcode() == Opcode::Store) {
auto* store = static_cast<StoreInst*>(inst);
if (store->GetPtr() != alloca) return false;
}
}
return true;
}
} // namespace
bool RunMem2Reg(Function& func) {
if (func.IsExternal()) return false;
DomTree dom(func);
// 1. 收集可提升的 alloca
std::vector<AllocaInst*> promotable;
auto* entry = func.GetEntry();
if (!entry) return false;
for (const auto& inst : entry->GetInstructions()) {
if (auto* alloca = dynamic_cast<AllocaInst*>(inst.get())) {
if (IsPromotable(alloca)) {
promotable.push_back(alloca);
}
}
}
if (promotable.empty()) return false;
// 对每个可提升的 alloca 分别执行
for (auto* alloca : promotable) {
// 确定 alloca 值的类型
std::shared_ptr<Type> val_type;
if (alloca->GetType()->IsPtrInt32()) {
val_type = Type::GetInt32Type();
} else if (alloca->GetType()->IsPtrFloat32()) {
val_type = Type::GetFloat32Type();
} else {
continue;
}
// 2. 收集所有 def 块(包含 store 的块)和 use 块(包含 load 的块)
std::unordered_set<BasicBlock*> def_blocks;
std::vector<StoreInst*> stores;
std::vector<LoadInst*> loads;
for (const auto& use : alloca->GetUses()) {
auto* inst = dynamic_cast<Instruction*>(use.GetUser());
if (!inst || !inst->GetParent()) continue;
if (auto* store = dynamic_cast<StoreInst*>(inst)) {
if (store->GetPtr() == alloca) {
def_blocks.insert(store->GetParent());
stores.push_back(store);
}
} else if (auto* load = dynamic_cast<LoadInst*>(inst)) {
loads.push_back(load);
}
}
// 3. 插入 phi 节点(使用迭代支配边界)
// 用 map 精确记录当前 alloca 在每个块中插入的 phi
std::unordered_map<BasicBlock*, PhiInst*> phi_map;
std::unordered_set<BasicBlock*> phi_blocks;
std::queue<BasicBlock*> worklist;
for (auto* bb : def_blocks) {
worklist.push(bb);
}
static int phi_counter = 0;
while (!worklist.empty()) {
auto* bb = worklist.front();
worklist.pop();
for (auto* df_bb : dom.GetDF(bb)) {
if (!phi_blocks.count(df_bb)) {
phi_blocks.insert(df_bb);
auto* phi = df_bb->PrependPhi(val_type,
"%phi." + std::to_string(phi_counter++));
phi_map[df_bb] = phi;
worklist.push(df_bb);
}
}
}
// 4. 重命名:沿支配树 DFS
std::stack<Value*> val_stack;
std::function<void(BasicBlock*)> Rename = [&](BasicBlock* bb) {
size_t stack_size = val_stack.size();
// 处理当前块中我们插入的 phi
auto phi_it = phi_map.find(bb);
if (phi_it != phi_map.end()) {
val_stack.push(phi_it->second);
}
// 遍历块中所有指令
std::vector<Instruction*> to_remove;
for (auto& inst_ptr : bb->GetInstructions()) {
auto* inst = inst_ptr.get();
if (auto* store = dynamic_cast<StoreInst*>(inst)) {
if (store->GetPtr() == alloca) {
val_stack.push(store->GetValue());
to_remove.push_back(store);
}
} else if (auto* load = dynamic_cast<LoadInst*>(inst)) {
if (load->GetPtr() == alloca) {
Value* cur_val = val_stack.empty() ? nullptr : val_stack.top();
if (cur_val) {
load->ReplaceAllUsesWith(cur_val);
}
to_remove.push_back(load);
}
}
}
// 填充后继块中 phi 的入边
for (auto* succ : bb->GetSuccessors()) {
auto succ_phi_it = phi_map.find(succ);
if (succ_phi_it == phi_map.end()) continue;
Value* cur_val = val_stack.empty() ? nullptr : val_stack.top();
if (cur_val) {
succ_phi_it->second->AddIncoming(cur_val, bb);
}
}
// 递归处理支配树的孩子
for (auto* child : dom.GetChildren(bb)) {
Rename(child);
}
// 恢复栈
while (val_stack.size() > stack_size) {
val_stack.pop();
}
// 删除已标记的指令
for (auto* inst : to_remove) {
bb->RemoveInstruction(inst);
}
};
Rename(entry);
// 5. 删除 alloca
entry->RemoveInstruction(alloca);
// 6. 清理没有入边的 phi
for (auto* bb : dom.GetRPO()) {
std::vector<Instruction*> dead_phis;
for (auto& inst_ptr : bb->GetInstructions()) {
auto* phi = dynamic_cast<PhiInst*>(inst_ptr.get());
if (!phi) break;
if (phi->GetNumIncoming() == 0) {
dead_phis.push_back(phi);
}
// 如果 phi 只有一个入边,直接替换为该值
if (phi->GetNumIncoming() == 1) {
phi->ReplaceAllUsesWith(phi->GetIncomingValue(0));
dead_phis.push_back(phi);
}
}
for (auto* phi : dead_phis) {
bb->RemoveInstruction(phi);
}
}
}
return true;
}
} // namespace passes
} // namespace ir
Loading…
Cancel
Save