diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp --- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp @@ -1026,8 +1026,25 @@ /// until we reach a value that dominates InsertPos. bool SCEVExpander::hoistIVInc(Instruction *IncV, Instruction *InsertPos, bool RecomputePoisonFlags) { - if (SE.DT.dominates(IncV, InsertPos)) - return true; + auto FixupPoisonFlags = [this](Instruction *I) { + // Drop flags that are potentially inferred from old context and infer flags + // in new context. + I->dropPoisonGeneratingFlags(); + if (auto *OBO = dyn_cast(I)) + if (auto Flags = SE.getStrengthenedNoWrapFlagsFromBinOp(OBO)) { + auto *BO = cast(I); + BO->setHasNoUnsignedWrap( + ScalarEvolution::maskFlags(*Flags, SCEV::FlagNUW) == SCEV::FlagNUW); + BO->setHasNoSignedWrap( + ScalarEvolution::maskFlags(*Flags, SCEV::FlagNSW) == SCEV::FlagNSW); + } + }; + + if (SE.DT.dominates(IncV, InsertPos)) { + if (RecomputePoisonFlags) + FixupPoisonFlags(IncV); + return true; + } // InsertPos must itself dominate IncV so that IncV's new position satisfies // its existing users. @@ -1053,19 +1070,8 @@ for (Instruction *I : llvm::reverse(IVIncs)) { fixupInsertPoints(I); I->moveBefore(InsertPos); - if (!RecomputePoisonFlags) - continue; - // Drop flags that are potentially inferred from old context and infer flags - // in new context. - I->dropPoisonGeneratingFlags(); - if (auto *OBO = dyn_cast(I)) - if (auto Flags = SE.getStrengthenedNoWrapFlagsFromBinOp(OBO)) { - auto *BO = cast(I); - BO->setHasNoUnsignedWrap( - ScalarEvolution::maskFlags(*Flags, SCEV::FlagNUW) == SCEV::FlagNUW); - BO->setHasNoSignedWrap( - ScalarEvolution::maskFlags(*Flags, SCEV::FlagNSW) == SCEV::FlagNSW); - } + if (RecomputePoisonFlags) + FixupPoisonFlags(I); } return true; } diff --git a/llvm/test/Transforms/IndVarSimplify/iv-poison.ll b/llvm/test/Transforms/IndVarSimplify/iv-poison.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/IndVarSimplify/iv-poison.ll @@ -0,0 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=indvars -S < %s | FileCheck %s + +; PR59777 +define i2 @iv_hoist_nsw_poison(i2 %arg) { +; CHECK-LABEL: @iv_hoist_nsw_poison( +; CHECK-NEXT: bb: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[DOT07:%.*]] = phi i2 [ 1, [[BB:%.*]] ], [ [[I:%.*]], [[BB1]] ] +; CHECK-NEXT: [[I]] = add nuw nsw i2 [[DOT07]], 1 +; CHECK-NEXT: [[DOTNOT_NOT:%.*]] = icmp ult i2 1, [[ARG:%.*]] +; CHECK-NEXT: br i1 [[DOTNOT_NOT]], label [[COMMON_RET:%.*]], label [[BB1]] +; CHECK: common.ret: +; CHECK-NEXT: [[I2_LCSSA:%.*]] = phi i2 [ [[I]], [[BB1]] ] +; CHECK-NEXT: ret i2 [[I2_LCSSA]] +; +bb: + br label %bb1 + +bb1: ; preds = %bb1, %bb + %.07 = phi i2 [ 1, %bb ], [ %i, %bb1 ] + %.0 = phi i2 [ 1, %bb ], [ %i2, %bb1 ] + %i = add nsw i2 %.07, 1 + %i2 = add i2 %.0, 1 + %.not.not = icmp ult i2 %.07, %arg + br i1 %.not.not, label %common.ret, label %bb1 + +common.ret: ; preds = %bb1 + ret i2 %i2 +}