From d83dc7a2e7f4cb2f2e06f1fe8c18c796b83b48a1 Mon Sep 17 00:00:00 2001 From: rain2133 <1370973498@qq.com> Date: Sun, 17 Aug 2025 01:19:44 +0800 Subject: [PATCH] =?UTF-8?q?[midend-LICM][fix]=E4=BF=AE=E5=A4=8D=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E4=B8=8D=E5=8F=98=E9=87=8F=E7=9A=84=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pass/Analysis/LoopCharacteristics.h | 6 +- .../Pass/Analysis/LoopCharacteristics.cpp | 296 ++++++++++++++++-- src/midend/Pass/Optimize/LICM.cpp | 5 +- src/midend/Pass/Pass.cpp | 27 +- 4 files changed, 300 insertions(+), 34 deletions(-) diff --git a/src/include/midend/Pass/Analysis/LoopCharacteristics.h b/src/include/midend/Pass/Analysis/LoopCharacteristics.h index e5ccafb..1f4a7ae 100644 --- a/src/include/midend/Pass/Analysis/LoopCharacteristics.h +++ b/src/include/midend/Pass/Analysis/LoopCharacteristics.h @@ -350,7 +350,11 @@ private: std::set& visited ); bool isBasicInductionVariable(Value* val, Loop* loop); - bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查 + // ========== 循环不变量分析辅助方法 ========== + bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set& invariants); + bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop); + bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr); + bool isPureFunction(Function* calledFunc); }; } // namespace sysy diff --git a/src/midend/Pass/Analysis/LoopCharacteristics.cpp b/src/midend/Pass/Analysis/LoopCharacteristics.cpp index daef567..eb58af1 100644 --- a/src/midend/Pass/Analysis/LoopCharacteristics.cpp +++ b/src/midend/Pass/Analysis/LoopCharacteristics.cpp @@ -776,38 +776,282 @@ void LoopCharacteristicsPass::findDerivedInductionVars( } } -// 递归/推进式判定 -bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set& invariants) { - // 1. 常量 - if (auto* constval = dynamic_cast(val)) return true; - - // 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量 - if (auto* arg = dynamic_cast(val)) return true; - - // 3. 指令且定义在循环外 - if (auto* inst = dynamic_cast(val)) { - if (!loop->contains(inst->getParent())) - return true; - - // 4. 跳转 phi指令 副作用 不外提 - if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst)) +// 检查操作数是否都是不变量 +bool LoopCharacteristicsPass::isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set& invariants) { + for (size_t i = 0; i < inst->getNumOperands(); ++i) { + Value* op = inst->getOperand(i); + if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op)) { return false; - - // 5. 所有操作数都是不变量 - for (size_t i = 0; i < inst->getNumOperands(); ++i) { - Value* op = inst->getOperand(i); - if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op)) - return false; } - return true; } - // 其它情况 + return true; +} + +// 检查内存位置是否在循环中被修改 +bool LoopCharacteristicsPass::isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop) { + // 遍历循环中的所有Store指令,检查是否有对该内存位置的写入 + for (BasicBlock* bb : loop->getBlocks()) { + for (auto& inst : bb->getInstructions()) { + if (auto* storeInst = dynamic_cast(inst.get())) { + Value* storeTar = storeInst->getPointer(); + + // 使用别名分析检查是否可能别名 + if (aliasAnalysis) { + auto aliasType = aliasAnalysis->queryAlias(ptr, storeTar); + if (aliasType != AliasType::NO_ALIAS) { + if (DEBUG) { + std::cout << " Memory location " << ptr->getName() + << " may be modified by store to " << storeTar->getName() << std::endl; + } + return true; + } + } else { + // 如果没有别名分析,保守处理 - 只检查精确匹配 + if (ptr == storeTar) { + return true; + } + } + } + } + } return false; } -bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) { - // 检查是否有简单的内存访问模式 - return true; // 暂时简化处理 +// 检查内存位置是否在循环中被读取 +bool LoopCharacteristicsPass::isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst) { + // 遍历循环中的所有Load指令,检查是否有对该内存位置的读取 + for (BasicBlock* bb : loop->getBlocks()) { + for (auto& inst : bb->getInstructions()) { + if (inst.get() == excludeInst) continue; // 排除当前指令本身 + + if (auto* loadInst = dynamic_cast(inst.get())) { + Value* loadSrc = loadInst->getPointer(); + + // 使用别名分析检查是否可能别名 + if (aliasAnalysis) { + auto aliasType = aliasAnalysis->queryAlias(ptr, loadSrc); + if (aliasType != AliasType::NO_ALIAS) { + return true; + } + } else { + // 如果没有别名分析,保守处理 - 只检查精确匹配 + if (ptr == loadSrc) { + return true; + } + } + } + } + } + return false; } +// 检查函数调用是否为纯函数 +bool LoopCharacteristicsPass::isPureFunction(Function* calledFunc) { + if (!calledFunc) return false; + + // 使用副作用分析检查函数是否为纯函数 + if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(calledFunc)) { + return true; + } + + // 检查是否为内置纯函数(如数学函数) + std::string funcName = calledFunc->getName(); + static const std::set pureFunctions = { + "abs", "fabs", "sqrt", "sin", "cos", "tan", "exp", "log", "pow", + "floor", "ceil", "round", "min", "max" + }; + + return pureFunctions.count(funcName) > 0; +} + +// 递归/推进式判定 - 完善版本 +bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set& invariants) { + if (DEBUG >= 2) { + std::cout << " Checking loop invariant for: " << val->getName() << std::endl; + } + + // 1. 常量 + if (auto* constval = dynamic_cast(val)) { + if (DEBUG >= 2) std::cout << " -> Constant: YES" << std::endl; + return true; + } + + // 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量 + // 在SSA形式下,参数不会被重新赋值 + if (auto* arg = dynamic_cast(val)) { + if (DEBUG >= 2) std::cout << " -> Function argument: YES" << std::endl; + return true; + } + + // 3. 指令且定义在循环外 + if (auto* inst = dynamic_cast(val)) { + if (!loop->contains(inst->getParent())) { + if (DEBUG >= 2) std::cout << " -> Defined outside loop: YES" << std::endl; + return true; + } + + // 4. 跳转指令、phi指令不能外提 + if (inst->isTerminator() || inst->isPhi()) { + if (DEBUG >= 2) std::cout << " -> Terminator or PHI: NO" << std::endl; + return false; + } + + // 5. 根据指令类型进行具体分析 + switch (inst->getKind()) { + case Instruction::Kind::kStore: { + // Store指令:检查循环内是否有对该内存的load + auto* storeInst = dynamic_cast(inst); + Value* storePtr = storeInst->getPointer(); + + // 首先检查操作数是否不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Store: operands not invariant: NO" << std::endl; + return false; + } + + // 检查是否有对该内存位置的load + if (isMemoryLocationLoadedInLoop(storePtr, loop, inst)) { + if (DEBUG >= 2) std::cout << " -> Store: memory location loaded in loop: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Store: safe to hoist: YES" << std::endl; + return true; + } + + case Instruction::Kind::kLoad: { + // Load指令:检查循环内是否有对该内存的store + auto* loadInst = dynamic_cast(inst); + Value* loadPtr = loadInst->getPointer(); + + // 首先检查指针操作数是否不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Load: pointer not invariant: NO" << std::endl; + return false; + } + + // 检查是否有对该内存位置的store + if (isMemoryLocationModifiedInLoop(loadPtr, loop)) { + if (DEBUG >= 2) std::cout << " -> Load: memory location modified in loop: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Load: safe to hoist: YES" << std::endl; + return true; + } + + case Instruction::Kind::kCall: { + // Call指令:检查是否为纯函数且参数不变 + auto* callInst = dynamic_cast(inst); + Function* calledFunc = callInst->getCallee(); + + // 检查是否为纯函数 + if (!isPureFunction(calledFunc)) { + if (DEBUG >= 2) std::cout << " -> Call: not pure function: NO" << std::endl; + return false; + } + + // 检查参数是否都不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Call: arguments not invariant: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Call: pure function with invariant args: YES" << std::endl; + return true; + } + + case Instruction::Kind::kGetElementPtr: { + // GEP指令:检查基址和索引是否都不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> GEP: base or indices not invariant: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> GEP: base and indices invariant: YES" << std::endl; + return true; + } + + // 一元运算指令 + case Instruction::Kind::kNeg: + case Instruction::Kind::kNot: + case Instruction::Kind::kFNeg: + case Instruction::Kind::kFNot: + case Instruction::Kind::kFtoI: + case Instruction::Kind::kItoF: + case Instruction::Kind::kBitItoF: + case Instruction::Kind::kBitFtoI: { + // 检查操作数是否不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Unary op: operand not invariant: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Unary op: operand invariant: YES" << std::endl; + return true; + } + + // 二元运算指令 + case Instruction::Kind::kAdd: + case Instruction::Kind::kSub: + case Instruction::Kind::kMul: + case Instruction::Kind::kDiv: + case Instruction::Kind::kRem: + case Instruction::Kind::kSll: + case Instruction::Kind::kSrl: + case Instruction::Kind::kSra: + case Instruction::Kind::kAnd: + case Instruction::Kind::kOr: + case Instruction::Kind::kFAdd: + case Instruction::Kind::kFSub: + case Instruction::Kind::kFMul: + case Instruction::Kind::kFDiv: + case Instruction::Kind::kICmpEQ: + case Instruction::Kind::kICmpNE: + case Instruction::Kind::kICmpLT: + case Instruction::Kind::kICmpGT: + case Instruction::Kind::kICmpLE: + case Instruction::Kind::kICmpGE: + case Instruction::Kind::kFCmpEQ: + case Instruction::Kind::kFCmpNE: + case Instruction::Kind::kFCmpLT: + case Instruction::Kind::kFCmpGT: + case Instruction::Kind::kFCmpLE: + case Instruction::Kind::kFCmpGE: + case Instruction::Kind::kMulh: { + // 检查所有操作数是否不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Binary op: operands not invariant: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Binary op: operands invariant: YES" << std::endl; + return true; + } + + default: { + // 其他指令:使用副作用分析 + if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) { + if (DEBUG >= 2) std::cout << " -> Other inst: has side effect: NO" << std::endl; + return false; + } + + // 检查操作数是否都不变 + if (!isInvariantOperands(inst, loop, invariants)) { + if (DEBUG >= 2) std::cout << " -> Other inst: operands not invariant: NO" << std::endl; + return false; + } + + if (DEBUG >= 2) std::cout << " -> Other inst: no side effect, operands invariant: YES" << std::endl; + return true; + } + } + } + + // 其它情况 + if (DEBUG >= 2) std::cout << " -> Other value type: NO" << std::endl; + return false; +} + + } // namespace sysy diff --git a/src/midend/Pass/Optimize/LICM.cpp b/src/midend/Pass/Optimize/LICM.cpp index b583066..3193dd3 100644 --- a/src/midend/Pass/Optimize/LICM.cpp +++ b/src/midend/Pass/Optimize/LICM.cpp @@ -55,10 +55,11 @@ bool LICMContext::hoistInstructions() { } } - // 检查是否全部排序,若未全部排序,说明有环(理论上不会) + // 检查是否全部排序,若未全部排序,打印错误信息 + // 这可能是因为存在循环依赖或其他问题导致无法完成拓扑排序 if (sorted.size() != workSet.size()) { if (DEBUG) - std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl; + std::cout << "LICM: Topological sort failed, possible dependency cycle." << std::endl; return false; } diff --git a/src/midend/Pass/Pass.cpp b/src/midend/Pass/Pass.cpp index e5e6aab..09de26e 100644 --- a/src/midend/Pass/Pass.cpp +++ b/src/midend/Pass/Pass.cpp @@ -153,14 +153,31 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR this->clearPasses(); this->addPass(&LoopNormalizationPass::ID); this->addPass(&InductionVariableElimination::ID); - // this->addPass(&LICM::ID); + this->run(); + + if(DEBUG) { + std::cout << "=== IR After Loop Normalization, Induction Variable Elimination ===\n"; + printPasses(); + } + + + this->clearPasses(); + this->addPass(&LICM::ID); + this->run(); + + if(DEBUG) { + std::cout << "=== IR After LICM ===\n"; + printPasses(); + } + + this->clearPasses(); this->addPass(&LoopStrengthReduction::ID); this->run(); - // if(DEBUG) { - // std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n"; - // printPasses(); - // } + if(DEBUG) { + std::cout << "=== IR After Loop Normalization, and Strength Reduction Optimizations ===\n"; + printPasses(); + } // this->clearPasses(); // this->addPass(&Reg2Mem::ID);