diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index e49f7d4f269..242ca836b32 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -784,6 +784,10 @@ namespace llvm { SmallVector, 2>> LoopDispositions; + /// A cache of the predicate "does the given loop contain an instruction + /// that can throw?" + DenseMap LoopMayThrow; + /// Compute a LoopDisposition value. LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L); @@ -1124,6 +1128,12 @@ namespace llvm { /// it is not okay to annotate (+ a b) with in the above example. bool isSCEVExprNeverPoison(const Instruction *I); + /// This is like \c isSCEVExprNeverPoison but it specifically works for + /// instructions that will get mapped to SCEV add recurrences. Return true + /// if \p I will never generate poison under the assumption that \p I is an + /// add recurrence on the loop \p L. + bool isAddRecNeverPoison(const Instruction *I, const Loop *L); + public: ScalarEvolution(Function &F, TargetLibraryInfo &TLI, AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI); diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 10455a4224c..7b637db9ff1 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -3980,8 +3980,6 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) { cast(Accum)->getLoop() == L)) { SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap; - // If the increment doesn't overflow, then neither the addrec nor - // the post-increment will overflow. if (auto BO = MatchBinaryOp(BEValueV)) { if (BO->Opcode == Instruction::Add && BO->LHS == PN) { if (BO->IsNUW) @@ -4012,16 +4010,19 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) { const SCEV *StartVal = getSCEV(StartValueV); const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags); - // Since the no-wrap flags are on the increment, they apply to the - // post-incremented value as well. - if (isLoopInvariant(Accum, L)) - (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags); - // Okay, for the entire analysis of this edge we assumed the PHI // to be symbolic. We now need to go back and purge all of the // entries for the scalars that use the symbolic expression. forgetSymbolicName(PN, SymbolicName); ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV; + + // We can add Flags to the post-inc expression only if we + // know that it us *undefined behavior* for BEValueV to + // overflow. + if (auto *BEInst = dyn_cast(BEValueV)) + if (isLoopInvariant(Accum, L) && isAddRecNeverPoison(BEInst, L)) + (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags); + return PHISCEV; } } @@ -4850,6 +4851,87 @@ bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) { return false; } +bool ScalarEvolution::isAddRecNeverPoison(const Instruction *I, const Loop *L) { + // If we know that \c I can never be poison period, then that's enough. + if (isSCEVExprNeverPoison(I)) + return true; + + // For an add recurrence specifically, we assume that infinite loops without + // side effects are undefined behavior, and then reason as follows: + // + // If the add recurrence is poison in any iteration, it is poison on all + // future iterations (since incrementing poison yields poison). If the result + // of the add recurrence is fed into the loop latch condition and the loop + // does not contain any throws or exiting blocks other than the latch, we now + // have the ability to "choose" whether the backedge is taken or not (by + // choosing a sufficiently evil value for the poison feeding into the branch) + // for every iteration including and after the one in which \p I first became + // poison. There are two possibilities (let's call the iteration in which \p + // I first became poison as K): + // + // 1. In the set of iterations including and after K, the loop body executes + // no side effects. In this case executing the backege an infinte number + // of times will yield undefined behavior. + // + // 2. In the set of iterations including and after K, the loop body executes + // at least one side effect. In this case, that specific instance of side + // effect is control dependent on poison, which also yields undefined + // behavior. + + auto *ExitingBB = L->getExitingBlock(); + auto *LatchBB = L->getLoopLatch(); + if (!ExitingBB || !LatchBB || ExitingBB != LatchBB) + return false; + + SmallPtrSet Pushed; + SmallVector Stack; + + Pushed.insert(I); + for (auto *U : I->users()) + if (Pushed.insert(cast(U)).second) + Stack.push_back(cast(U)); + + bool LatchControlDependentOnPoison = false; + while (!Stack.empty()) { + const Instruction *I = Stack.pop_back_val(); + + for (auto *U : I->users()) { + if (propagatesFullPoison(cast(U))) { + if (Pushed.insert(cast(U)).second) + Stack.push_back(cast(U)); + } else if (auto *BI = dyn_cast(U)) { + assert(BI->isConditional() && "Only possibility!"); + if (BI->getParent() == LatchBB) { + LatchControlDependentOnPoison = true; + break; + } + } + } + } + + if (!LatchControlDependentOnPoison) + return false; + + // Now check if loop is no-throw, and cache the information. In the future, + // we can consider commoning this logic with LICMSafetyInfo into a separate + // analysis pass. + + auto Itr = LoopMayThrow.find(L); + if (Itr == LoopMayThrow.end()) { + bool MayThrow = false; + for (auto *BB : L->getBlocks()) { + MayThrow = any_of(*BB, [](Instruction &I) { return I.mayThrow(); }); + if (MayThrow) + break; + } + auto InsertPair = LoopMayThrow.insert({L, MayThrow}); + assert(InsertPair.second && "We just checked!"); + Itr = InsertPair.first; + } + + return !Itr->second; +} + /// createSCEV - We know that there is no SCEV for the specified value. Analyze /// the expression. /// @@ -5439,6 +5521,8 @@ void ScalarEvolution::forgetLoop(const Loop *L) { // ValuesAtScopes map. for (Loop::iterator I = L->begin(), E = L->end(); I != E; ++I) forgetLoop(*I); + + LoopMayThrow.erase(L); } /// forgetValue - This method should be called by the client when it has diff --git a/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll b/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll index 5c372b5d7b8..f28e66716e1 100644 --- a/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll +++ b/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll @@ -1,6 +1,6 @@ ; ; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s -define void @infer.sext.0(i1* %c, i32 %start) { +define void @infer.sext.0(i1* %c, i32 %start, i32* %buf) { ; CHECK-LABEL: Classifying expressions for: @infer.sext.0 entry: br label %loop @@ -12,6 +12,10 @@ define void @infer.sext.0(i1* %c, i32 %start) { %idx.inc.sext = sext i32 %idx.inc to i64 ; CHECK: %idx.inc.sext = sext i32 %idx.inc to i64 ; CHECK-NEXT: --> {(1 + (sext i32 %start to i64)),+,1}<%loop> + + %buf.gep = getelementptr inbounds i32, i32* %buf, i32 %idx.inc + %val = load i32, i32* %buf.gep + %condition = icmp eq i32 %counter, 1 %counter.inc = add i32 %counter, 1 br i1 %condition, label %exit, label %loop @@ -20,7 +24,7 @@ define void @infer.sext.0(i1* %c, i32 %start) { ret void } -define void @infer.zext.0(i1* %c, i32 %start) { +define void @infer.zext.0(i1* %c, i32 %start, i32* %buf) { ; CHECK-LABEL: Classifying expressions for: @infer.zext.0 entry: br label %loop @@ -32,6 +36,10 @@ define void @infer.zext.0(i1* %c, i32 %start) { %idx.inc.sext = zext i32 %idx.inc to i64 ; CHECK: %idx.inc.sext = zext i32 %idx.inc to i64 ; CHECK-NEXT: --> {(1 + (zext i32 %start to i64)),+,1}<%loop> + + %buf.gep = getelementptr inbounds i32, i32* %buf, i32 %idx.inc + %val = load i32, i32* %buf.gep + %condition = icmp eq i32 %counter, 1 %counter.inc = add i32 %counter, 1 br i1 %condition, label %exit, label %loop diff --git a/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll b/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll index 1a5409d01f6..fa5ab82e064 100644 --- a/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll +++ b/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll @@ -36,7 +36,8 @@ define void @g(i1* %condition) { ; CHECK: %idx.inc2.sext = sext i32 %idx.inc2 to i64 ; CHECK-NEXT: --> {2,+,3}<%loop> - %c = load volatile i1, i1* %condition + %cond.gep = getelementptr inbounds i1, i1* %condition, i32 %idx.inc + %c = load volatile i1, i1* %cond.gep br i1 %c, label %loop, label %exit exit: diff --git a/test/Analysis/ScalarEvolution/nsw.ll b/test/Analysis/ScalarEvolution/nsw.ll index 35de8e78e34..d015717e354 100644 --- a/test/Analysis/ScalarEvolution/nsw.ll +++ b/test/Analysis/ScalarEvolution/nsw.ll @@ -30,15 +30,17 @@ bb: ; preds = %bb1, %bb.nph %tmp8 = add nsw i32 %i.01, 1 ; [#uses=2] ; CHECK: %tmp8 ; CHECK-NEXT: --> {1,+,1}<%bb> + %p.gep = getelementptr double, double* %p, i32 %tmp8 + %p.val = load double, double* %p.gep br label %bb1 bb1: ; preds = %bb %phitmp = sext i32 %tmp8 to i64 ; [#uses=1] ; CHECK: %phitmp ; CHECK-NEXT: --> {1,+,1}<%bb> - %tmp9 = getelementptr double, double* %p, i64 %phitmp ; [#uses=1] + %tmp9 = getelementptr inbounds double, double* %p, i64 %phitmp ; [#uses=1] ; CHECK: %tmp9 -; CHECK-NEXT: --> {(8 + %p),+,8}<%bb> +; CHECK-NEXT: --> {(8 + %p),+,8}<%bb> %tmp10 = load double, double* %tmp9, align 8 ; [#uses=1] %tmp11 = fcmp ogt double %tmp10, 2.000000e+00 ; [#uses=1] br i1 %tmp11, label %bb, label %bb1.return_crit_edge @@ -143,15 +145,15 @@ bb7: ; preds = %bb1 } ; CHECK-LABEL: PR12376 -; CHECK: --> {(4 + %arg),+,4}<%bb2>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (4 + (4 * ((3 + (-1 * %arg) + (%arg umax %arg1)) /u 4)) + %arg) +; CHECK: --> {(4 + %arg),+,4}<%bb2>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (4 + (4 * ((-1 + (-1 * %arg) + ((4 + %arg) umax %arg1)) /u 4)) + %arg) define void @PR12376(i32* nocapture %arg, i32* nocapture %arg1) { bb: br label %bb2 bb2: ; preds = %bb2, %bb %tmp = phi i32* [ %arg, %bb ], [ %tmp4, %bb2 ] - %tmp3 = icmp ult i32* %tmp, %arg1 %tmp4 = getelementptr inbounds i32, i32* %tmp, i64 1 + %tmp3 = icmp ult i32* %tmp4, %arg1 br i1 %tmp3, label %bb2, label %bb5 bb5: ; preds = %bb2 @@ -161,8 +163,8 @@ bb5: ; preds = %bb2 declare void @f(i32) ; CHECK-LABEL: nswnowrap -; CHECK: --> {(1 + %v),+,1}<%for.body>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (2 + %v) -define void @nswnowrap(i32 %v) { +; CHECK: --> {(1 + %v),+,1}<%for.body>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (2 + %v) +define void @nswnowrap(i32 %v, i32* %buf) { entry: %add = add nsw i32 %v, 1 br label %for.body @@ -170,8 +172,10 @@ entry: for.body: %i.04 = phi i32 [ %v, %entry ], [ %inc, %for.body ] %inc = add nsw i32 %i.04, 1 - tail call void @f(i32 %i.04) + %buf.gep = getelementptr inbounds i32, i32* %buf, i32 %inc + %buf.val = load i32, i32* %buf.gep %cmp = icmp slt i32 %i.04, %add + tail call void @f(i32 %i.04) br i1 %cmp, label %for.body, label %for.end for.end: diff --git a/test/Analysis/ScalarEvolution/pr27315.ll b/test/Analysis/ScalarEvolution/pr27315.ll new file mode 100644 index 00000000000..8f5f79df563 --- /dev/null +++ b/test/Analysis/ScalarEvolution/pr27315.ll @@ -0,0 +1,31 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +declare i1 @use(i64) + +define void @f_0() { +; CHECK-LABEL: Classifying expressions for: @f_0 + +; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.inc.nowrap, %be ] +; CHECK-NEXT: --> {0,+,1}<%loop> +; CHECK: %iv.inc.maywrap = add i32 %iv, 1 +; CHECK-NEXT: --> {1,+,1}<%loop> +; CHECK: %iv.inc.maywrap.sext = sext i32 %iv.inc.maywrap to i64 +; CHECK-NEXT: --> (sext i32 {1,+,1}<%loop> to i64) +entry: + br label %loop + +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.inc.nowrap, %be ] + %iv.inc.maywrap = add i32 %iv, 1 + %iv.inc.maywrap.sext = sext i32 %iv.inc.maywrap to i64 + %cond0 = call i1 @use(i64 %iv.inc.maywrap.sext) + br i1 %cond0, label %be, label %leave + +be: + %iv.inc.nowrap = add nsw i32 %iv, 1 + %be.cond = call i1 @use(i64 0) ;; Get an unanalyzable value + br i1 %be.cond, label %loop, label %leave + +leave: + ret void +} diff --git a/test/Transforms/IndVarSimplify/elim-extend.ll b/test/Transforms/IndVarSimplify/elim-extend.ll index 98701c33852..8daac23ea74 100644 --- a/test/Transforms/IndVarSimplify/elim-extend.ll +++ b/test/Transforms/IndVarSimplify/elim-extend.ll @@ -22,7 +22,7 @@ loop: store i8 0, i8* %postadr %postivnsw = add nsw i32 %ivnsw, 1 %postofsnsw = sext i32 %postivnsw to i64 - %postadrnsw = getelementptr i8, i8* %base, i64 %postofsnsw + %postadrnsw = getelementptr inbounds i8, i8* %base, i64 %postofsnsw store i8 0, i8* %postadrnsw %cond = icmp sgt i32 %limit, %iv br i1 %cond, label %loop, label %exit