diff options
Diffstat (limited to 'test/Analysis/ScalarEvolution')
| -rw-r--r-- | test/Analysis/ScalarEvolution/avoid-assume-hang.ll | 139 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/constant_condition.ll | 51 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/flags-from-poison.ll | 592 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll | 10 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/min-max-exprs.ll | 2 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll | 122 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/non-IV-phi.ll | 59 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/pr24757.ll | 35 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/pr25369.ll | 78 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/scev-aa.ll | 2 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/shift-op.ll | 164 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll | 128 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/trip-count.ll | 5 | ||||
| -rw-r--r-- | test/Analysis/ScalarEvolution/zext-wrap.ll | 2 |
14 files changed, 1379 insertions, 10 deletions
diff --git a/test/Analysis/ScalarEvolution/avoid-assume-hang.ll b/test/Analysis/ScalarEvolution/avoid-assume-hang.ll new file mode 100644 index 0000000000000..e2428ed1f73f7 --- /dev/null +++ b/test/Analysis/ScalarEvolution/avoid-assume-hang.ll @@ -0,0 +1,139 @@ +; RUN: opt %s -always-inline | opt -analyze -scalar-evolution +; There was optimization bug in ScalarEvolution, that causes too long +; compute time and stack overflow crash. + +declare void @body(i32) +declare void @llvm.assume(i1) + +define available_externally void @assume1(i64 %i.ext, i64 %a) alwaysinline { + %cmp0 = icmp ne i64 %i.ext, %a + call void @llvm.assume(i1 %cmp0) + + %a1 = add i64 %a, 1 + %cmp1 = icmp ne i64 %i.ext, %a1 + call void @llvm.assume(i1 %cmp1) + + %a2 = add i64 %a1, 1 + %cmp2 = icmp ne i64 %i.ext, %a2 + call void @llvm.assume(i1 %cmp2) + + %a3 = add i64 %a2, 1 + %cmp3 = icmp ne i64 %i.ext, %a3 + call void @llvm.assume(i1 %cmp3) + + %a4 = add i64 %a3, 1 + %cmp4 = icmp ne i64 %i.ext, %a4 + call void @llvm.assume(i1 %cmp4) + + ret void +} + +define available_externally void @assume2(i64 %i.ext, i64 %a) alwaysinline { + call void @assume1(i64 %i.ext, i64 %a) + + %a1 = add i64 %a, 5 + %cmp1 = icmp ne i64 %i.ext, %a1 + call void @assume1(i64 %i.ext, i64 %a1) + + %a2 = add i64 %a1, 5 + %cmp2 = icmp ne i64 %i.ext, %a2 + call void @assume1(i64 %i.ext, i64 %a2) + + %a3 = add i64 %a2, 5 + %cmp3 = icmp ne i64 %i.ext, %a3 + call void @assume1(i64 %i.ext, i64 %a3) + + %a4 = add i64 %a3, 5 + %cmp4 = icmp ne i64 %i.ext, %a4 + call void @assume1(i64 %i.ext, i64 %a4) + + ret void +} + +define available_externally void @assume3(i64 %i.ext, i64 %a) alwaysinline { + call void @assume2(i64 %i.ext, i64 %a) + + %a1 = add i64 %a, 25 + %cmp1 = icmp ne i64 %i.ext, %a1 + call void @assume2(i64 %i.ext, i64 %a1) + + %a2 = add i64 %a1, 25 + %cmp2 = icmp ne i64 %i.ext, %a2 + call void @assume2(i64 %i.ext, i64 %a2) + + %a3 = add i64 %a2, 25 + %cmp3 = icmp ne i64 %i.ext, %a3 + call void @assume2(i64 %i.ext, i64 %a3) + + %a4 = add i64 %a3, 25 + %cmp4 = icmp ne i64 %i.ext, %a4 + call void @assume2(i64 %i.ext, i64 %a4) + + ret void +} + +define available_externally void @assume4(i64 %i.ext, i64 %a) alwaysinline { + call void @assume3(i64 %i.ext, i64 %a) + + %a1 = add i64 %a, 125 + %cmp1 = icmp ne i64 %i.ext, %a1 + call void @assume3(i64 %i.ext, i64 %a1) + + %a2 = add i64 %a1, 125 + %cmp2 = icmp ne i64 %i.ext, %a2 + call void @assume3(i64 %i.ext, i64 %a2) + + %a3 = add i64 %a2, 125 + %cmp3 = icmp ne i64 %i.ext, %a3 + call void @assume3(i64 %i.ext, i64 %a3) + + %a4 = add i64 %a3, 125 + %cmp4 = icmp ne i64 %i.ext, %a4 + call void @assume3(i64 %i.ext, i64 %a4) + + ret void +} + +define available_externally void @assume5(i64 %i.ext, i64 %a) alwaysinline { + call void @assume4(i64 %i.ext, i64 %a) + + %a1 = add i64 %a, 625 + %cmp1 = icmp ne i64 %i.ext, %a1 + call void @assume4(i64 %i.ext, i64 %a1) + + %a2 = add i64 %a1, 625 + %cmp2 = icmp ne i64 %i.ext, %a2 + call void @assume4(i64 %i.ext, i64 %a2) + + %a3 = add i64 %a2, 625 + %cmp3 = icmp ne i64 %i.ext, %a3 + call void @assume4(i64 %i.ext, i64 %a3) + + %a4 = add i64 %a3, 625 + %cmp4 = icmp ne i64 %i.ext, %a4 + call void @assume4(i64 %i.ext, i64 %a4) + + ret void +} + +define void @fn(i32 %init) { +entry: + br label %loop + +loop: + %i = phi i32 [%init, %entry], [%next, %loop] + call void @body(i32 %i) + + %i.ext = zext i32 %i to i64 + + call void @assume5(i64 %i.ext, i64 500000000) + + %i.next = add i64 %i.ext, 1 + %next = trunc i64 %i.next to i32 + %done = icmp eq i32 %i, 500000000 + + br i1 %done, label %exit, label %loop + +exit: + ret void +}
\ No newline at end of file diff --git a/test/Analysis/ScalarEvolution/constant_condition.ll b/test/Analysis/ScalarEvolution/constant_condition.ll new file mode 100644 index 0000000000000..32ab91b2c857b --- /dev/null +++ b/test/Analysis/ScalarEvolution/constant_condition.ll @@ -0,0 +1,51 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +define i32 @branch_true(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @branch_true + entry: + br i1 true, label %add, label %merge + + add: + %sum = add i32 %x, %y + br label %merge + + merge: + %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK-NEXT: --> (%x + %y) U: full-set S: full-set + ret i32 %v +} + +define i32 @branch_false(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @branch_false + entry: + br i1 false, label %add, label %merge + + add: + %sum = add i32 %x, %y + br label %merge + + merge: + %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK-NEXT: --> %x U: full-set S: full-set + ret i32 %v +} + +define i32 @select_true(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @select_true + entry: + %v = select i1 true, i32 %x, i32 %y +; CHECK: %v = select i1 true, i32 %x, i32 %y +; CHECK-NEXT: --> %x U: full-set S: full-set + ret i32 %v +} + +define i32 @select_false(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @select_false + entry: + %v = select i1 false, i32 %x, i32 %y +; CHECK: %v = select i1 false, i32 %x, i32 %y +; CHECK-NEXT: --> %y U: full-set S: full-set + ret i32 %v +} diff --git a/test/Analysis/ScalarEvolution/flags-from-poison.ll b/test/Analysis/ScalarEvolution/flags-from-poison.ll new file mode 100644 index 0000000000000..b1fe7f1138b6c --- /dev/null +++ b/test/Analysis/ScalarEvolution/flags-from-poison.ll @@ -0,0 +1,592 @@ +; RUN: opt < %s -S -analyze -scalar-evolution | FileCheck %s + +; Positive and negative tests for inferring flags like nsw from +; reasoning about how a poison value from overflow would trigger +; undefined behavior. + +define void @foo() { + ret void +} + +; Example where an add should get the nsw flag, so that a sext can be +; distributed over the add. +define void @test-add-nsw(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-nsw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nsw> + %index32 = add nsw i32 %i, %offset + +; CHECK: %index64 = +; CHECK: --> {(sext i32 %offset to i64),+,1}<nsw> + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + call void @foo() + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Example where an add should get the nuw flag. +define void @test-add-nuw(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-nuw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nuw> + %index32 = add nuw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nuw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +; With no load to trigger UB from poison, we cannot infer nsw. +define void @test-add-no-load(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-no-load +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nuw i32 %i, 1 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +; The current code is only supposed to look at the loop header, so +; it should not infer nsw in this case, as that would require looking +; outside the loop header. +define void @test-add-not-header(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-not-header +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ] + br label %loop2 +loop2: + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Same thing as test-add-not-header, but in this case only the load +; instruction is outside the loop header. +define void @test-add-not-header2(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-not-header2 +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + br label %loop2 +loop2: + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; The call instruction makes it not guaranteed that the add will be +; executed, since it could run forever or throw an exception, so we +; cannot assume that the UB is realized. +define void @test-add-call(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-call +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + call void @foo() + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Same issue as test-add-call, but this time the call is between the +; producer of poison and the load that consumes it. +define void @test-add-call2(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-call2 +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + call void @foo() + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Without inbounds, GEP does not propagate poison in the very +; conservative approach used here. +define void @test-add-no-inbounds(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-no-inbounds +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Multiplication by a non-zero constant propagates poison if there is +; a nuw or nsw flag on the multiplication. +define void @test-add-mul-propagates(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-mul-propagates +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nsw> + %index32 = add nsw i32 %i, %offset + + %indexmul = mul nuw i32 %index32, 2 + %ptr = getelementptr inbounds float, float* %input, i32 %indexmul + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Multiplication by a non-constant should not propagate poison in the +; very conservative approach used here. +define void @test-add-mul-no-propagation(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-mul-no-propagation +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %indexmul = mul nsw i32 %index32, %offset + %ptr = getelementptr inbounds float, float* %input, i32 %indexmul + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Multiplication by a non-zero constant does not propagate poison +; without a no-wrap flag. +define void @test-add-mul-no-propagation2(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-mul-no-propagation2 +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nw> + %index32 = add nsw i32 %i, %offset + + %indexmul = mul i32 %index32, 2 + %ptr = getelementptr inbounds float, float* %input, i32 %indexmul + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Division by poison triggers UB. +define void @test-add-div(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-div +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %j = +; CHECK: --> {%offset,+,1}<nsw> + %j = add nsw i32 %i, %offset + + %q = sdiv i32 %numIterations, %j + %nexti = add nsw i32 %i, 1 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Remainder of poison by non-poison divisor does not trigger UB. +define void @test-add-div2(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-div2 +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %j = +; CHECK: --> {%offset,+,1}<nw> + %j = add nsw i32 %i, %offset + + %q = sdiv i32 %j, %numIterations + %nexti = add nsw i32 %i, 1 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Store to poison address triggers UB. +define void @test-add-store(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-store +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {%offset,+,1}<nsw> + %index32 = add nsw i32 %i, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + store float 1.0, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Three sequential adds where the middle add should have nsw. There is +; a special case for sequential adds and this test covers that. We have to +; put the final add first in the program since otherwise the special case +; is not triggered, hence the strange basic block ordering. +define void @test-add-twice(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-add-twice +entry: + br label %loop +loop2: +; CHECK: %seq = +; CHECK: --> {(2 + %offset),+,1}<nw> + %seq = add nsw nuw i32 %index32, 1 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +loop: + %i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ] + + %j = add nsw i32 %i, 1 +; CHECK: %index32 = +; CHECK: --> {(1 + %offset),+,1}<nsw> + %index32 = add nsw i32 %j, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + store float 1.0, float* %ptr, align 4 + br label %loop2 +exit: + ret void +} + +; Example where a mul should get the nsw flag, so that a sext can be +; distributed over the mul. +define void @test-mul-nsw(float* %input, i32 %stride, i32 %numIterations) { +; CHECK-LABEL: @test-mul-nsw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {0,+,%stride}<nsw> + %index32 = mul nsw i32 %i, %stride + +; CHECK: %index64 = +; CHECK: --> {0,+,(sext i32 %stride to i64)}<nsw> + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Example where a mul should get the nuw flag. +define void @test-mul-nuw(float* %input, i32 %stride, i32 %numIterations) { +; CHECK-LABEL: @test-mul-nuw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {0,+,%stride}<nuw> + %index32 = mul nuw i32 %i, %stride + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nuw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +; Example where a shl should get the nsw flag, so that a sext can be +; distributed over the shl. +define void @test-shl-nsw(float* %input, i32 %start, i32 %numIterations) { +; CHECK-LABEL: @test-shl-nsw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ %start, %entry ] + +; CHECK: %index32 = +; CHECK: --> {(256 * %start),+,256}<nsw> + %index32 = shl nsw i32 %i, 8 + +; CHECK: %index64 = +; CHECK: --> {(sext i32 (256 * %start) to i64),+,256}<nsw> + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Example where a shl should get the nuw flag. +define void @test-shl-nuw(float* %input, i32 %numIterations) { +; CHECK-LABEL: @test-shl-nuw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {0,+,512}<nuw> + %index32 = shl nuw i32 %i, 9 + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nuw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +; Example where a sub should *not* get the nsw flag, because of how +; scalar evolution represents A - B as A + (-B) and -B can wrap even +; in cases where A - B does not. +define void @test-sub-no-nsw(float* %input, i32 %start, i32 %sub, i32 %numIterations) { +; CHECK-LABEL: @test-sub-no-nsw +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ %start, %entry ] + +; CHECK: %index32 = +; CHECK: --> {((-1 * %sub) + %start),+,1}<nw> + %index32 = sub nsw i32 %i, %sub + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Example where a sub should get the nsw flag as the RHS cannot be the +; minimal signed value. +define void @test-sub-nsw(float* %input, i32 %start, i32 %sub, i32 %numIterations) { +; CHECK-LABEL: @test-sub-nsw +entry: + %halfsub = ashr i32 %sub, 1 + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ %start, %entry ] + +; CHECK: %index32 = +; CHECK: --> {((-1 * %halfsub)<nsw> + %start),+,1}<nsw> + %index32 = sub nsw i32 %i, %halfsub + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Example where a sub should get the nsw flag, since the LHS is non-negative, +; which implies that the RHS cannot be the minimal signed value. +define void @test-sub-nsw-lhs-non-negative(float* %input, i32 %sub, i32 %numIterations) { +; CHECK-LABEL: @test-sub-nsw-lhs-non-negative +entry: + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + +; CHECK: %index32 = +; CHECK: --> {(-1 * %sub),+,1}<nsw> + %index32 = sub nsw i32 %i, %sub + +; CHECK: %index64 = +; CHECK: --> {(sext i32 (-1 * %sub) to i64),+,1}<nsw> + %index64 = sext i32 %index32 to i64 + + %ptr = getelementptr inbounds float, float* %input, i64 %index64 + %nexti = add nsw i32 %i, 1 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop +exit: + ret void +} + +; Two adds with a sub in the middle and the sub should have nsw. There is +; a special case for sequential adds/subs and this test covers that. We have to +; put the final add first in the program since otherwise the special case +; is not triggered, hence the strange basic block ordering. +define void @test-sub-with-add(float* %input, i32 %offset, i32 %numIterations) { +; CHECK-LABEL: @test-sub-with-add +entry: + br label %loop +loop2: +; CHECK: %seq = +; CHECK: --> {(2 + (-1 * %offset)),+,1}<nw> + %seq = add nsw nuw i32 %index32, 1 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +loop: + %i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ] + + %j = add nsw i32 %i, 1 +; CHECK: %index32 = +; CHECK: --> {(1 + (-1 * %offset)),+,1}<nsw> + %index32 = sub nsw i32 %j, %offset + + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %nexti = add nsw i32 %i, 1 + store float 1.0, float* %ptr, align 4 + br label %loop2 +exit: + ret void +} + + +; Subtraction of two recurrences. The addition in the SCEV that this +; maps to is NSW, but the negation of the RHS does not since that +; recurrence could be the most negative representable value. +define void @subrecurrences(i32 %outer_l, i32 %inner_l, i32 %val) { +; CHECK-LABEL: @subrecurrences + entry: + br label %outer + +outer: + %o_idx = phi i32 [ 0, %entry ], [ %o_idx.inc, %outer.be ] + %o_idx.inc = add nsw i32 %o_idx, 1 + %cond = icmp eq i32 %o_idx, %val + br i1 %cond, label %inner, label %outer.be + +inner: + %i_idx = phi i32 [ 0, %outer ], [ %i_idx.inc, %inner ] + %i_idx.inc = add nsw i32 %i_idx, 1 +; CHECK: %v = +; CHECK-NEXT: --> {{[{][{]}}-1,+,-1}<nw><%outer>,+,1}<nsw><%inner> + %v = sub nsw i32 %i_idx, %o_idx.inc + %forub = udiv i32 1, %v + %cond2 = icmp eq i32 %i_idx, %inner_l + br i1 %cond2, label %outer.be, label %inner + +outer.be: + %cond3 = icmp eq i32 %o_idx, %outer_l + br i1 %cond3, label %exit, label %outer + +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll b/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll index 078ca03ff14e1..5c372b5d7b8a1 100644 --- a/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll +++ b/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll @@ -11,7 +11,7 @@ define void @infer.sext.0(i1* %c, i32 %start) { %idx.inc = add nsw i32 %idx, 1 %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}<nsw><%loop> +; CHECK-NEXT: --> {(1 + (sext i32 %start to i64))<nsw>,+,1}<nsw><%loop> %condition = icmp eq i32 %counter, 1 %counter.inc = add i32 %counter, 1 br i1 %condition, label %exit, label %loop @@ -31,7 +31,7 @@ define void @infer.zext.0(i1* %c, i32 %start) { %idx.inc = add nuw i32 %idx, 1 %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}<nuw><%loop> +; CHECK-NEXT: --> {(1 + (zext i32 %start to i64))<nuw><nsw>,+,1}<nuw><%loop> %condition = icmp eq i32 %counter, 1 %counter.inc = add i32 %counter, 1 br i1 %condition, label %exit, label %loop @@ -51,7 +51,7 @@ define void @infer.sext.1(i32 %start, i1* %c) { %idx = phi i32 [ %start.real, %entry ], [ %idx.inc, %loop ] %idx.sext = sext i32 %idx to i64 ; CHECK: %idx.sext = sext i32 %idx to i64 -; CHECK-NEXT: --> {(2 + (sext i32 (4 * %start) to i64)),+,2}<nsw><%loop> +; CHECK-NEXT: --> {(2 + (sext i32 (4 * %start) to i64))<nsw>,+,2}<nsw><%loop> %idx.inc = add nsw i32 %idx, 2 %condition = load i1, i1* %c br i1 %condition, label %exit, label %loop @@ -71,7 +71,7 @@ define void @infer.sext.2(i1* %c, i8 %start) { %idx = phi i8 [ %start.inc, %entry ], [ %idx.inc, %loop ] %idx.sext = sext i8 %idx to i16 ; CHECK: %idx.sext = sext i8 %idx to i16 -; CHECK-NEXT: --> {(1 + (sext i8 %start to i16)),+,1}<nsw><%loop> +; CHECK-NEXT: --> {(1 + (sext i8 %start to i16))<nsw>,+,1}<nsw><%loop> %idx.inc = add nsw i8 %idx, 1 %condition = load volatile i1, i1* %c br i1 %condition, label %exit, label %loop @@ -91,7 +91,7 @@ define void @infer.zext.1(i1* %c, i8 %start) { %idx = phi i8 [ %start.inc, %entry ], [ %idx.inc, %loop ] %idx.zext = zext i8 %idx to i16 ; CHECK: %idx.zext = zext i8 %idx to i16 -; CHECK-NEXT: --> {(1 + (zext i8 %start to i16)),+,1}<nuw><%loop> +; CHECK-NEXT: --> {(1 + (zext i8 %start to i16))<nuw><nsw>,+,1}<nuw><%loop> %idx.inc = add nuw i8 %idx, 1 %condition = load volatile i1, i1* %c br i1 %condition, label %exit, label %loop diff --git a/test/Analysis/ScalarEvolution/min-max-exprs.ll b/test/Analysis/ScalarEvolution/min-max-exprs.ll index 892fc23fe6b2e..e8c1e33e095f8 100644 --- a/test/Analysis/ScalarEvolution/min-max-exprs.ll +++ b/test/Analysis/ScalarEvolution/min-max-exprs.ll @@ -33,7 +33,7 @@ bb2: ; preds = %bb1 %tmp9 = select i1 %tmp4, i64 %tmp5, i64 %tmp6 ; min(N, i+3) ; CHECK: select i1 %tmp4, i64 %tmp5, i64 %tmp6 -; CHECK-NEXT: --> (-1 + (-1 * ((-1 + (-1 * (sext i32 {3,+,1}<nw><%bb1> to i64))) smax (-1 + (-1 * (sext i32 %N to i64)))))) +; CHECK-NEXT: --> (-1 + (-1 * ((-1 + (-1 * (sext i32 {3,+,1}<nuw><%bb1> to i64))<nsw>)<nsw> smax (-1 + (-1 * (sext i32 %N to i64))<nsw>)<nsw>))<nsw>)<nsw> %tmp11 = getelementptr inbounds i32, i32* %A, i64 %tmp9 %tmp12 = load i32, i32* %tmp11, align 4 %tmp13 = shl nsw i32 %tmp12, 1 diff --git a/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll b/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll new file mode 100644 index 0000000000000..c24d7173e4ee5 --- /dev/null +++ b/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll @@ -0,0 +1,122 @@ +; RUN: opt -S -analyze -scalar-evolution < %s | FileCheck %s + +!0 = !{i8 0, i8 127} + +define void @f0(i8* %len_addr) { +; CHECK-LABEL: Classifying expressions for: @f0 + entry: + %len = load i8, i8* %len_addr, !range !0 + %len_norange = load i8, i8* %len_addr +; CHECK: %len = load i8, i8* %len_addr, !range !0 +; CHECK-NEXT: --> %len U: [0,127) S: [0,127) +; CHECK: %len_norange = load i8, i8* %len_addr +; CHECK-NEXT: --> %len_norange U: full-set S: full-set + + %t0 = add i8 %len, 1 + %t1 = add i8 %len, 2 +; CHECK: %t0 = add i8 %len, 1 +; CHECK-NEXT: --> (1 + %len)<nuw><nsw> U: [1,-128) S: [1,-128) +; CHECK: %t1 = add i8 %len, 2 +; CHECK-NEXT: --> (2 + %len)<nuw> U: [2,-127) S: [2,-127) + + %t2 = sub i8 %len, 1 + %t3 = sub i8 %len, 2 +; CHECK: %t2 = sub i8 %len, 1 +; CHECK-NEXT: --> (-1 + %len)<nsw> U: [-1,126) S: [-1,126) +; CHECK: %t3 = sub i8 %len, 2 +; CHECK-NEXT: --> (-2 + %len)<nsw> U: [-2,125) S: [-2,125) + + %q0 = add i8 %len_norange, 1 + %q1 = add i8 %len_norange, 2 +; CHECK: %q0 = add i8 %len_norange, 1 +; CHECK-NEXT: --> (1 + %len_norange) U: full-set S: full-set +; CHECK: %q1 = add i8 %len_norange, 2 +; CHECK-NEXT: --> (2 + %len_norange) U: full-set S: full-set + + %q2 = sub i8 %len_norange, 1 + %q3 = sub i8 %len_norange, 2 +; CHECK: %q2 = sub i8 %len_norange, 1 +; CHECK-NEXT: --> (-1 + %len_norange) U: full-set S: full-set +; CHECK: %q3 = sub i8 %len_norange, 2 +; CHECK-NEXT: --> (-2 + %len_norange) U: full-set S: full-set + + ret void +} + +define void @f1(i8* %len_addr) { +; CHECK-LABEL: Classifying expressions for: @f1 + entry: + %len = load i8, i8* %len_addr, !range !0 + %len_norange = load i8, i8* %len_addr +; CHECK: %len = load i8, i8* %len_addr, !range !0 +; CHECK-NEXT: --> %len U: [0,127) S: [0,127) +; CHECK: %len_norange = load i8, i8* %len_addr +; CHECK-NEXT: --> %len_norange U: full-set S: full-set + + %t0 = add i8 %len, -1 + %t1 = add i8 %len, -2 +; CHECK: %t0 = add i8 %len, -1 +; CHECK-NEXT: --> (-1 + %len)<nsw> U: [-1,126) S: [-1,126) +; CHECK: %t1 = add i8 %len, -2 +; CHECK-NEXT: --> (-2 + %len)<nsw> U: [-2,125) S: [-2,125) + + %t0.sext = sext i8 %t0 to i16 + %t1.sext = sext i8 %t1 to i16 +; CHECK: %t0.sext = sext i8 %t0 to i16 +; CHECK-NEXT: --> (-1 + (zext i8 %len to i16))<nsw> U: [-1,126) S: [-1,126) +; CHECK: %t1.sext = sext i8 %t1 to i16 +; CHECK-NEXT: --> (-2 + (zext i8 %len to i16))<nsw> U: [-2,125) S: [-2,125) + + %q0 = add i8 %len_norange, 1 + %q1 = add i8 %len_norange, 2 +; CHECK: %q0 = add i8 %len_norange, 1 +; CHECK-NEXT: --> (1 + %len_norange) U: full-set S: full-set +; CHECK: %q1 = add i8 %len_norange, 2 +; CHECK-NEXT: --> (2 + %len_norange) U: full-set S: full-set + + %q0.sext = sext i8 %q0 to i16 + %q1.sext = sext i8 %q1 to i16 +; CHECK: %q0.sext = sext i8 %q0 to i16 +; CHECK-NEXT: --> (sext i8 (1 + %len_norange) to i16) U: [-128,128) S: [-128,128) +; CHECK: %q1.sext = sext i8 %q1 to i16 +; CHECK-NEXT: --> (sext i8 (2 + %len_norange) to i16) U: [-128,128) S: [-128,128) + + ret void +} + +define void @f2(i8* %len_addr) { +; CHECK-LABEL: Classifying expressions for: @f2 + entry: + %len = load i8, i8* %len_addr, !range !0 + %len_norange = load i8, i8* %len_addr +; CHECK: %len = load i8, i8* %len_addr, !range !0 +; CHECK-NEXT: --> %len U: [0,127) S: [0,127) +; CHECK: %len_norange = load i8, i8* %len_addr +; CHECK-NEXT: --> %len_norange U: full-set S: full-set + + %t0 = add i8 %len, 1 + %t1 = add i8 %len, 2 +; CHECK: %t0 = add i8 %len, 1 +; CHECK-NEXT: --> (1 + %len)<nuw><nsw> +; CHECK: %t1 = add i8 %len, 2 +; CHECK-NEXT: --> (2 + %len)<nuw> + + %t0.zext = zext i8 %t0 to i16 + %t1.zext = zext i8 %t1 to i16 +; CHECK: %t0.zext = zext i8 %t0 to i16 +; CHECK-NEXT: --> (1 + (zext i8 %len to i16))<nuw><nsw> U: [1,128) S: [1,128) +; CHECK: %t1.zext = zext i8 %t1 to i16 +; CHECK-NEXT: --> (2 + (zext i8 %len to i16))<nuw><nsw> U: [2,129) S: [2,129) + + %q0 = add i8 %len_norange, 1 + %q1 = add i8 %len_norange, 2 + %q0.zext = zext i8 %q0 to i16 + %q1.zext = zext i8 %q1 to i16 + +; CHECK: %q0.zext = zext i8 %q0 to i16 +; CHECK-NEXT: --> (zext i8 (1 + %len_norange) to i16) U: [0,256) S: [0,256) +; CHECK: %q1.zext = zext i8 %q1 to i16 +; CHECK-NEXT: --> (zext i8 (2 + %len_norange) to i16) U: [0,256) S: [0,256) + + ret void +} diff --git a/test/Analysis/ScalarEvolution/non-IV-phi.ll b/test/Analysis/ScalarEvolution/non-IV-phi.ll new file mode 100644 index 0000000000000..f0d6c2f5d9d33 --- /dev/null +++ b/test/Analysis/ScalarEvolution/non-IV-phi.ll @@ -0,0 +1,59 @@ +; RUN: opt -scalar-evolution -analyze < %s | FileCheck %s + +define void @test1(i8 %t, i32 %len) { +; CHECK-LABEL: test1 +; CHECK: %sphi = phi i32 [ %ext, %entry ], [ %idx.inc.ext, %loop ] +; CHECK-NEXT: --> (zext i8 {%t,+,1}<%loop> to i32) + + entry: + %st = zext i8 %t to i16 + %ext = zext i8 %t to i32 + %ecmp = icmp ult i16 %st, 42 + br i1 %ecmp, label %loop, label %exit + + loop: + + %idx = phi i8 [ %t, %entry ], [ %idx.inc, %loop ] + %sphi = phi i32 [ %ext, %entry ], [%idx.inc.ext, %loop] + + %idx.inc = add i8 %idx, 1 + %idx.inc.ext = zext i8 %idx.inc to i32 + %idx.ext = zext i8 %idx to i32 + + %c = icmp ult i32 %idx.inc.ext, %len + br i1 %c, label %loop, label %exit + + exit: + ret void +} + +define void @test2(i8 %t, i32 %len) { +; CHECK-LABEL: test2 +; CHECK: %sphi = phi i32 [ %ext.mul, %entry ], [ %mul, %loop ] +; CHECK-NEXT: --> (4 * (zext i8 {%t,+,1}<%loop> to i32)) + + entry: + %st = zext i8 %t to i16 + %ext = zext i8 %t to i32 + %ext.mul = mul i32 %ext, 4 + + %ecmp = icmp ult i16 %st, 42 + br i1 %ecmp, label %loop, label %exit + + loop: + + %idx = phi i8 [ %t, %entry ], [ %idx.inc, %loop ] + %sphi = phi i32 [ %ext.mul, %entry ], [%mul, %loop] + + %idx.inc = add i8 %idx, 1 + %idx.inc.ext = zext i8 %idx.inc to i32 + %mul = mul i32 %idx.inc.ext, 4 + + %idx.ext = zext i8 %idx to i32 + + %c = icmp ult i32 %idx.inc.ext, %len + br i1 %c, label %loop, label %exit + + exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/pr24757.ll b/test/Analysis/ScalarEvolution/pr24757.ll new file mode 100644 index 0000000000000..815adcde0e9df --- /dev/null +++ b/test/Analysis/ScalarEvolution/pr24757.ll @@ -0,0 +1,35 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +; CHECK: Loop %bb1: backedge-taken count is (zext i7 (trunc i8 %a.promoted to i7) to i8) + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.10.0" + +@a = global i8 -127, align 1 +@b = common global i32 0, align 4 + +declare void @use(i32) + +define i32 @main() { +bb: + %a.promoted = load i8, i8* @a + br label %bb1 + +bb1: ; preds = %bb1, %bb + %tmp = phi i8 [ %tmp2, %bb1 ], [ %a.promoted, %bb ] + %tmp2 = add i8 %tmp, -1 + %tmp3 = sext i8 %tmp to i32 + %tmp4 = xor i32 %tmp3, -1 + %tmp5 = sext i8 %tmp2 to i32 + %tmpf = sub nsw i32 %tmp4, %tmp5 + %tmp6 = trunc i32 %tmpf to i8 + %tmp7 = icmp eq i8 %tmp6, 0 + br i1 %tmp7, label %bb8, label %bb1 + +bb8: ; preds = %bb1 + store i8 %tmp2, i8* @a + store i32 %tmp4, i32* @b + %tmp9 = sext i8 %tmp2 to i32 + call void @use(i32 %tmp9) + ret i32 0 +} diff --git a/test/Analysis/ScalarEvolution/pr25369.ll b/test/Analysis/ScalarEvolution/pr25369.ll new file mode 100644 index 0000000000000..10754867a3683 --- /dev/null +++ b/test/Analysis/ScalarEvolution/pr25369.ll @@ -0,0 +1,78 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @hoge1() { +; CHECK-LABEL: Classifying expressions for: @hoge1 +bb: + br i1 undef, label %bb4, label %bb2 + +bb2: ; preds = %bb2, %bb + br i1 false, label %bb4, label %bb2 + +bb3: ; preds = %bb4 + %tmp = add i32 %tmp10, -1 + br label %bb13 + +bb4: ; preds = %bb4, %bb2, %bb + %tmp5 = phi i64 [ %tmp11, %bb4 ], [ 1, %bb2 ], [ 1, %bb ] + %tmp6 = phi i32 [ %tmp10, %bb4 ], [ 0, %bb2 ], [ 0, %bb ] + %tmp7 = load i32, i32* undef, align 4 + %tmp8 = add i32 %tmp7, %tmp6 + %tmp9 = add i32 undef, %tmp8 + %tmp10 = add i32 undef, %tmp9 + %tmp11 = add nsw i64 %tmp5, 3 + %tmp12 = icmp eq i64 %tmp11, 64 + br i1 %tmp12, label %bb3, label %bb4 + +; CHECK: Loop %bb4: backedge-taken count is 20 +; CHECK: Loop %bb4: max backedge-taken count is 20 + +bb13: ; preds = %bb13, %bb3 + %tmp14 = phi i64 [ 0, %bb3 ], [ %tmp15, %bb13 ] + %tmp15 = add nuw nsw i64 %tmp14, 1 + %tmp16 = trunc i64 %tmp15 to i32 + %tmp17 = icmp eq i32 %tmp16, %tmp + br i1 %tmp17, label %bb18, label %bb13 + +bb18: ; preds = %bb13 + ret void +} + +define void @hoge2() { +; CHECK-LABEL: Classifying expressions for: @hoge2 +bb: + br i1 undef, label %bb4, label %bb2 + +bb2: ; preds = %bb2, %bb + br i1 false, label %bb4, label %bb2 + +bb3: ; preds = %bb4 + %tmp = add i32 %tmp10, -1 + br label %bb13 + +bb4: ; preds = %bb4, %bb2, %bb + %tmp5 = phi i64 [ %tmp11, %bb4 ], [ 1, %bb2 ], [ 3, %bb ] + %tmp6 = phi i32 [ %tmp10, %bb4 ], [ 0, %bb2 ], [ 0, %bb ] + %tmp7 = load i32, i32* undef, align 4 + %tmp8 = add i32 %tmp7, %tmp6 + %tmp9 = add i32 undef, %tmp8 + %tmp10 = add i32 undef, %tmp9 + %tmp11 = add nsw i64 %tmp5, 3 + %tmp12 = icmp eq i64 %tmp11, 64 + br i1 %tmp12, label %bb3, label %bb4 + +; CHECK: Loop %bb4: Unpredictable backedge-taken count. +; CHECK: Loop %bb4: Unpredictable max backedge-taken count. + +bb13: ; preds = %bb13, %bb3 + %tmp14 = phi i64 [ 0, %bb3 ], [ %tmp15, %bb13 ] + %tmp15 = add nuw nsw i64 %tmp14, 1 + %tmp16 = trunc i64 %tmp15 to i32 + %tmp17 = icmp eq i32 %tmp16, %tmp + br i1 %tmp17, label %bb18, label %bb13 + +bb18: ; preds = %bb13 + ret void +} diff --git a/test/Analysis/ScalarEvolution/scev-aa.ll b/test/Analysis/ScalarEvolution/scev-aa.ll index e2123f44f1676..47a84d57c3b3c 100644 --- a/test/Analysis/ScalarEvolution/scev-aa.ll +++ b/test/Analysis/ScalarEvolution/scev-aa.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -scev-aa -aa-eval -print-all-alias-modref-info \ +; RUN: opt -disable-output < %s -disable-basicaa -scev-aa -aa-eval -print-all-alias-modref-info \ ; RUN: 2>&1 | FileCheck %s ; At the time of this writing, -basicaa misses the example of the form diff --git a/test/Analysis/ScalarEvolution/shift-op.ll b/test/Analysis/ScalarEvolution/shift-op.ll new file mode 100644 index 0000000000000..fe832d5676876 --- /dev/null +++ b/test/Analysis/ScalarEvolution/shift-op.ll @@ -0,0 +1,164 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +define void @test0(i32 %init) { +; CHECK-LABEL: Classifying expressions for: @test0 +; CHECK: Loop %loop: max backedge-taken count is 32 + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = lshr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test1(i32 %init) { +; CHECK-LABEL: Classifying expressions for: @test1 +; CHECK: Loop %loop: max backedge-taken count is 32 + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = shl i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test2(i32 %init) { +; CHECK-LABEL: Determining loop execution counts for: @test2 +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +; Unpredictable because %iv could "stabilize" to either -1 or 0, +; depending on %init. + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = ashr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test3(i32* %init.ptr) { +; CHECK-LABEL: Determining loop execution counts for: @test3 +; CHECK: Loop %loop: max backedge-taken count is 32 + entry: + %init = load i32, i32* %init.ptr, !range !0 + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = ashr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test4(i32* %init.ptr) { +; CHECK-LABEL: Classifying expressions for: @test4 +; CHECK-LABEL: Loop %loop: max backedge-taken count is 32 + entry: + %init = load i32, i32* %init.ptr, !range !1 + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = ashr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, -1 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test5(i32* %init.ptr) { +; CHECK-LABEL: Determining loop execution counts for: @test5 +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +; %iv will "stabilize" to -1, so this is an infinite loop + entry: + %init = load i32, i32* %init.ptr, !range !1 + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = ashr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test6(i32 %init, i32 %shift.amt) { +; CHECK-LABEL: Determining loop execution counts for: @test6 +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +; Potentially infinite loop, since %shift.amt could be 0 + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = lshr i32 %iv, %shift.amt + %exit.cond = icmp eq i32 %iv, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test7(i32 %init) { +; CHECK-LABEL: Classifying expressions for: @test7 +; CHECK: Loop %loop: max backedge-taken count is 32 + + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = lshr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv.shift, 0 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +define void @test8(i32 %init) { +; CHECK-LABEL: Classifying expressions for: @test8 +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +; In this test case, %iv.test stabilizes to 127, not -1, so the loop +; is infinite. + + entry: + br label %loop + + loop: + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ] + %iv.shift = ashr i32 %iv, 1 + %iv.test = lshr i32 %iv, 1 + %exit.cond = icmp eq i32 %iv.test, -1 + br i1 %exit.cond, label %leave, label %loop + + leave: + ret void +} + +!0 = !{i32 0, i32 50000} +!1 = !{i32 -5000, i32 -1} diff --git a/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll b/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll new file mode 100644 index 0000000000000..500f3e16c8f5f --- /dev/null +++ b/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll @@ -0,0 +1,128 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +define i32 @f0(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @f0 + entry: + %c = icmp sgt i32 %y, 0 + br i1 %c, label %add, label %merge + + add: + %sum = add i32 %x, %y + br label %merge + + merge: + %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK-NEXT: --> ((0 smax %y) + %x) U: full-set S: full-set + ret i32 %v +} + +define i32 @f1(i32 %x, i32 %y) { +; CHECK-LABEL: Classifying expressions for: @f1 + entry: + %c = icmp sge i32 %y, 0 + br i1 %c, label %add, label %merge + + add: + %sum = add i32 %x, %y + br label %merge + + merge: + %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %sum, %add ], [ %x, %entry ] +; CHECK-NEXT: --> ((0 smax %y) + %x) U: full-set S: full-set + ret i32 %v +} + +define i32 @f2(i32 %x, i32 %y, i32* %ptr) { +; CHECK-LABEL: Classifying expressions for: @f2 + entry: + %c = icmp sge i32 %y, 0 + br i1 %c, label %add, label %merge + + add: + %lv = load i32, i32* %ptr + br label %merge + + merge: + %v = phi i32 [ %lv, %add ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %lv, %add ], [ %x, %entry ] +; CHECK-NEXT: --> %v U: full-set S: full-set + ret i32 %v +} + +define i32 @f3(i32 %x, i32 %init, i32 %lim) { +; CHECK-LABEL: Classifying expressions for: @f3 + entry: + br label %loop + +loop: + %iv = phi i32 [ %init, %entry ], [ %iv.inc, %merge ] + %iv.inc = add i32 %iv, 1 + %c = icmp sge i32 %iv, 0 + br i1 %c, label %add, label %merge + + add: + %sum = add i32 %x, %iv + br label %merge + + merge: + %v = phi i32 [ %sum, %add ], [ %x, %loop ] +; CHECK: %v = phi i32 [ %sum, %add ], [ %x, %loop ] +; CHECK-NEXT: --> ((0 smax {%init,+,1}<%loop>) + %x) U: full-set S: full-set + %be.cond = icmp eq i32 %iv.inc, %lim + br i1 %be.cond, label %loop, label %leave + + leave: + ret i32 0 +} + +define i32 @f4(i32 %x, i32 %init, i32 %lim) { +; CHECK-LABEL: Classifying expressions for: @f4 + entry: + %c = icmp sge i32 %init, 0 + br i1 %c, label %add, label %merge + + add: + br label %loop + + loop: + %iv = phi i32 [ %init, %add ], [ %iv.inc, %loop ] + %iv.inc = add i32 %iv, 1 + %be.cond = icmp eq i32 %iv.inc, %lim + br i1 %be.cond, label %loop, label %add.cont + + add.cont: + %sum = add i32 %x, %iv + br label %merge + + merge: + %v = phi i32 [ %sum, %add.cont ], [ %x, %entry ] +; CHECK: %v = phi i32 [ %sum, %add.cont ], [ %x, %entry ] +; CHECK-NEXT: --> %v U: full-set S: full-set + ret i32 %v +} + +define i32 @f5(i32* %val) { +; CHECK-LABEL: Classifying expressions for: @f5 +entry: + br label %for.end + +for.condt: + br i1 true, label %for.cond.0, label %for.end + +for.end: + %inc = load i32, i32* %val + br i1 false, label %for.condt, label %for.cond.0 + +for.cond.0: + %init = phi i32 [ 0, %for.condt ], [ %inc, %for.end ] + +; CHECK: %init = phi i32 [ 0, %for.condt ], [ %inc, %for.end ] +; CHECK-NEXT: --> %init U: full-set S: full-set + +; Matching "through" %init will break LCSSA at the SCEV expression +; level. + + ret i32 %init +} diff --git a/test/Analysis/ScalarEvolution/trip-count.ll b/test/Analysis/ScalarEvolution/trip-count.ll index 1b75c88c753c2..89750810d1b72 100644 --- a/test/Analysis/ScalarEvolution/trip-count.ll +++ b/test/Analysis/ScalarEvolution/trip-count.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -analyze -scalar-evolution -scalar-evolution-max-iterations=0 | FileCheck %s +; RUN: opt < %s -passes='print<scalar-evolution>' -disable-output 2>&1 | FileCheck %s ; PR1101 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -6,7 +7,7 @@ target triple = "x86_64-unknown-linux-gnu" @A = weak global [1000 x i32] zeroinitializer, align 32 -; CHECK: Printing analysis 'Scalar Evolution Analysis' for function 'test1': +; CHECK-LABEL: Determining loop execution counts for: @test1 ; CHECK: backedge-taken count is 10000 define void @test1(i32 %N) { @@ -32,7 +33,7 @@ return: ; preds = %bb5 } ; PR22795 -; CHECK: Printing analysis 'Scalar Evolution Analysis' for function 'test2': +; CHECK-LABEL: Classifying expressions for: @test2 ; CHECK: %iv = phi i32 [ -1, %entry ], [ %next.1, %for.inc.1 ] ; CHECK-NEXT: --> {-1,+,2}<%preheader> U: full-set S: full-set Exits: 13 diff --git a/test/Analysis/ScalarEvolution/zext-wrap.ll b/test/Analysis/ScalarEvolution/zext-wrap.ll index f56e4556c697a..5bc149e2309a2 100644 --- a/test/Analysis/ScalarEvolution/zext-wrap.ll +++ b/test/Analysis/ScalarEvolution/zext-wrap.ll @@ -10,7 +10,7 @@ bb.i: ; preds = %bb1.i, %bb.nph ; This cast shouldn't be folded into the addrec. ; CHECK: %tmp = zext i8 %l_95.0.i1 to i16 -; CHECK: --> (zext i8 {0,+,-1}<%bb.i> to i16){{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: 2 +; CHECK: --> (zext i8 {0,+,-1}<nw><%bb.i> to i16){{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: 2 %tmp = zext i8 %l_95.0.i1 to i16 |
