[midend-LICM][fix]修复循环不变量的识别逻辑
This commit is contained in:
@ -350,7 +350,11 @@ private:
|
|||||||
std::set<Value*>& visited
|
std::set<Value*>& visited
|
||||||
);
|
);
|
||||||
bool isBasicInductionVariable(Value* val, Loop* loop);
|
bool isBasicInductionVariable(Value* val, Loop* loop);
|
||||||
bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
|
// ========== 循环不变量分析辅助方法 ==========
|
||||||
|
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||||
|
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
|
||||||
|
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
|
||||||
|
bool isPureFunction(Function* calledFunc);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@ -776,38 +776,282 @@ void LoopCharacteristicsPass::findDerivedInductionVars(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归/推进式判定
|
// 检查操作数是否都是不变量
|
||||||
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
|
bool LoopCharacteristicsPass::isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants) {
|
||||||
// 1. 常量
|
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||||
if (auto* constval = dynamic_cast<ConstantValue*>(val)) return true;
|
Value* op = inst->getOperand(i);
|
||||||
|
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op)) {
|
||||||
// 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量
|
|
||||||
if (auto* arg = dynamic_cast<Argument*>(val)) return true;
|
|
||||||
|
|
||||||
// 3. 指令且定义在循环外
|
|
||||||
if (auto* inst = dynamic_cast<Instruction*>(val)) {
|
|
||||||
if (!loop->contains(inst->getParent()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// 4. 跳转 phi指令 副作用 不外提
|
|
||||||
if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst))
|
|
||||||
return false;
|
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<StoreInst*>(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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) {
|
// 检查内存位置是否在循环中被读取
|
||||||
// 检查是否有简单的内存访问模式
|
bool LoopCharacteristicsPass::isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst) {
|
||||||
return true; // 暂时简化处理
|
// 遍历循环中的所有Load指令,检查是否有对该内存位置的读取
|
||||||
|
for (BasicBlock* bb : loop->getBlocks()) {
|
||||||
|
for (auto& inst : bb->getInstructions()) {
|
||||||
|
if (inst.get() == excludeInst) continue; // 排除当前指令本身
|
||||||
|
|
||||||
|
if (auto* loadInst = dynamic_cast<LoadInst*>(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<std::string> 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<Value*>& invariants) {
|
||||||
|
if (DEBUG >= 2) {
|
||||||
|
std::cout << " Checking loop invariant for: " << val->getName() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 常量
|
||||||
|
if (auto* constval = dynamic_cast<ConstantValue*>(val)) {
|
||||||
|
if (DEBUG >= 2) std::cout << " -> Constant: YES" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 参数(函数参数)通常不在任何BasicBlock内,直接判定为不变量
|
||||||
|
// 在SSA形式下,参数不会被重新赋值
|
||||||
|
if (auto* arg = dynamic_cast<Argument*>(val)) {
|
||||||
|
if (DEBUG >= 2) std::cout << " -> Function argument: YES" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 指令且定义在循环外
|
||||||
|
if (auto* inst = dynamic_cast<Instruction*>(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<StoreInst*>(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<LoadInst*>(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<CallInst*>(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
|
} // namespace sysy
|
||||||
|
|||||||
@ -55,10 +55,11 @@ bool LICMContext::hoistInstructions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
|
// 检查是否全部排序,若未全部排序,打印错误信息
|
||||||
|
// 这可能是因为存在循环依赖或其他问题导致无法完成拓扑排序
|
||||||
if (sorted.size() != workSet.size()) {
|
if (sorted.size() != workSet.size()) {
|
||||||
if (DEBUG)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -153,14 +153,31 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
this->clearPasses();
|
this->clearPasses();
|
||||||
this->addPass(&LoopNormalizationPass::ID);
|
this->addPass(&LoopNormalizationPass::ID);
|
||||||
this->addPass(&InductionVariableElimination::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->addPass(&LoopStrengthReduction::ID);
|
||||||
this->run();
|
this->run();
|
||||||
|
|
||||||
// if(DEBUG) {
|
if(DEBUG) {
|
||||||
// std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n";
|
std::cout << "=== IR After Loop Normalization, and Strength Reduction Optimizations ===\n";
|
||||||
// printPasses();
|
printPasses();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// this->clearPasses();
|
// this->clearPasses();
|
||||||
// this->addPass(&Reg2Mem::ID);
|
// this->addPass(&Reg2Mem::ID);
|
||||||
|
|||||||
Reference in New Issue
Block a user