[llvm] r326418 - [SCEV] Smart range calculation for SCEVUnknown Phis
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 28 22:56:48 PST 2018
Author: mkazantsev
Date: Wed Feb 28 22:56:48 2018
New Revision: 326418
URL: http://llvm.org/viewvc/llvm-project?rev=326418&view=rev
Log:
[SCEV] Smart range calculation for SCEVUnknown Phis
The range of SCEVUnknown Phi which merges values `X1, X2, ..., XN`
can be evaluated as `U(Range(X1), Range(X2), ..., Range(XN))`.
Reviewed By: sanjoy
Differential Revision: https://reviews.llvm.org/D43810
Added:
llvm/trunk/test/Analysis/ScalarEvolution/unknown_phis.ll
Modified:
llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
llvm/trunk/lib/Analysis/ScalarEvolution.cpp
llvm/trunk/test/Transforms/IRCE/single-access-no-preloop.ll
llvm/trunk/test/Transforms/LoopVectorize/X86/consecutive-ptr-cg-bug.ll
Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=326418&r1=326417&r2=326418&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)
+++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Wed Feb 28 22:56:48 2018
@@ -1099,6 +1099,9 @@ private:
/// Mark predicate values currently being processed by isImpliedCond.
SmallPtrSet<Value *, 6> PendingLoopPredicates;
+ /// Mark SCEVUnknown Phis currently being processed by getRangeRef.
+ SmallPtrSet<const PHINode *, 6> PendingPhiRanges;
+
/// Set to true by isLoopBackedgeGuardedByCond when we're walking the set of
/// conditions dominating the backedge of a loop.
bool WalkingBEDominatingConds = false;
Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=326418&r1=326417&r2=326418&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Feb 28 22:56:48 2018
@@ -5582,6 +5582,25 @@ ScalarEvolution::getRangeRef(const SCEV
APInt::getSignedMaxValue(BitWidth).ashr(NS - 1) + 1));
}
+ // A range of Phi is a subset of union of all ranges of its input.
+ if (const PHINode *Phi = dyn_cast<PHINode>(U->getValue())) {
+ // Make sure that we do not run over cycled Phis.
+ if (PendingPhiRanges.insert(Phi).second) {
+ ConstantRange RangeFromOps(BitWidth, /*isFullSet=*/false);
+ for (auto &Op : Phi->operands()) {
+ auto OpRange = getRangeRef(getSCEV(Op), SignHint);
+ RangeFromOps = RangeFromOps.unionWith(OpRange);
+ // No point to continue if we already have a full set.
+ if (RangeFromOps.isFullSet())
+ break;
+ }
+ ConservativeResult = ConservativeResult.intersectWith(RangeFromOps);
+ bool Erased = PendingPhiRanges.erase(Phi);
+ assert(Erased && "Failed to erase Phi properly?");
+ (void) Erased;
+ }
+ }
+
return setRange(U, SignHint, std::move(ConservativeResult));
}
@@ -10888,6 +10907,7 @@ ScalarEvolution::ScalarEvolution(ScalarE
LI(Arg.LI), CouldNotCompute(std::move(Arg.CouldNotCompute)),
ValueExprMap(std::move(Arg.ValueExprMap)),
PendingLoopPredicates(std::move(Arg.PendingLoopPredicates)),
+ PendingPhiRanges(std::move(Arg.PendingPhiRanges)),
MinTrailingZerosCache(std::move(Arg.MinTrailingZerosCache)),
BackedgeTakenCounts(std::move(Arg.BackedgeTakenCounts)),
PredicatedBackedgeTakenCounts(
@@ -10931,6 +10951,7 @@ ScalarEvolution::~ScalarEvolution() {
BTCI.second.clear();
assert(PendingLoopPredicates.empty() && "isImpliedCond garbage");
+ assert(PendingPhiRanges.empty() && "getRangeRef garbage");
assert(!WalkingBEDominatingConds && "isLoopBackedgeGuardedByCond garbage!");
assert(!ProvingSplitPredicate && "ProvingSplitPredicate garbage!");
}
Added: llvm/trunk/test/Analysis/ScalarEvolution/unknown_phis.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/unknown_phis.ll?rev=326418&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/unknown_phis.ll (added)
+++ llvm/trunk/test/Analysis/ScalarEvolution/unknown_phis.ll Wed Feb 28 22:56:48 2018
@@ -0,0 +1,54 @@
+; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s
+
+define void @merge_values_with_ranges(i32 *%a_len_ptr, i32 *%b_len_ptr, i1 %unknown_cond) {
+
+; CHECK-LABEL: Classifying expressions for: @merge_values_with_ranges
+; CHECK: %len = phi i32 [ %len_a, %if.true ], [ %len_b, %if.false ]
+; CHECK-NEXT: --> %len U: [0,2147483647) S: [0,2147483647)
+
+ entry:
+ br i1 %unknown_cond, label %if.true, label %if.false
+
+if.true:
+ %len_a = load i32, i32* %a_len_ptr, !range !0
+ br label %merge
+
+if.false:
+ %len_b = load i32, i32* %b_len_ptr, !range !0
+ br label %merge
+
+merge:
+ %len = phi i32 [ %len_a, %if.true ], [ %len_b, %if.false ]
+ ret void
+}
+
+define void @merge_values_with_ranges_looped(i32 *%a_len_ptr, i32 *%b_len_ptr) {
+
+; TODO: We could be much smarter here. So far we just make sure that we do not
+; go into infinite loop analyzing these Phis.
+
+; CHECK-LABEL: Classifying expressions for: @merge_values_with_ranges_looped
+; CHECK: %p1 = phi i32 [ %len_a, %entry ], [ %p2, %loop ]
+; CHECK-NEXT: --> %p1 U: full-set S: full-set
+; CHECK: %p2 = phi i32 [ %len_b, %entry ], [ %p1, %loop ]
+; CHECK-NEXT: --> %p2 U: full-set S: full-set
+
+ entry:
+ %len_a = load i32, i32* %a_len_ptr, !range !0
+ %len_b = load i32, i32* %b_len_ptr, !range !0
+ br label %loop
+
+loop:
+ %p1 = phi i32 [ %len_a, %entry ], [ %p2, %loop ]
+ %p2 = phi i32 [ %len_b, %entry ], [ %p1, %loop ]
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ %iv.next = add i32 %iv, 1
+ %loop.cond = icmp slt i32 %iv.next, 100
+ br i1 %loop.cond, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+
+!0 = !{i32 0, i32 2147483647}
Modified: llvm/trunk/test/Transforms/IRCE/single-access-no-preloop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IRCE/single-access-no-preloop.ll?rev=326418&r1=326417&r2=326418&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/IRCE/single-access-no-preloop.ll (original)
+++ llvm/trunk/test/Transforms/IRCE/single-access-no-preloop.ll Wed Feb 28 22:56:48 2018
@@ -179,5 +179,71 @@ in.bounds2:
; CHECK-NOT: br i1 false
; CHECK-NOT: preloop
+define void @single_access_no_preloop_no_offset_phi_len(i32 *%arr, i32 *%a_len_ptr, i32 *%b_len_ptr, i32 %n, i1 %unknown_cond) {
+ entry:
+ br i1 %unknown_cond, label %if.true, label %if.false
+
+if.true:
+ %len_a = load i32, i32* %a_len_ptr, !range !0
+ br label %merge
+
+if.false:
+ %len_b = load i32, i32* %b_len_ptr, !range !0
+ br label %merge
+
+merge:
+ %len = phi i32 [ %len_a, %if.true ], [ %len_b, %if.false ]
+ %first.itr.check = icmp sgt i32 %n, 0
+ br i1 %first.itr.check, label %loop, label %exit
+
+ loop:
+ %idx = phi i32 [ 0, %merge ] , [ %idx.next, %in.bounds ]
+ %idx.next = add i32 %idx, 1
+ %abc = icmp slt i32 %idx, %len
+ br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
+
+ in.bounds:
+ %addr = getelementptr i32, i32* %arr, i32 %idx
+ store i32 0, i32* %addr
+ %next = icmp slt i32 %idx.next, %n
+ br i1 %next, label %loop, label %exit
+
+ out.of.bounds:
+ ret void
+
+ exit:
+ ret void
+}
+
+; CHECK-LABEL: @single_access_no_preloop_no_offset_phi_len(
+
+; CHECK: loop:
+; CHECK: br i1 true, label %in.bounds, label %out.of.bounds
+
+; CHECK: main.exit.selector:
+; CHECK-NEXT: %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds ]
+; CHECK-NEXT: [[continue:%[^ ]+]] = icmp slt i32 %idx.next.lcssa, %n
+; CHECK-NEXT: br i1 [[continue]], label %main.pseudo.exit, label %exit.loopexit
+
+; CHECK: main.pseudo.exit:
+; CHECK-NEXT: %idx.copy = phi i32 [ 0, %loop.preheader ], [ %idx.next.lcssa, %main.exit.selector ]
+; CHECK-NEXT: %indvar.end = phi i32 [ 0, %loop.preheader ], [ %idx.next.lcssa, %main.exit.selector ]
+; CHECK-NEXT: br label %postloop
+
+; CHECK: postloop:
+; CHECK-NEXT: br label %loop.postloop
+
+; CHECK: loop.postloop:
+; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.next.postloop, %in.bounds.postloop ], [ %idx.copy, %postloop ]
+; CHECK-NEXT: %idx.next.postloop = add i32 %idx.postloop, 1
+; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %len
+; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds
+
+; CHECK: in.bounds.postloop:
+; CHECK-NEXT: %addr.postloop = getelementptr i32, i32* %arr, i32 %idx.postloop
+; CHECK-NEXT: store i32 0, i32* %addr.postloop
+; CHECK-NEXT: %next.postloop = icmp slt i32 %idx.next.postloop, %n
+; CHECK-NEXT: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit
+
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}
Modified: llvm/trunk/test/Transforms/LoopVectorize/X86/consecutive-ptr-cg-bug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopVectorize/X86/consecutive-ptr-cg-bug.ll?rev=326418&r1=326417&r2=326418&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopVectorize/X86/consecutive-ptr-cg-bug.ll (original)
+++ llvm/trunk/test/Transforms/LoopVectorize/X86/consecutive-ptr-cg-bug.ll Wed Feb 28 22:56:48 2018
@@ -29,11 +29,13 @@ target triple = "x86_64-unknown-linux-gn
; Verify that store is vectorized as stride-1 memory access.
-; CHECK: vector.body:
-; CHECK: store <4 x i32>
+; CHECK-LABEL: @test_01(
+; CHECK-NOT: vector.body:
+; This test was originally vectorized, but now SCEV is smart enough to prove
+; that its trip count is 1, so it gets ignored by vectorizer.
; Function Attrs: uwtable
-define void @test() {
+define void @test_01() {
br label %.outer
; <label>:1: ; preds = %2
@@ -66,3 +68,41 @@ define void @test() {
br i1 undef, label %2, label %._crit_edge.loopexit
}
+; After trip count is increased, the test gets vectorized.
+; CHECK-LABEL: @test_02(
+; CHECK: vector.body:
+; CHECK: store <4 x i32>
+
+; Function Attrs: uwtable
+define void @test_02() {
+ br label %.outer
+
+; <label>:1: ; preds = %2
+ ret void
+
+; <label>:2: ; preds = %._crit_edge.loopexit
+ %3 = add nsw i32 %.ph, -2
+ br i1 undef, label %1, label %.outer
+
+.outer: ; preds = %2, %0
+ %.ph = phi i32 [ %3, %2 ], [ 336, %0 ]
+ %.ph2 = phi i32 [ 62, %2 ], [ 110, %0 ]
+ %4 = and i32 %.ph, 30
+ %5 = add i32 %.ph2, 1
+ br label %6
+
+; <label>:6: ; preds = %6, %.outer
+ %7 = phi i32 [ %5, %.outer ], [ %13, %6 ]
+ %8 = phi i32 [ %.ph2, %.outer ], [ %7, %6 ]
+ %9 = add i32 %8, 2
+ %10 = zext i32 %9 to i64
+ %11 = getelementptr inbounds i32, i32 addrspace(1)* undef, i64 %10
+ %12 = ashr i32 undef, %4
+ store i32 %12, i32 addrspace(1)* %11, align 4
+ %13 = add i32 %7, 1
+ %14 = icmp sgt i32 %13, 610
+ br i1 %14, label %._crit_edge.loopexit, label %6
+
+._crit_edge.loopexit: ; preds = %._crit_edge.loopexit, %6
+ br i1 undef, label %2, label %._crit_edge.loopexit
+}
More information about the llvm-commits
mailing list