| ; 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 | |
| } | |
| define void @test-add-nuw-from-icmp(float* %input, i32 %offset, | |
| i32 %numIterations) { | |
| ; CHECK-LABEL: @test-add-nuw-from-icmp | |
| entry: | |
| br label %loop | |
| loop: | |
| %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] | |
| ; CHECK: %index32 = | |
| ; CHECK: --> {%offset,+,1}<nuw> | |
| %index32 = add nuw i32 %i, %offset | |
| %cmp = icmp sgt i32 %index32, 0 | |
| %cmp.idx = sext i1 %cmp to i32 | |
| %ptr = getelementptr inbounds float, float* %input, i32 %cmp.idx | |
| %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}<nsw> | |
| %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 | |
| } | |
| ; Similar to test-add-not-header, but in this case the load | |
| ; instruction may not be executed. | |
| define void @test-add-not-header3(float* %input, i32 %offset, i32 %numIterations, | |
| i1* %cond_buf) { | |
| ; CHECK-LABEL: @test-add-not-header3 | |
| 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 | |
| %cond = load volatile i1, i1* %cond_buf | |
| br i1 %cond, label %loop2, label %exit | |
| loop2: | |
| %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-header2, except we have a few extra | |
| ; blocks. | |
| define void @test-add-not-header4(float* %input, i32 %offset, i32 %numIterations) { | |
| ; CHECK-LABEL: @test-add-not-header4 | |
| entry: | |
| br label %loop | |
| loop: | |
| %i = phi i32 [ %nexti, %loop2 ], [ 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 | |
| br label %loop3 | |
| loop3: | |
| br label %loop4 | |
| loop4: | |
| 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 | |
| } | |
| ; Demonstrate why we need a Visited set in llvm::programUndefinedIfFullPoison. | |
| define void @test-add-not-header5(float* %input, i32 %offset) { | |
| ; CHECK-LABEL: @test-add-not-header5 | |
| 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 | |
| br 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 | |
| } | |
| ; Any poison input makes getelementptr produce poison | |
| define void @test-gep-propagates-poison(float* %input, i32 %offset, i32 %numIterations) { | |
| ; CHECK-LABEL: @test-gep-propagates-poison | |
| 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 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 | |
| } | |
| ; Any poison input to multiplication propages poison. | |
| define void @test-mul-propagates-poison(float* %input, i32 %offset, i32 %numIterations) { | |
| ; CHECK-LABEL: @test-mul-propagates-poison | |
| 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 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 | |
| } | |
| define void @test-mul-propagates-poison-2(float* %input, i32 %offset, i32 %numIterations) { | |
| ; CHECK-LABEL: @test-mul-propagates-poison-2 | |
| 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 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)<nsw>,+,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)<nsw>,+,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: --> {(-1 * (sext i32 %sub to i64))<nsw>,+,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 | |
| } | |
| ; Example checking that a sext is pushed onto a sub's operands if the sub is an | |
| ; overflow intrinsic. | |
| define void @test-sext-sub(float* %input, i32 %sub, i32 %numIterations) { | |
| ; CHECK-LABEL: @test-sext-sub | |
| entry: | |
| br label %loop | |
| loop: | |
| %i = phi i32 [ %nexti, %cont ], [ 0, %entry ] | |
| ; CHECK: %val = extractvalue { i32, i1 } %ssub, 0 | |
| ; CHECK: --> {(-1 * %sub),+,1}<nw> | |
| %ssub = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %i, i32 %sub) | |
| %val = extractvalue { i32, i1 } %ssub, 0 | |
| %ovfl = extractvalue { i32, i1 } %ssub, 1 | |
| br i1 %ovfl, label %trap, label %cont | |
| trap: | |
| tail call void @llvm.trap() | |
| unreachable | |
| cont: | |
| ; CHECK: %index64 = | |
| ; CHECK: --> {(-1 * (sext i32 %sub to i64))<nsw>,+,1}<nsw | |
| %index64 = sext i32 %val 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))<nsw>,+,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 | |
| } | |
| ; PR28932: Don't assert on non-SCEV-able value %2. | |
| %struct.anon = type { i8* } | |
| @a = common global %struct.anon* null, align 8 | |
| @b = common global i32 0, align 4 | |
| declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) | |
| declare void @llvm.trap() | |
| define i32 @pr28932() { | |
| entry: | |
| %.pre = load %struct.anon*, %struct.anon** @a, align 8 | |
| %.pre7 = load i32, i32* @b, align 4 | |
| br label %for.cond | |
| for.cond: ; preds = %cont6, %entry | |
| %0 = phi i32 [ %3, %cont6 ], [ %.pre7, %entry ] | |
| %1 = phi %struct.anon* [ %.ph, %cont6 ], [ %.pre, %entry ] | |
| %tobool = icmp eq %struct.anon* %1, null | |
| %2 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %0, i32 1) | |
| %3 = extractvalue { i32, i1 } %2, 0 | |
| %4 = extractvalue { i32, i1 } %2, 1 | |
| %idxprom = sext i32 %3 to i64 | |
| %5 = getelementptr inbounds %struct.anon, %struct.anon* %1, i64 0, i32 0 | |
| %6 = load i8*, i8** %5, align 8 | |
| %7 = getelementptr inbounds i8, i8* %6, i64 %idxprom | |
| %8 = load i8, i8* %7, align 1 | |
| br i1 %tobool, label %if.else, label %if.then | |
| if.then: ; preds = %for.cond | |
| br i1 %4, label %trap, label %cont6 | |
| trap: ; preds = %if.else, %if.then | |
| tail call void @llvm.trap() | |
| unreachable | |
| if.else: ; preds = %for.cond | |
| br i1 %4, label %trap, label %cont1 | |
| cont1: ; preds = %if.else | |
| %conv5 = sext i8 %8 to i64 | |
| %9 = inttoptr i64 %conv5 to %struct.anon* | |
| store %struct.anon* %9, %struct.anon** @a, align 8 | |
| br label %cont6 | |
| cont6: ; preds = %cont1, %if.then | |
| %.ph = phi %struct.anon* [ %9, %cont1 ], [ %1, %if.then ] | |
| store i32 %3, i32* @b, align 4 | |
| br label %for.cond | |
| } |