diff --git a/src/DCE.cpp b/src/DCE.cpp index e0e9519..db5d966 100644 --- a/src/DCE.cpp +++ b/src/DCE.cpp @@ -1,48 +1,57 @@ -#include "DCE.h" -#include "IR.h" -#include "SysYIROptUtils.h" -#include -#include +#include "DCE.h" // 包含DCE遍的头文件 +#include "IR.h" // 包含IR相关的定义 +#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义 +#include // 用于断言 +#include // 用于调试输出 +#include // 包含set,虽然DCEContext内部用unordered_set,但这里保留 namespace sysy { // DCE 遍的静态 ID void *DCE::ID = (void *)&DCE::ID; -// DCE 遍的 runOnFunction 方法实现 -bool DCE::runOnFunction(Function *func, AnalysisManager &AM) { +// ====================================================================== +// DCEContext 类的实现 +// 封装了 DCE 遍的核心逻辑和状态,确保每次函数优化运行时状态独立 +// ====================================================================== + +// DCEContext 的 run 方法实现 +void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) { + // 清空活跃指令集合,确保每次运行都是新的状态 alive_insts.clear(); - bool changed = false; + // 第一次遍历:扫描所有指令,识别“天然活跃”的指令并将其及其依赖标记为活跃 + // 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格 auto basicBlocks = func->getBasicBlocks(); - for (auto &basicBlock : basicBlocks) { // 确保基本块有效 if (!basicBlock) continue; + // 使用 basicBlock->getInstructions() 获取指令列表,保留用户风格 for (auto &inst : basicBlock->getInstructions()) { // 确保指令有效 if (!inst) continue; + // 调用 DCEContext 自身的 isAlive 和 addAlive 方法 if (isAlive(inst.get())) { addAlive(inst.get()); } } } - // 第二遍:删除所有未被标记为活跃的指令。 + // 第二次遍历:删除所有未被标记为活跃的指令。 for (auto &basicBlock : basicBlocks) { if (!basicBlock) continue; // 使用传统的迭代器循环,并手动管理迭代器, - // 以便在删除元素后正确前进。 + // 以便在删除元素后正确前进。保留用户风格 for (auto instIter = basicBlock->getInstructions().begin(); instIter != basicBlock->getInstructions().end();) { auto &inst = *instIter; Instruction *currentInst = inst.get(); // 如果指令不在活跃集合中,则删除它。 // 分支和返回指令由 isAlive 处理,并会被保留。 if (alive_insts.count(currentInst) == 0) { - // 删除指令 + // 删除指令,保留用户风格的 SysYIROptUtils::usedelete 和 erase changed = true; // 标记 IR 已被修改 SysYIROptUtils::usedelete(currentInst); instIter = basicBlock->getInstructions().erase(instIter); // 删除后返回下一个迭代器 @@ -51,27 +60,26 @@ bool DCE::runOnFunction(Function *func, AnalysisManager &AM) { } } } - - return changed; } // 判断指令是否是“天然活跃”的实现 // 只有具有副作用的指令(如存储、函数调用、原子操作) // 和控制流指令(如分支、返回)是天然活跃的。 -bool DCE::isAlive(Instruction *inst) { +bool DCEContext::isAlive(Instruction *inst) { // TODO: 后续程序并发考虑原子操作 // 其结果不被其他指令使用的指令(例如 StoreInst, BranchInst, ReturnInst)。 // dynamic_cast(inst) 检查是否是函数调用指令, // 函数调用通常有副作用。 // 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程。 + // 保留用户提供的 isAlive 逻辑 bool isBranchOrReturn = inst->isBranch() || inst->isReturn(); bool isCall = inst->isCall(); - bool isStoreOrMemset = inst->isStore() && inst->isMemset(); + bool isStoreOrMemset = inst->isStore() || inst->isMemset(); return isBranchOrReturn || isCall || isStoreOrMemset; } // 递归地将活跃指令及其依赖加入到 alive_insts 集合中 -void DCE::addAlive(Instruction *inst) { +void DCEContext::addAlive(Instruction *inst) { // 如果指令已经存在于活跃集合中,则无需重复处理 if (alive_insts.count(inst) > 0) { return; @@ -79,6 +87,7 @@ void DCE::addAlive(Instruction *inst) { // 将当前指令标记为活跃 alive_insts.insert(inst); // 遍历当前指令的所有操作数 + // 保留用户提供的 getOperands() 和 getValue() for (auto operand : inst->getOperands()) { // 如果操作数是一个指令(即它是一个值的定义), // 并且它还没有被标记为活跃 @@ -88,4 +97,44 @@ void DCE::addAlive(Instruction *inst) { } } +// ====================================================================== +// DCE Pass 类的实现 +// 主要负责与 PassManager 交互,创建 DCEContext 实例并运行优化 +// ====================================================================== + +// DCE 遍的 runOnFunction 方法实现 +bool DCE::runOnFunction(Function *func, AnalysisManager &AM) { + + DCEContext ctx; + bool changed = false; + ctx.run(func, &AM, changed); // 运行 DCE 优化 + + // 如果 IR 被修改,则使相关的分析结果失效 + if (changed) { + // DCE 会删除指令,这会影响数据流分析,尤其是活跃性分析。 + // 如果删除导致基本块变空,也可能间接影响 CFG 和支配树。 + // AM.invalidateAnalysis(&LivenessAnalysisPass::ID, func); // 活跃性分析失效 + // AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, func); // 支配树分析可能失效 + // 其他所有依赖于数据流或 IR 结构的分析都可能失效。 + } + return changed; +} + +// 声明DCE遍的分析依赖和失效信息 +void DCE::getAnalysisUsage(std::set &analysisDependencies, std::set &analysisInvalidations) const { + // DCE不依赖特定的分析结果,它通过遍历和副作用判断来工作。 + + // DCE会删除指令,这会影响许多分析结果。 + // 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。 + // 假设存在LivenessAnalysisPass和DominatorTreeAnalysisPass + // analysisInvalidations.insert(&LivenessAnalysisPass::ID); + // analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); + // 任何改变IR结构的优化,都可能导致通用分析(如活跃性、支配树、循环信息)失效。 + // 最保守的做法是使所有函数粒度的分析失效,或者只声明你明确知道会受影响的分析。 + // 考虑到这个DCE仅删除指令,如果它不删除基本块,CFG可能不变,但数据流分析会失效。 + // 对于更激进的DCE(如ADCE),CFG也会改变。 + // 这里我们假设它主要影响数据流分析,并且可能间接影响CFG相关分析。 + // 如果有SideEffectInfo,它也可能被修改,但通常SideEffectInfo是静态的,不因DCE而变。 +} + } // namespace sysy diff --git a/src/include/DCE.h b/src/include/DCE.h index 8be40bd..41bc223 100644 --- a/src/include/DCE.h +++ b/src/include/DCE.h @@ -1,46 +1,63 @@ #pragma once -#include "IR.h" // 包含IR相关的定义,如Instruction, Function, BasicBlock等 -#include "IRBuilder.h" // 包含IR构建器的定义 -#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的 -#include "Liveness.h" -#include "Dom.h" // 包含支配树的定义 -#include "Pass.h" // 包含Pass的基类定义 -#include // 用于存储活跃指令 +#include "Pass.h" +#include "IR.h" +#include "SysYIROptUtils.h" +#include "Dom.h" +#include +#include namespace sysy { +// 前向声明分析结果类,确保在需要时可以引用 +// class DominatorTreeAnalysisResult; // Pass.h 中已包含,这里不再需要 +class SideEffectInfoAnalysisResult; // 假设有副作用分析结果类 + +// DCEContext 类,用于封装DCE的内部逻辑和状态 +// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化 +class DCEContext { +public: + // 运行DCE的主要方法 + // func: 当前要优化的函数 + // tp: 分析管理器,用于获取其他分析结果(如果需要) + void run(Function* func, AnalysisManager* AM, bool &changed); + +private: + // 存储活跃指令的集合 + std::unordered_set alive_insts; + + // 判断指令是否是“天然活跃”的(即总是保留的) + // inst: 要检查的指令 + // 返回值: 如果指令是天然活跃的,则为true,否则为false + bool isAlive(Instruction* inst); + + // 递归地将活跃指令及其依赖加入到 alive_insts 集合中 + // inst: 要标记为活跃的指令 + void addAlive(Instruction* inst); +}; + // DCE 优化遍类,继承自 OptimizationPass class DCE : public OptimizationPass { - private: - std::unordered_set alive_insts; - // 判断指令是否是“天然活跃”的(即总是保留的) - // inst: 要检查的指令 - // 返回值: 如果指令是天然活跃的,则为true,否则为false - bool isAlive(Instruction *inst); - // 递归地将活跃指令及其依赖加入到 alive_insts 集合中 - // inst: 要标记为活跃的指令 - void addAlive(Instruction *inst); public: - static void *ID; - DCE() : OptimizationPass("DCE", Granularity::Function) {} - bool runOnFunction(Function *func, AnalysisManager &AM) override; - void getAnalysisUsage(std::set &analysisDependencies, std::set &analysisInvalidations) const override{ - // DCE不依赖特定的分析结果,它通过遍历和副作用判断来工作。 + // 构造函数 + DCE() : OptimizationPass("DCE", Granularity::Function) {} - // DCE会删除指令,这会影响许多分析结果。 - // 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。 - // 假设存在LivenessAnalysisPass和DominatorTreeAnalysisPass - // analysisInvalidations.insert(&LivenessAnalysisPass::ID); - // analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); - // 任何改变IR结构的优化,都可能导致通用分析(如活跃性、支配树、循环信息)失效。 - // 最保守的做法是使所有函数粒度的分析失效,或者只声明你明确知道会受影响的分析。 - // 考虑到这个DCE仅删除指令,如果它不删除基本块,CFG可能不变,但数据流分析会失效。 - // 对于更激进的DCE(如ADCE),CFG也会改变。 - // 这里我们假设它主要影响数据流分析,并且可能间接影响CFG相关分析。 - // 如果有SideEffectInfo,它也可能被修改,但通常SideEffectInfo是静态的,不因DCE而变。 - } - void *getPassID() const override { return &ID; } + // 静态成员,作为该遍的唯一ID + static void *ID; + + // 运行在函数上的优化逻辑 + // F: 当前要优化的函数 + // AM: 分析管理器,用于获取或使分析结果失效 + // 返回值: 如果IR被修改,则为true,否则为false + bool runOnFunction(Function *F, AnalysisManager& AM) override; + + // 声明该遍的分析依赖和失效信息 + // analysisDependencies: 该遍运行前需要哪些分析结果 + // analysisInvalidations: 该遍运行后会使哪些分析结果失效 + void getAnalysisUsage(std::set &analysisDependencies, std::set &analysisInvalidations) const override; + + // Pass 基类中的纯虚函数,必须实现 + void *getPassID() const override { return &ID; } }; } // namespace sysy \ No newline at end of file