diff options
Diffstat (limited to 'test/Analysis')
216 files changed, 10534 insertions, 0 deletions
diff --git a/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll b/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll new file mode 100644 index 00000000000..45f6088eaf0 --- /dev/null +++ b/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll @@ -0,0 +1,20 @@ +; This testcase makes sure that size is taken to account when alias analysis +; is performed. It is not legal to delete the second load instruction because +; the value computed by the first load instruction is changed by the store. + +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +define i32 @test() { +; CHECK: %Y.DONOTREMOVE = load i32* %A +; CHECK: %Z = sub i32 0, %Y.DONOTREMOVE + %A = alloca i32 + store i32 0, i32* %A + %X = load i32* %A + %B = bitcast i32* %A to i8* + %C = getelementptr i8* %B, i64 1 + store i8 1, i8* %C ; Aliases %A + %Y.DONOTREMOVE = load i32* %A + %Z = sub i32 %X, %Y.DONOTREMOVE + ret i32 %Z +} + diff --git a/test/Analysis/BasicAA/2003-03-04-GEPCrash.ll b/test/Analysis/BasicAA/2003-03-04-GEPCrash.ll new file mode 100644 index 00000000000..4f8eabb7930 --- /dev/null +++ b/test/Analysis/BasicAA/2003-03-04-GEPCrash.ll @@ -0,0 +1,7 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>/dev/null +; Test for a bug in BasicAA which caused a crash when querying equality of P1&P2 +define void @test({[2 x i32],[2 x i32]}* %A, i64 %X, i64 %Y) { + %P1 = getelementptr {[2 x i32],[2 x i32]}* %A, i64 0, i32 0, i64 %X + %P2 = getelementptr {[2 x i32],[2 x i32]}* %A, i64 0, i32 1, i64 %Y + ret void +} diff --git a/test/Analysis/BasicAA/2003-04-22-GEPProblem.ll b/test/Analysis/BasicAA/2003-04-22-GEPProblem.ll new file mode 100644 index 00000000000..78f74a0abe5 --- /dev/null +++ b/test/Analysis/BasicAA/2003-04-22-GEPProblem.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +; BasicAA was incorrectly concluding that P1 and P2 didn't conflict! + +define i32 @test(i32 *%Ptr, i64 %V) { +; CHECK: sub i32 %X, %Y + %P2 = getelementptr i32* %Ptr, i64 1 + %P1 = getelementptr i32* %Ptr, i64 %V + %X = load i32* %P1 + store i32 5, i32* %P2 + %Y = load i32* %P1 + %Z = sub i32 %X, %Y + ret i32 %Z +} diff --git a/test/Analysis/BasicAA/2003-04-25-GEPCrash.ll b/test/Analysis/BasicAA/2003-04-25-GEPCrash.ll new file mode 100644 index 00000000000..97bc38eb69b --- /dev/null +++ b/test/Analysis/BasicAA/2003-04-25-GEPCrash.ll @@ -0,0 +1,7 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>/dev/null +; Test for a bug in BasicAA which caused a crash when querying equality of P1&P2 +define void @test([17 x i16]* %mask_bits) { + %P1 = getelementptr [17 x i16]* %mask_bits, i64 0, i64 0 + %P2 = getelementptr [17 x i16]* %mask_bits, i64 252645134, i64 0 + ret void +} diff --git a/test/Analysis/BasicAA/2003-05-21-GEP-Problem.ll b/test/Analysis/BasicAA/2003-05-21-GEP-Problem.ll new file mode 100644 index 00000000000..8ca34698559 --- /dev/null +++ b/test/Analysis/BasicAA/2003-05-21-GEP-Problem.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -basicaa -licm -disable-output + %struct..apr_array_header_t = type { i32*, i32, i32, i32, i8* } + %struct..apr_table_t = type { %struct..apr_array_header_t, i32, [32 x i32], [32 x i32] } + +define void @table_reindex(%struct..apr_table_t* %t.1) { ; No predecessors! + br label %loopentry + +loopentry: ; preds = %0, %no_exit + %tmp.101 = getelementptr %struct..apr_table_t* %t.1, i64 0, i32 0, i32 2 + %tmp.11 = load i32* %tmp.101 ; <i32> [#uses=0] + br i1 false, label %no_exit, label %UnifiedExitNode + +no_exit: ; preds = %loopentry + %tmp.25 = sext i32 0 to i64 ; <i64> [#uses=1] + %tmp.261 = getelementptr %struct..apr_table_t* %t.1, i64 0, i32 3, i64 %tmp.25 ; <i32*> [#uses=1] + store i32 0, i32* %tmp.261 + br label %loopentry + +UnifiedExitNode: ; preds = %loopentry + ret void +} diff --git a/test/Analysis/BasicAA/2003-06-01-AliasCrash.ll b/test/Analysis/BasicAA/2003-06-01-AliasCrash.ll new file mode 100644 index 00000000000..0abd3847836 --- /dev/null +++ b/test/Analysis/BasicAA/2003-06-01-AliasCrash.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>/dev/null + +define i32 @MTConcat([3 x i32]* %a.1) { + %tmp.961 = getelementptr [3 x i32]* %a.1, i64 0, i64 4 + %tmp.97 = load i32* %tmp.961 + %tmp.119 = getelementptr [3 x i32]* %a.1, i64 1, i64 0 + %tmp.120 = load i32* %tmp.119 + %tmp.1541 = getelementptr [3 x i32]* %a.1, i64 0, i64 4 + %tmp.155 = load i32* %tmp.1541 + ret i32 0 +} diff --git a/test/Analysis/BasicAA/2003-07-03-BasicAACrash.ll b/test/Analysis/BasicAA/2003-07-03-BasicAACrash.ll new file mode 100644 index 00000000000..3e813fa2ca1 --- /dev/null +++ b/test/Analysis/BasicAA/2003-07-03-BasicAACrash.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>/dev/null + +%struct..RefPoint = type { i32, { i32, i8, i8 } } +%struct..RefRect = type { %struct..RefPoint, %struct..RefPoint } + +define i32 @BMT_CommitPartDrawObj() { + %tmp.19111 = getelementptr %struct..RefRect* null, i64 0, i32 0, i32 1, i32 2 + %tmp.20311 = getelementptr %struct..RefRect* null, i64 0, i32 1, i32 1, i32 2 + ret i32 0 +} diff --git a/test/Analysis/BasicAA/2003-09-19-LocalArgument.ll b/test/Analysis/BasicAA/2003-09-19-LocalArgument.ll new file mode 100644 index 00000000000..fd4c239bbbe --- /dev/null +++ b/test/Analysis/BasicAA/2003-09-19-LocalArgument.ll @@ -0,0 +1,15 @@ +; In this test, a local alloca cannot alias an incoming argument. + +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +; CHECK: define i32 @test +; CHECK-NEXT: ret i32 0 + +define i32 @test(i32* %P) { + %X = alloca i32 + %V1 = load i32* %P + store i32 0, i32* %X + %V2 = load i32* %P + %Diff = sub i32 %V1, %V2 + ret i32 %Diff +} diff --git a/test/Analysis/BasicAA/2003-11-04-SimpleCases.ll b/test/Analysis/BasicAA/2003-11-04-SimpleCases.ll new file mode 100644 index 00000000000..768411e9d35 --- /dev/null +++ b/test/Analysis/BasicAA/2003-11-04-SimpleCases.ll @@ -0,0 +1,18 @@ +; This testcase consists of alias relations which should be completely +; resolvable by basicaa. + +; RUN: opt < %s -basicaa -aa-eval -print-may-aliases -disable-output 2>&1 | FileCheck %s + +%T = type { i32, [10 x i8] } + +; CHECK: Function: test +; CHECK-NOT: May: + +define void @test(%T* %P) { + %A = getelementptr %T* %P, i64 0 + %B = getelementptr %T* %P, i64 0, i32 0 + %C = getelementptr %T* %P, i64 0, i32 1 + %D = getelementptr %T* %P, i64 0, i32 1, i64 0 + %E = getelementptr %T* %P, i64 0, i32 1, i64 5 + ret void +} diff --git a/test/Analysis/BasicAA/2003-12-11-ConstExprGEP.ll b/test/Analysis/BasicAA/2003-12-11-ConstExprGEP.ll new file mode 100644 index 00000000000..b7bbf7732f9 --- /dev/null +++ b/test/Analysis/BasicAA/2003-12-11-ConstExprGEP.ll @@ -0,0 +1,20 @@ +; This testcase consists of alias relations which should be completely +; resolvable by basicaa, but require analysis of getelementptr constant exprs. + +; RUN: opt < %s -basicaa -aa-eval -print-may-aliases -disable-output 2>&1 | FileCheck %s + +%T = type { i32, [10 x i8] } + +@G = external global %T + +; CHECK: Function: test +; CHECK-NOT: May: + +define void @test() { + %D = getelementptr %T* @G, i64 0, i32 0 + %E = getelementptr %T* @G, i64 0, i32 1, i64 5 + %F = getelementptr i32* getelementptr (%T* @G, i64 0, i32 0), i64 0 + %X = getelementptr [10 x i8]* getelementptr (%T* @G, i64 0, i32 1), i64 0, i64 5 + + ret void +} diff --git a/test/Analysis/BasicAA/2004-07-28-MustAliasbug.ll b/test/Analysis/BasicAA/2004-07-28-MustAliasbug.ll new file mode 100644 index 00000000000..578aa5943cb --- /dev/null +++ b/test/Analysis/BasicAA/2004-07-28-MustAliasbug.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -basicaa -dse -S | FileCheck %s + +define void @test({i32,i32 }* %P) { +; CHECK: store i32 0, i32* %X + %Q = getelementptr {i32,i32}* %P, i32 1 + %X = getelementptr {i32,i32}* %Q, i32 0, i32 1 + %Y = getelementptr {i32,i32}* %Q, i32 1, i32 1 + store i32 0, i32* %X + store i32 1, i32* %Y + ret void +} diff --git a/test/Analysis/BasicAA/2006-03-03-BadArraySubscript.ll b/test/Analysis/BasicAA/2006-03-03-BadArraySubscript.ll new file mode 100644 index 00000000000..06a804c392f --- /dev/null +++ b/test/Analysis/BasicAA/2006-03-03-BadArraySubscript.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>&1 | FileCheck %s +; TEST that A[1][0] may alias A[0][i]. +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +; CHECK: 2 no alias responses + +define void @test(i32 %N) { +entry: + %X = alloca [3 x [3 x i32]] ; <[3 x [3 x i32]]*> [#uses=4] + %tmp.24 = icmp sgt i32 %N, 0 ; <i1> [#uses=1] + br i1 %tmp.24, label %no_exit, label %loopexit + +no_exit: ; preds = %no_exit, %entry + %i.0.0 = phi i32 [ 0, %entry ], [ %inc, %no_exit ] ; <i32> [#uses=2] + %tmp.6 = getelementptr [3 x [3 x i32]]* %X, i32 0, i32 0, i32 %i.0.0 ; <i32*> [#uses=1] + store i32 1, i32* %tmp.6 + %tmp.8 = getelementptr [3 x [3 x i32]]* %X, i32 0, i32 0, i32 0 ; <i32*> [#uses=1] + %tmp.9 = load i32* %tmp.8 ; <i32> [#uses=1] + %tmp.11 = getelementptr [3 x [3 x i32]]* %X, i32 0, i32 1, i32 0 ; <i32*> [#uses=1] + %tmp.12 = load i32* %tmp.11 ; <i32> [#uses=1] + %tmp.13 = add i32 %tmp.12, %tmp.9 ; <i32> [#uses=1] + %inc = add i32 %i.0.0, 1 ; <i32> [#uses=2] + %tmp.2 = icmp slt i32 %inc, %N ; <i1> [#uses=1] + br i1 %tmp.2, label %no_exit, label %loopexit + +loopexit: ; preds = %no_exit, %entry + %Y.0.1 = phi i32 [ 0, %entry ], [ %tmp.13, %no_exit ] ; <i32> [#uses=1] + %tmp.4 = getelementptr [3 x [3 x i32]]* %X, i32 0, i32 0 ; <[3 x i32]*> [#uses=1] + %tmp.15 = call i32 (...)* @foo( [3 x i32]* %tmp.4, i32 %Y.0.1 ) ; <i32> [#uses=0] + ret void +} + +declare i32 @foo(...) diff --git a/test/Analysis/BasicAA/2006-11-03-BasicAAVectorCrash.ll b/test/Analysis/BasicAA/2006-11-03-BasicAAVectorCrash.ll new file mode 100644 index 00000000000..0db58156547 --- /dev/null +++ b/test/Analysis/BasicAA/2006-11-03-BasicAAVectorCrash.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -basicaa -licm -disable-output +target datalayout = "E-p:32:32" +target triple = "powerpc-apple-darwin8.7.0" + +define void @glgRunProcessor() { +entry: + br i1 false, label %bb2037.i, label %cond_true.i18 + +cond_true.i18: ; preds = %entry + ret void + +bb205.i: ; preds = %bb2037.i + switch i32 0, label %bb1013.i [ + i32 14, label %bb239.i + i32 15, label %bb917.i + ] + +bb239.i: ; preds = %bb205.i + br i1 false, label %cond_false277.i, label %cond_true264.i + +cond_true264.i: ; preds = %bb239.i + ret void + +cond_false277.i: ; preds = %bb239.i + %tmp1062.i = getelementptr [2 x <4 x i32>]* null, i32 0, i32 1 ; <<4 x i32>*> [#uses=1] + store <4 x i32> zeroinitializer, <4 x i32>* %tmp1062.i + br i1 false, label %cond_true1032.i, label %cond_false1063.i85 + +bb917.i: ; preds = %bb205.i + ret void + +bb1013.i: ; preds = %bb205.i + ret void + +cond_true1032.i: ; preds = %cond_false277.i + %tmp1187.i = getelementptr [2 x <4 x i32>]* null, i32 0, i32 0, i32 7 ; <i32*> [#uses=1] + store i32 0, i32* %tmp1187.i + br label %bb2037.i + +cond_false1063.i85: ; preds = %cond_false277.i + ret void + +bb2037.i: ; preds = %cond_true1032.i, %entry + br i1 false, label %bb205.i, label %cond_next2042.i + +cond_next2042.i: ; preds = %bb2037.i + ret void +} diff --git a/test/Analysis/BasicAA/2007-01-13-BasePointerBadNoAlias.ll b/test/Analysis/BasicAA/2007-01-13-BasePointerBadNoAlias.ll new file mode 100644 index 00000000000..46b6aaf91ac --- /dev/null +++ b/test/Analysis/BasicAA/2007-01-13-BasePointerBadNoAlias.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s +; PR1109 + +target datalayout = "e-p:32:32" +target triple = "i686-apple-darwin8" + %struct.CONSTRAINT = type { i32, i32, i32, i32 } + %struct.FILE_POS = type { i8, i8, i16, i32 } + %struct.FIRST_UNION = type { %struct.FILE_POS } + %struct.FOURTH_UNION = type { %struct.CONSTRAINT } + %struct.GAP = type { i8, i8, i16 } + %struct.LIST = type { %struct.rec*, %struct.rec* } + %struct.SECOND_UNION = type { { i16, i8, i8 } } + %struct.STYLE = type { { %struct.GAP }, { %struct.GAP }, i16, i16, i16, i8, i8 } + %struct.THIRD_UNION = type { { [2 x i32], [2 x i32] } } + %struct.closure_type = type { [2 x %struct.LIST], %struct.FIRST_UNION, %struct.SECOND_UNION, %struct.THIRD_UNION, %struct.FOURTH_UNION, %struct.rec*, { %struct.rec* } } + %struct.head_type = type { [2 x %struct.LIST], %struct.FIRST_UNION, %struct.SECOND_UNION, %struct.THIRD_UNION, %struct.FOURTH_UNION, %struct.rec*, { %struct.rec* }, %struct.rec*, %struct.rec*, %struct.rec*, %struct.rec*, %struct.rec*, %struct.rec*, %struct.rec*, %struct.rec*, i32 } + %struct.rec = type { %struct.head_type } + +; CHECK: define i32 @test +; CHECK: %Z = sub i32 %A, %Q +; CHECK: ret i32 %Z + +define i32 @test(%struct.closure_type* %tmp18169) { + %tmp18174 = getelementptr %struct.closure_type* %tmp18169, i32 0, i32 4, i32 0, i32 0 ; <i32*> [#uses=2] + %tmp18269 = bitcast i32* %tmp18174 to %struct.STYLE* ; <%struct.STYLE*> [#uses=1] + %A = load i32* %tmp18174 ; <i32> [#uses=1] + + %tmp18272 = getelementptr %struct.STYLE* %tmp18269, i32 0, i32 0, i32 0, i32 2 ; <i16*> [#uses=1] + store i16 123, i16* %tmp18272 + + %Q = load i32* %tmp18174 ; <i32> [#uses=1] + %Z = sub i32 %A, %Q ; <i32> [#uses=1] + ret i32 %Z +} diff --git a/test/Analysis/BasicAA/2007-08-01-NoAliasAndCalls.ll b/test/Analysis/BasicAA/2007-08-01-NoAliasAndCalls.ll new file mode 100644 index 00000000000..2a6f5b9955d --- /dev/null +++ b/test/Analysis/BasicAA/2007-08-01-NoAliasAndCalls.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +; CHECK: Function: foo +; CHECK: MayAlias: i32* %x, i32* %y + +define void @foo(i32* noalias %x) { + %y = call i32* @unclear(i32* %x) + store i32 0, i32* %x + store i32 0, i32* %y + ret void +} + +declare i32* @unclear(i32* %a) diff --git a/test/Analysis/BasicAA/2007-08-01-NoAliasAndGEP.ll b/test/Analysis/BasicAA/2007-08-01-NoAliasAndGEP.ll new file mode 100644 index 00000000000..4be793ec416 --- /dev/null +++ b/test/Analysis/BasicAA/2007-08-01-NoAliasAndGEP.ll @@ -0,0 +1,20 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +; CHECK: Function: foo +; CHECK: MayAlias: i32* %Ipointer, i32* %Jpointer +; CHECK: 9 no alias responses +; CHECK: 6 may alias responses + +define void @foo(i32* noalias %p, i32* noalias %q, i32 %i, i32 %j) { + %Ipointer = getelementptr i32* %p, i32 %i + %qi = getelementptr i32* %q, i32 %i + %Jpointer = getelementptr i32* %p, i32 %j + %qj = getelementptr i32* %q, i32 %j + store i32 0, i32* %p + store i32 0, i32* %Ipointer + store i32 0, i32* %Jpointer + store i32 0, i32* %q + store i32 0, i32* %qi + store i32 0, i32* %qj + ret void +} diff --git a/test/Analysis/BasicAA/2007-08-05-GetOverloadedModRef.ll b/test/Analysis/BasicAA/2007-08-05-GetOverloadedModRef.ll new file mode 100644 index 00000000000..ec0e2bd9141 --- /dev/null +++ b/test/Analysis/BasicAA/2007-08-05-GetOverloadedModRef.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s +; PR1600 + +declare i16 @llvm.cttz.i16(i16, i1) + +define i32 @test(i32* %P, i16* %Q) { +; CHECK: ret i32 0 + %A = load i16* %Q ; <i16> [#uses=1] + %x = load i32* %P ; <i32> [#uses=1] + %B = call i16 @llvm.cttz.i16( i16 %A, i1 true ) ; <i16> [#uses=1] + %y = load i32* %P ; <i32> [#uses=1] + store i16 %B, i16* %Q + %z = sub i32 %x, %y ; <i32> [#uses=1] + ret i32 %z +} + diff --git a/test/Analysis/BasicAA/2007-10-24-ArgumentsGlobals.ll b/test/Analysis/BasicAA/2007-10-24-ArgumentsGlobals.ll new file mode 100644 index 00000000000..429160ef6d5 --- /dev/null +++ b/test/Analysis/BasicAA/2007-10-24-ArgumentsGlobals.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -basicaa -gvn -dce -S | FileCheck %s + + %struct.A = type { i32 } + %struct.B = type { %struct.A } +@a = global %struct.B zeroinitializer ; <%struct.B*> [#uses=2] + +define i32 @_Z3fooP1A(%struct.A* %b) { +; CHECK: %tmp7 = load +; CHECK: ret i32 %tmp7 +entry: + store i32 1, i32* getelementptr (%struct.B* @a, i32 0, i32 0, i32 0), align 8 + %tmp4 = getelementptr %struct.A* %b, i32 0, i32 0 ;<i32*> [#uses=1] + store i32 0, i32* %tmp4, align 4 + %tmp7 = load i32* getelementptr (%struct.B* @a, i32 0, i32 0, i32 0), align 8 ; <i32> [#uses=1] + ret i32 %tmp7 +} diff --git a/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll b/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll new file mode 100644 index 00000000000..563d3326367 --- /dev/null +++ b/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -basicaa -gvn -disable-output +; PR1774 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + %struct.device = type { [20 x i8] } + %struct.pci_device_id = type { i32, i32, i32, i32, i32, i32, i64 } + %struct.usb_bus = type { %struct.device* } + %struct.usb_hcd = type { %struct.usb_bus, i64, [0 x i64] } +@uhci_pci_ids = external constant [1 x %struct.pci_device_id] ; <[1 x %struct.pci_device_id]*> [#uses=1] + +@__mod_pci_device_table = alias [1 x %struct.pci_device_id]* @uhci_pci_ids + ; <[1 x %struct.pci_device_id]*> [#uses=0] + +define i32 @uhci_suspend(%struct.usb_hcd* %hcd) { +entry: + %tmp17 = getelementptr %struct.usb_hcd* %hcd, i32 0, i32 2, i64 1 + ; <i64*> [#uses=1] + %tmp1718 = bitcast i64* %tmp17 to i32* ; <i32*> [#uses=1] + %tmp19 = load i32* %tmp1718, align 4 ; <i32> [#uses=0] + br i1 false, label %cond_true34, label %done_okay + +cond_true34: ; preds = %entry + %tmp631 = getelementptr %struct.usb_hcd* %hcd, i32 0, i32 2, i64 +2305843009213693950 ; <i64*> [#uses=1] + %tmp70 = bitcast i64* %tmp631 to %struct.device** + + %tmp71 = load %struct.device** %tmp70, align 8 + + ret i32 undef + +done_okay: ; preds = %entry + ret i32 undef +} diff --git a/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll b/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll new file mode 100644 index 00000000000..52d0af1b81c --- /dev/null +++ b/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -basicaa -gvn -disable-output +; PR1782 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + %struct.device = type { [20 x i8] } + %struct.pci_device_id = type { i32, i32, i32, i32, i32, i32, i64 } + %struct.usb_bus = type { %struct.device* } + %struct.usb_hcd = type { %struct.usb_bus, [0 x i64] } +@pci_ids = external constant [1 x %struct.pci_device_id] ; <[1 x %struct.pci_device_id]*> [#uses=1] + +@__mod_pci_device_table = alias [1 x %struct.pci_device_id]* @pci_ids ; <[1 x %struct.pci_device_id]*> [#uses=0] + +define i32 @ehci_pci_setup(%struct.usb_hcd* %hcd) { +entry: + %tmp14 = getelementptr %struct.usb_hcd* %hcd, i32 0, i32 0, i32 0 ; <%struct.device**> [#uses=1] + %tmp15 = load %struct.device** %tmp14, align 8 ; <%struct.device*> [#uses=0] + br i1 false, label %bb25, label %return + +bb25: ; preds = %entry + br i1 false, label %cond_true, label %return + +cond_true: ; preds = %bb25 + %tmp601 = getelementptr %struct.usb_hcd* %hcd, i32 0, i32 1, i64 2305843009213693951 ; <i64*> [#uses=1] + %tmp67 = bitcast i64* %tmp601 to %struct.device** ; <%struct.device**> [#uses=1] + %tmp68 = load %struct.device** %tmp67, align 8 ; <%struct.device*> [#uses=0] + ret i32 undef + +return: ; preds = %bb25, %entry + ret i32 undef +} diff --git a/test/Analysis/BasicAA/2008-04-15-Byval.ll b/test/Analysis/BasicAA/2008-04-15-Byval.ll new file mode 100644 index 00000000000..428189a8a87 --- /dev/null +++ b/test/Analysis/BasicAA/2008-04-15-Byval.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -std-compile-opts -S | FileCheck %s +; ModuleID = 'small2.c' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin8" + %struct.x = type { [4 x i32] } + +define void @foo(%struct.x* byval align 4 %X) nounwind { +; CHECK: store i32 2, i32* %tmp1 +entry: + %tmp = getelementptr %struct.x* %X, i32 0, i32 0 ; <[4 x i32]*> [#uses=1] + %tmp1 = getelementptr [4 x i32]* %tmp, i32 0, i32 3 ; <i32*> [#uses=1] + store i32 2, i32* %tmp1, align 4 + %tmp2 = call i32 (...)* @bar( %struct.x* byval align 4 %X ) nounwind ; <i32> [#uses=0] + br label %return +return: ; preds = %entry + ret void +} + +declare i32 @bar(...) diff --git a/test/Analysis/BasicAA/2008-06-02-GEPTailCrash.ll b/test/Analysis/BasicAA/2008-06-02-GEPTailCrash.ll new file mode 100644 index 00000000000..17091444764 --- /dev/null +++ b/test/Analysis/BasicAA/2008-06-02-GEPTailCrash.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -basicaa -gvn -disable-output +; PR2395 + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" +target triple = "i686-pc-linux-gnu" + %struct.S291 = type <{ %union.anon, i32 }> + %union.anon = type { } +@a291 = external global [5 x %struct.S291] ; <[5 x %struct.S291]*> [#uses=2] + +define void @test291() nounwind { +entry: + store i32 1138410269, i32* getelementptr ([5 x %struct.S291]* @a291, i32 0, i32 2, i32 1) + %tmp54 = load i32* bitcast (%struct.S291* getelementptr ([5 x %struct.S291]* @a291, i32 0, i32 2) to i32*), align 4 ; <i32> [#uses=0] + unreachable +} diff --git a/test/Analysis/BasicAA/2008-11-23-NoaliasRet.ll b/test/Analysis/BasicAA/2008-11-23-NoaliasRet.ll new file mode 100644 index 00000000000..3db9a3fbcdc --- /dev/null +++ b/test/Analysis/BasicAA/2008-11-23-NoaliasRet.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -basicaa -aa-eval -disable-output 2>&1 | FileCheck %s + +declare noalias i32* @_Znwj(i32 %x) nounwind + +; CHECK: 1 no alias response + +define i32 @foo() { + %A = call i32* @_Znwj(i32 4) + %B = call i32* @_Znwj(i32 4) + store i32 1, i32* %A + store i32 2, i32* %B + %C = load i32* %A + ret i32 %C +} diff --git a/test/Analysis/BasicAA/2009-03-04-GEPNoalias.ll b/test/Analysis/BasicAA/2009-03-04-GEPNoalias.ll new file mode 100644 index 00000000000..add7dee0fe1 --- /dev/null +++ b/test/Analysis/BasicAA/2009-03-04-GEPNoalias.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s + +declare noalias i32* @noalias() + +define i32 @test(i32 %x) { +; CHECK: load i32* %a + %a = call i32* @noalias() + store i32 1, i32* %a + %b = getelementptr i32* %a, i32 %x + store i32 2, i32* %b + + %c = load i32* %a + ret i32 %c +} diff --git a/test/Analysis/BasicAA/2009-10-13-AtomicModRef.ll b/test/Analysis/BasicAA/2009-10-13-AtomicModRef.ll new file mode 100644 index 00000000000..4b6a12e821e --- /dev/null +++ b/test/Analysis/BasicAA/2009-10-13-AtomicModRef.ll @@ -0,0 +1,15 @@ +; RUN: opt -basicaa -gvn -instcombine -S < %s | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +define i8 @foo(i8* %ptr) { + %P = getelementptr i8* %ptr, i32 0 + %Q = getelementptr i8* %ptr, i32 1 +; CHECK: getelementptr + %X = load i8* %P + %Y = atomicrmw add i8* %Q, i8 1 monotonic + %Z = load i8* %P +; CHECK-NOT: = load + %A = sub i8 %X, %Z + ret i8 %A +; CHECK: ret i8 0 +} diff --git a/test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll b/test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll new file mode 100644 index 00000000000..c546d68f425 --- /dev/null +++ b/test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +; If GEP base doesn't alias Z, then GEP doesn't alias Z. +; rdar://7282591 + +@Y = common global i32 0 +@Z = common global i32 0 + +; CHECK: Function: foo +; CHECK: NoAlias: i32* %P, i32* @Z + +define void @foo(i32 %cond) nounwind { +entry: + %a = alloca i32 + %tmp = icmp ne i32 %cond, 0 + br i1 %tmp, label %bb, label %bb1 + +bb: + %b = getelementptr i32* %a, i32 0 + br label %bb2 + +bb1: + br label %bb2 + +bb2: + %P = phi i32* [ %b, %bb ], [ @Y, %bb1 ] + %tmp1 = load i32* @Z, align 4 + store i32 123, i32* %P, align 4 + %tmp2 = load i32* @Z, align 4 + br label %return + +return: + ret void +} diff --git a/test/Analysis/BasicAA/2010-09-15-GEP-SignedArithmetic.ll b/test/Analysis/BasicAA/2010-09-15-GEP-SignedArithmetic.ll new file mode 100644 index 00000000000..66569808fb6 --- /dev/null +++ b/test/Analysis/BasicAA/2010-09-15-GEP-SignedArithmetic.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +; PR7959 + +target datalayout = "e-p:32:32:32" + +; CHECK: 1 partial alias response + +define i32 @test(i32* %tab, i32 %indvar) nounwind { + %tmp31 = mul i32 %indvar, -2 + %tmp32 = add i32 %tmp31, 30 + %t.5 = getelementptr i32* %tab, i32 %tmp32 + %loada = load i32* %tab + store i32 0, i32* %t.5 + %loadb = load i32* %tab + %rval = add i32 %loada, %loadb + ret i32 %rval +} diff --git a/test/Analysis/BasicAA/aligned-overread.ll b/test/Analysis/BasicAA/aligned-overread.ll new file mode 100644 index 00000000000..b05f8eb6948 --- /dev/null +++ b/test/Analysis/BasicAA/aligned-overread.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s -basicaa -dse -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.8.0" + +%struct.S0 = type <{ i8, [4 x i8] }> + +@a = global { i8, i8, i8, i8, i8 } { i8 undef, i8 0, i8 0, i8 0, i8 0 }, align 8 + +define i32 @main() nounwind uwtable ssp { +entry: + %tmp = load i8* getelementptr inbounds ({ i8, i8, i8, i8, i8 }* @a, i64 0, i32 4), align 4 + %tmp1 = or i8 %tmp, -128 + store i8 %tmp1, i8* getelementptr inbounds ({ i8, i8, i8, i8, i8 }* @a, i64 0, i32 4), align 4 + %tmp2 = load i64* bitcast ({ i8, i8, i8, i8, i8 }* @a to i64*), align 8 + store i8 11, i8* getelementptr inbounds ({ i8, i8, i8, i8, i8 }* @a, i64 0, i32 4), align 4 + %tmp3 = trunc i64 %tmp2 to i32 + ret i32 %tmp3 + +; Make sure we don't delete either store here +; CHECK: @main +; CHECK: store i8 %tmp1 +; CHECK: store i8 11 +} + diff --git a/test/Analysis/BasicAA/args-rets-allocas-loads.ll b/test/Analysis/BasicAA/args-rets-allocas-loads.ll new file mode 100644 index 00000000000..066f46b16c0 --- /dev/null +++ b/test/Analysis/BasicAA/args-rets-allocas-loads.ll @@ -0,0 +1,311 @@ +; RUN: opt -basicaa -aa-eval -print-all-alias-modref-info -disable-output < %s 2>&1 | FileCheck %s + +declare void @callee(double* %callee_arg) +declare void @nocap_callee(double* nocapture %nocap_callee_arg) + +declare double* @normal_returner() +declare noalias double* @noalias_returner() + +define void @caller_a(double* %arg_a0, + double* %arg_a1, + double* noalias %noalias_arg_a0, + double* noalias %noalias_arg_a1, + double** %indirect_a0, + double** %indirect_a1) { + %escape_alloca_a0 = alloca double + %escape_alloca_a1 = alloca double + %noescape_alloca_a0 = alloca double + %noescape_alloca_a1 = alloca double + + %normal_ret_a0 = call double* @normal_returner() + %normal_ret_a1 = call double* @normal_returner() + %noalias_ret_a0 = call double* @noalias_returner() + %noalias_ret_a1 = call double* @noalias_returner() + + %loaded_a0 = load double** %indirect_a0 + %loaded_a1 = load double** %indirect_a1 + + call void @callee(double* %escape_alloca_a0) + call void @callee(double* %escape_alloca_a1) + call void @nocap_callee(double* %noescape_alloca_a0) + call void @nocap_callee(double* %noescape_alloca_a1) + + store double 0.0, double* %loaded_a0 + store double 0.0, double* %loaded_a1 + store double 0.0, double* %arg_a0 + store double 0.0, double* %arg_a1 + store double 0.0, double* %noalias_arg_a0 + store double 0.0, double* %noalias_arg_a1 + store double 0.0, double* %escape_alloca_a0 + store double 0.0, double* %escape_alloca_a1 + store double 0.0, double* %noescape_alloca_a0 + store double 0.0, double* %noescape_alloca_a1 + store double 0.0, double* %normal_ret_a0 + store double 0.0, double* %normal_ret_a1 + store double 0.0, double* %noalias_ret_a0 + store double 0.0, double* %noalias_ret_a1 + ret void +} + +; CHECK: Function: caller_a: 16 pointers, 8 call sites +; CHECK-NEXT: MayAlias: double* %arg_a0, double* %arg_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noalias_arg_a1 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noalias_arg_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %noalias_arg_a1 +; CHECK-NEXT: MayAlias: double* %arg_a0, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %arg_a1, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %arg_a0, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double* %arg_a1, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double** %indirect_a0, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %escape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %escape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noalias_arg_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %escape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %escape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noalias_arg_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %escape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a0, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a0, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a1, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a1, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: MayAlias: double* %arg_a0, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %arg_a1, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %normal_ret_a0, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %normal_ret_a0, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a0, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a1, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a0, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a1, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %arg_a0, double* %normal_ret_a1 +; CHECK-NEXT: MayAlias: double* %arg_a1, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %normal_ret_a1 +; CHECK-NEXT: MayAlias: double* %normal_ret_a1, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %normal_ret_a1, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a0, double* %normal_ret_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a1, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a0, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %noescape_alloca_a1, double* %normal_ret_a1 +; CHECK-NEXT: MayAlias: double* %normal_ret_a0, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %arg_a0, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %arg_a1, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a0, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_arg_a1, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double** %indirect_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double** %indirect_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a0, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %escape_alloca_a1, double* %noalias_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double* %noescape_alloca_a1 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double* %normal_ret_a0 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a1, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %noalias_ret_a0, double* %noalias_ret_a1 +; CHECK-NEXT: MayAlias: double* %arg_a0, double* %loaded_a0 +; CHECK-NEXT: MayAlias: double* %arg_a1, double* %loaded_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noalias_arg_a1 +; CHECK-NEXT: MayAlias: double* %loaded_a0, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %loaded_a0, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a0, double* %loaded_a0 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a1, double* %loaded_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noescape_alloca_a1 +; CHECK-NEXT: MayAlias: double* %loaded_a0, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %loaded_a0, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a0, double* %noalias_ret_a1 +; CHECK-NEXT: MayAlias: double* %arg_a0, double* %loaded_a1 +; CHECK-NEXT: MayAlias: double* %arg_a1, double* %loaded_a1 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noalias_arg_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noalias_arg_a1 +; CHECK-NEXT: MayAlias: double* %loaded_a1, double** %indirect_a0 +; CHECK-NEXT: MayAlias: double* %loaded_a1, double** %indirect_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a0, double* %loaded_a1 +; CHECK-NEXT: MayAlias: double* %escape_alloca_a1, double* %loaded_a1 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noescape_alloca_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noescape_alloca_a1 +; CHECK-NEXT: MayAlias: double* %loaded_a1, double* %normal_ret_a0 +; CHECK-NEXT: MayAlias: double* %loaded_a1, double* %normal_ret_a1 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noalias_ret_a0 +; CHECK-NEXT: NoAlias: double* %loaded_a1, double* %noalias_ret_a1 +; CHECK-NEXT: MayAlias: double* %loaded_a0, double* %loaded_a1 +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> %normal_ret_a0 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> %normal_ret_a1 = call double* @normal_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %noalias_ret_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> %noalias_ret_a0 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %noalias_ret_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> %noalias_ret_a1 = call double* @noalias_returner() +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> call void @callee(double* %escape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> call void @callee(double* %escape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %noescape_alloca_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> call void @nocap_callee(double* %noescape_alloca_a0) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %arg_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_arg_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double** %indirect_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %escape_alloca_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noescape_alloca_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %noescape_alloca_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %normal_ret_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: NoModRef: Ptr: double* %noalias_ret_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a0 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK-NEXT: Both ModRef: Ptr: double* %loaded_a1 <-> call void @nocap_callee(double* %noescape_alloca_a1) +; CHECK: ===== Alias Analysis Evaluator Report ===== +; CHECK-NEXT: 120 Total Alias Queries Performed +; CHECK-NEXT: 84 no alias responses (70.0%) +; CHECK-NEXT: 36 may alias responses (30.0%) +; CHECK-NEXT: 0 partial alias responses (0.0%) +; CHECK-NEXT: 0 must alias responses (0.0%) +; CHECK-NEXT: Alias Analysis Evaluator Pointer Alias Summary: 70%/30%/0% +; CHECK-NEXT: 184 Total ModRef Queries Performed +; CHECK-NEXT: 44 no mod/ref responses (23.9%) +; CHECK-NEXT: 0 mod responses (0.0%) +; CHECK-NEXT: 0 ref responses (0.0%) +; CHECK-NEXT: 140 mod & ref responses (76.0%) +; CHECK-NEXT: Alias Analysis Evaluator Mod/Ref Summary: 23%/0%/0%/76% diff --git a/test/Analysis/BasicAA/byval.ll b/test/Analysis/BasicAA/byval.ll new file mode 100644 index 00000000000..673fee01cc8 --- /dev/null +++ b/test/Analysis/BasicAA/byval.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i686-apple-darwin8" + %struct.x = type { i32, i32, i32, i32 } +@g = weak global i32 0 ; <i32*> [#uses=1] + +define i32 @foo(%struct.x* byval %a) nounwind { +; CHECK: ret i32 1 + %tmp1 = tail call i32 (...)* @bar( %struct.x* %a ) nounwind ; <i32> [#uses=0] + %tmp2 = getelementptr %struct.x* %a, i32 0, i32 0 ; <i32*> [#uses=2] + store i32 1, i32* %tmp2, align 4 + store i32 2, i32* @g, align 4 + %tmp4 = load i32* %tmp2, align 4 ; <i32> [#uses=1] + ret i32 %tmp4 +} + +declare i32 @bar(...) + diff --git a/test/Analysis/BasicAA/cas.ll b/test/Analysis/BasicAA/cas.ll new file mode 100644 index 00000000000..d0cd9f40ccc --- /dev/null +++ b/test/Analysis/BasicAA/cas.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +@flag0 = internal global i32 zeroinitializer +@turn = internal global i32 zeroinitializer + +; CHECK: ret i32 0 + +define i32 @main() { + %a = load i32* @flag0 + %b = atomicrmw xchg i32* @turn, i32 1 monotonic + %c = load i32* @flag0 + %d = sub i32 %a, %c + ret i32 %d +} diff --git a/test/Analysis/BasicAA/constant-over-index.ll b/test/Analysis/BasicAA/constant-over-index.ll new file mode 100644 index 00000000000..232533cc73e --- /dev/null +++ b/test/Analysis/BasicAA/constant-over-index.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info 2>&1 | FileCheck %s +; PR4267 + +; CHECK: MayAlias: double* %p.0.i.0, double* %p3 + +; %p3 is equal to %p.0.i.0 on the second iteration of the loop, +; so MayAlias is needed. + +define void @foo([3 x [3 x double]]* noalias %p) { +entry: + %p3 = getelementptr [3 x [3 x double]]* %p, i64 0, i64 0, i64 3 + br label %loop + +loop: + %i = phi i64 [ 0, %entry ], [ %i.next, %loop ] + + %p.0.i.0 = getelementptr [3 x [3 x double]]* %p, i64 0, i64 %i, i64 0 + + store volatile double 0.0, double* %p3 + store volatile double 0.1, double* %p.0.i.0 + + %i.next = add i64 %i, 1 + %cmp = icmp slt i64 %i.next, 3 + br i1 %cmp, label %loop, label %exit + +exit: + ret void +} diff --git a/test/Analysis/BasicAA/dag.ll b/test/Analysis/BasicAA/dag.ll new file mode 100644 index 00000000000..1d2f6f1a76d --- /dev/null +++ b/test/Analysis/BasicAA/dag.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info 2>&1 | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + +; BasicAA's guard against use-def cycles shouldn't prevent it from +; analyzing use-def dags. + +; CHECK: MustAlias: i8* %base, i8* %phi +; CHECK: MustAlias: i8* %phi, i8* %wwa +; CHECK: MustAlias: i8* %phi, i8* %wwb +; CHECK: MustAlias: i16* %bigbase, i8* %phi +define i8 @foo(i8* %base, i1 %x, i1 %w) { +entry: + br i1 %w, label %wa, label %wb +wa: + %wwa = bitcast i8* %base to i8* + br label %wc +wb: + %wwb = bitcast i8* %base to i8* + br label %wc +wc: + %first = phi i8* [ %wwa, %wa ], [ %wwb, %wb ] + %fc = bitcast i8* %first to i8* + br i1 %x, label %xa, label %xb +xa: + %xxa = bitcast i8* %fc to i8* + br label %xc +xb: + %xxb = bitcast i8* %fc to i8* + br label %xc +xc: + %phi = phi i8* [ %xxa, %xa ], [ %xxb, %xb ] + + store i8 0, i8* %phi + + %bigbase = bitcast i8* %base to i16* + store i16 -1, i16* %bigbase + + %loaded = load i8* %phi + ret i8 %loaded +} diff --git a/test/Analysis/BasicAA/empty.ll b/test/Analysis/BasicAA/empty.ll new file mode 100644 index 00000000000..dfc79f9c042 --- /dev/null +++ b/test/Analysis/BasicAA/empty.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + +; CHECK: Function: foo: +; CHECK-NEXT: NoAlias: {}* %p, {}* %q + +define void @foo({}* %p, {}* %q) { + store {} {}, {}* %p + store {} {}, {}* %q + ret void +} diff --git a/test/Analysis/BasicAA/featuretest.ll b/test/Analysis/BasicAA/featuretest.ll new file mode 100644 index 00000000000..47d278fab1c --- /dev/null +++ b/test/Analysis/BasicAA/featuretest.ll @@ -0,0 +1,127 @@ +; This testcase tests for various features the basicaa test should be able to +; determine, as noted in the comments. + +; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@Global = external global { i32 } + +declare void @external(i32*) + +; Array test: Test that operations on one local array do not invalidate +; operations on another array. Important for scientific codes. +; +define i32 @different_array_test(i64 %A, i64 %B) { + %Array1 = alloca i32, i32 100 + %Array2 = alloca i32, i32 200 + + call void @external(i32* %Array1) + call void @external(i32* %Array2) + + %pointer = getelementptr i32* %Array1, i64 %A + %val = load i32* %pointer + + %pointer2 = getelementptr i32* %Array2, i64 %B + store i32 7, i32* %pointer2 + + %REMOVE = load i32* %pointer ; redundant with above load + %retval = sub i32 %REMOVE, %val + ret i32 %retval +; CHECK: @different_array_test +; CHECK: ret i32 0 +} + +; Constant index test: Constant indexes into the same array should not +; interfere with each other. Again, important for scientific codes. +; +define i32 @constant_array_index_test() { + %Array = alloca i32, i32 100 + call void @external(i32* %Array) + + %P1 = getelementptr i32* %Array, i64 7 + %P2 = getelementptr i32* %Array, i64 6 + + %A = load i32* %P1 + store i32 1, i32* %P2 ; Should not invalidate load + %BREMOVE = load i32* %P1 + %Val = sub i32 %A, %BREMOVE + ret i32 %Val +; CHECK: @constant_array_index_test +; CHECK: ret i32 0 +} + +; Test that if two pointers are spaced out by a constant getelementptr, that +; they cannot alias. +define i32 @gep_distance_test(i32* %A) { + %REMOVEu = load i32* %A + %B = getelementptr i32* %A, i64 2 ; Cannot alias A + store i32 7, i32* %B + %REMOVEv = load i32* %A + %r = sub i32 %REMOVEu, %REMOVEv + ret i32 %r +; CHECK: @gep_distance_test +; CHECK: ret i32 0 +} + +; Test that if two pointers are spaced out by a constant offset, that they +; cannot alias, even if there is a variable offset between them... +define i32 @gep_distance_test2({i32,i32}* %A, i64 %distance) { + %A1 = getelementptr {i32,i32}* %A, i64 0, i32 0 + %REMOVEu = load i32* %A1 + %B = getelementptr {i32,i32}* %A, i64 %distance, i32 1 + store i32 7, i32* %B ; B cannot alias A, it's at least 4 bytes away + %REMOVEv = load i32* %A1 + %r = sub i32 %REMOVEu, %REMOVEv + ret i32 %r +; CHECK: @gep_distance_test2 +; CHECK: ret i32 0 +} + +; Test that we can do funny pointer things and that distance calc will still +; work. +define i32 @gep_distance_test3(i32 * %A) { + %X = load i32* %A + %B = bitcast i32* %A to i8* + %C = getelementptr i8* %B, i64 4 + store i8 42, i8* %C + %Y = load i32* %A + %R = sub i32 %X, %Y + ret i32 %R +; CHECK: @gep_distance_test3 +; CHECK: ret i32 0 +} + +; Test that we can disambiguate globals reached through constantexpr geps +define i32 @constexpr_test() { + %X = alloca i32 + call void @external(i32* %X) + + %Y = load i32* %X + store i32 5, i32* getelementptr ({ i32 }* @Global, i64 0, i32 0) + %REMOVE = load i32* %X + %retval = sub i32 %Y, %REMOVE + ret i32 %retval +; CHECK: @constexpr_test +; CHECK: ret i32 0 +} + + + +; PR7589 +; These two index expressions are different, this cannot be CSE'd. +define i16 @zext_sext_confusion(i16* %row2col, i5 %j) nounwind{ +entry: + %sum5.cast = zext i5 %j to i64 ; <i64> [#uses=1] + %P1 = getelementptr i16* %row2col, i64 %sum5.cast + %row2col.load.1.2 = load i16* %P1, align 1 ; <i16> [#uses=1] + + %sum13.cast31 = sext i5 %j to i6 ; <i6> [#uses=1] + %sum13.cast = zext i6 %sum13.cast31 to i64 ; <i64> [#uses=1] + %P2 = getelementptr i16* %row2col, i64 %sum13.cast + %row2col.load.1.6 = load i16* %P2, align 1 ; <i16> [#uses=1] + + %.ret = sub i16 %row2col.load.1.6, %row2col.load.1.2 ; <i16> [#uses=1] + ret i16 %.ret +; CHECK: @zext_sext_confusion +; CHECK: ret i16 %.ret +} diff --git a/test/Analysis/BasicAA/full-store-partial-alias.ll b/test/Analysis/BasicAA/full-store-partial-alias.ll new file mode 100644 index 00000000000..2c34fd5f615 --- /dev/null +++ b/test/Analysis/BasicAA/full-store-partial-alias.ll @@ -0,0 +1,35 @@ +; RUN: opt -S -tbaa -basicaa -gvn < %s | FileCheck -check-prefix=BASICAA %s +; RUN: opt -S -tbaa -gvn < %s | FileCheck %s +; rdar://8875631, rdar://8875069 + +; BasicAA should notice that the store stores to the entire %u object, +; so the %tmp5 load is PartialAlias with the store and suppress TBAA. +; Without BasicAA, TBAA should say that %tmp5 is NoAlias with the store. + +target datalayout = "e-p:64:64:64" + +%union.anon = type { double } + +@u = global %union.anon { double -2.500000e-01 }, align 8 +@endianness_test = global i64 1, align 8 + +define i32 @signbit(double %x) nounwind { +; BASICAA: ret i32 %tmp5.lobit +; CHECK: ret i32 0 +entry: + %u = alloca %union.anon, align 8 + %tmp9 = getelementptr inbounds %union.anon* %u, i64 0, i32 0 + store double %x, double* %tmp9, align 8, !tbaa !0 + %tmp2 = load i32* bitcast (i64* @endianness_test to i32*), align 8, !tbaa !3 + %idxprom = sext i32 %tmp2 to i64 + %tmp4 = bitcast %union.anon* %u to [2 x i32]* + %arrayidx = getelementptr inbounds [2 x i32]* %tmp4, i64 0, i64 %idxprom + %tmp5 = load i32* %arrayidx, align 4, !tbaa !3 + %tmp5.lobit = lshr i32 %tmp5, 31 + ret i32 %tmp5.lobit +} + +!0 = metadata !{metadata !"double", metadata !1} +!1 = metadata !{metadata !"omnipotent char", metadata !2} +!2 = metadata !{metadata !"Simple C/C++ TBAA", null} +!3 = metadata !{metadata !"int", metadata !1} diff --git a/test/Analysis/BasicAA/gcsetest.ll b/test/Analysis/BasicAA/gcsetest.ll new file mode 100644 index 00000000000..db557b7a248 --- /dev/null +++ b/test/Analysis/BasicAA/gcsetest.ll @@ -0,0 +1,61 @@ +; Test that GCSE uses basicaa to do alias analysis, which is capable of +; disambiguating some obvious cases. All loads should be removable in +; this testcase. + +; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s + +@A = global i32 7 +@B = global i32 8 + +; CHECK: define i32 @test() +; CHECK-NEXT: store i32 123, i32* @B +; CHECK-NEXT: ret i32 0 + +define i32 @test() { + %A1 = load i32* @A + + store i32 123, i32* @B ; Store cannot alias @A + + %A2 = load i32* @A + %X = sub i32 %A1, %A2 + ret i32 %X +} + +; CHECK: define i32 @test2() +; CHECK-NEXT: br label %Loop +; CHECK: Loop: +; CHECK-NEXT: store i32 0, i32* @B +; CHECK-NEXT: br i1 true, label %out, label %Loop +; CHECK: out: +; CHECK-NEXT: ret i32 0 + +define i32 @test2() { + %A1 = load i32* @A + br label %Loop +Loop: + %AP = phi i32 [0, %0], [%X, %Loop] + store i32 %AP, i32* @B ; Store cannot alias @A + + %A2 = load i32* @A + %X = sub i32 %A1, %A2 + %c = icmp eq i32 %X, 0 + br i1 %c, label %out, label %Loop + +out: + ret i32 %X +} + +declare void @external() + +; CHECK: define i32 @test3() +; CHECK-NEXT: call void @external() +; CHECK-NEXT: ret i32 7 + +define i32 @test3() { + %X = alloca i32 + store i32 7, i32* %X + call void @external() + %V = load i32* %X + ret i32 %V +} + diff --git a/test/Analysis/BasicAA/gep-alias.ll b/test/Analysis/BasicAA/gep-alias.ll new file mode 100644 index 00000000000..9c2c7eeec38 --- /dev/null +++ b/test/Analysis/BasicAA/gep-alias.ll @@ -0,0 +1,203 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S 2>&1 | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + +; Make sure that basicaa thinks R and r are must aliases. +define i32 @test1(i8 * %P) { +entry: + %Q = bitcast i8* %P to {i32, i32}* + %R = getelementptr {i32, i32}* %Q, i32 0, i32 1 + %S = load i32* %R + + %q = bitcast i8* %P to {i32, i32}* + %r = getelementptr {i32, i32}* %q, i32 0, i32 1 + %s = load i32* %r + + %t = sub i32 %S, %s + ret i32 %t +; CHECK: @test1 +; CHECK: ret i32 0 +} + +define i32 @test2(i8 * %P) { +entry: + %Q = bitcast i8* %P to {i32, i32, i32}* + %R = getelementptr {i32, i32, i32}* %Q, i32 0, i32 1 + %S = load i32* %R + + %r = getelementptr {i32, i32, i32}* %Q, i32 0, i32 2 + store i32 42, i32* %r + + %s = load i32* %R + + %t = sub i32 %S, %s + ret i32 %t +; CHECK: @test2 +; CHECK: ret i32 0 +} + + +; This was a miscompilation. +define i32 @test3({float, {i32, i32, i32}}* %P) { +entry: + %P2 = getelementptr {float, {i32, i32, i32}}* %P, i32 0, i32 1 + %R = getelementptr {i32, i32, i32}* %P2, i32 0, i32 1 + %S = load i32* %R + + %r = getelementptr {i32, i32, i32}* %P2, i32 0, i32 2 + store i32 42, i32* %r + + %s = load i32* %R + + %t = sub i32 %S, %s + ret i32 %t +; CHECK: @test3 +; CHECK: ret i32 0 +} + + +;; This is reduced from the SmallPtrSet constructor. +%SmallPtrSetImpl = type { i8**, i32, i32, i32, [1 x i8*] } +%SmallPtrSet64 = type { %SmallPtrSetImpl, [64 x i8*] } + +define i32 @test4(%SmallPtrSet64* %P) { +entry: + %tmp2 = getelementptr inbounds %SmallPtrSet64* %P, i64 0, i32 0, i32 1 + store i32 64, i32* %tmp2, align 8 + %tmp3 = getelementptr inbounds %SmallPtrSet64* %P, i64 0, i32 0, i32 4, i64 64 + store i8* null, i8** %tmp3, align 8 + %tmp4 = load i32* %tmp2, align 8 + ret i32 %tmp4 +; CHECK: @test4 +; CHECK: ret i32 64 +} + +; P[i] != p[i+1] +define i32 @test5(i32* %p, i64 %i) { + %pi = getelementptr i32* %p, i64 %i + %i.next = add i64 %i, 1 + %pi.next = getelementptr i32* %p, i64 %i.next + %x = load i32* %pi + store i32 42, i32* %pi.next + %y = load i32* %pi + %z = sub i32 %x, %y + ret i32 %z +; CHECK: @test5 +; CHECK: ret i32 0 +} + +; P[i] != p[(i*4)|1] +define i32 @test6(i32* %p, i64 %i1) { + %i = shl i64 %i1, 2 + %pi = getelementptr i32* %p, i64 %i + %i.next = or i64 %i, 1 + %pi.next = getelementptr i32* %p, i64 %i.next + %x = load i32* %pi + store i32 42, i32* %pi.next + %y = load i32* %pi + %z = sub i32 %x, %y + ret i32 %z +; CHECK: @test6 +; CHECK: ret i32 0 +} + +; P[1] != P[i*4] +define i32 @test7(i32* %p, i64 %i) { + %pi = getelementptr i32* %p, i64 1 + %i.next = shl i64 %i, 2 + %pi.next = getelementptr i32* %p, i64 %i.next + %x = load i32* %pi + store i32 42, i32* %pi.next + %y = load i32* %pi + %z = sub i32 %x, %y + ret i32 %z +; CHECK: @test7 +; CHECK: ret i32 0 +} + +; P[zext(i)] != p[zext(i+1)] +; PR1143 +define i32 @test8(i32* %p, i16 %i) { + %i1 = zext i16 %i to i32 + %pi = getelementptr i32* %p, i32 %i1 + %i.next = add i16 %i, 1 + %i.next2 = zext i16 %i.next to i32 + %pi.next = getelementptr i32* %p, i32 %i.next2 + %x = load i32* %pi + store i32 42, i32* %pi.next + %y = load i32* %pi + %z = sub i32 %x, %y + ret i32 %z +; CHECK: @test8 +; CHECK: ret i32 0 +} + +define i8 @test9([4 x i8] *%P, i32 %i, i32 %j) { + %i2 = shl i32 %i, 2 + %i3 = add i32 %i2, 1 + ; P2 = P + 1 + 4*i + %P2 = getelementptr [4 x i8] *%P, i32 0, i32 %i3 + + %j2 = shl i32 %j, 2 + + ; P4 = P + 4*j + %P4 = getelementptr [4 x i8]* %P, i32 0, i32 %j2 + + %x = load i8* %P2 + store i8 42, i8* %P4 + %y = load i8* %P2 + %z = sub i8 %x, %y + ret i8 %z +; CHECK: @test9 +; CHECK: ret i8 0 +} + +define i8 @test10([4 x i8] *%P, i32 %i) { + %i2 = shl i32 %i, 2 + %i3 = add i32 %i2, 4 + ; P2 = P + 4 + 4*i + %P2 = getelementptr [4 x i8] *%P, i32 0, i32 %i3 + + ; P4 = P + 4*i + %P4 = getelementptr [4 x i8]* %P, i32 0, i32 %i2 + + %x = load i8* %P2 + store i8 42, i8* %P4 + %y = load i8* %P2 + %z = sub i8 %x, %y + ret i8 %z +; CHECK: @test10 +; CHECK: ret i8 0 +} + +; (This was a miscompilation.) +define float @test11(i32 %indvar, [4 x [2 x float]]* %q) nounwind ssp { + %tmp = mul i32 %indvar, -1 + %dec = add i32 %tmp, 3 + %scevgep = getelementptr [4 x [2 x float]]* %q, i32 0, i32 %dec + %scevgep35 = bitcast [2 x float]* %scevgep to i64* + %arrayidx28 = getelementptr inbounds [4 x [2 x float]]* %q, i32 0, i32 0 + %y29 = getelementptr inbounds [2 x float]* %arrayidx28, i32 0, i32 1 + store float 1.0, float* %y29, align 4 + store i64 0, i64* %scevgep35, align 4 + %tmp30 = load float* %y29, align 4 + ret float %tmp30 + ; CHECK: @test11 + ; CHECK: ret float %tmp30 +} + +; (This was a miscompilation.) +define i32 @test12(i32 %x, i32 %y, i8* %p) nounwind { + %a = bitcast i8* %p to [13 x i8]* + %b = getelementptr [13 x i8]* %a, i32 %x + %c = bitcast [13 x i8]* %b to [15 x i8]* + %d = getelementptr [15 x i8]* %c, i32 %y, i32 8 + %castd = bitcast i8* %d to i32* + %castp = bitcast i8* %p to i32* + store i32 1, i32* %castp + store i32 0, i32* %castd + %r = load i32* %castp + ret i32 %r + ; CHECK: @test12 + ; CHECK: ret i32 %r +} diff --git a/test/Analysis/BasicAA/getmodrefinfo-cs-cs.ll b/test/Analysis/BasicAA/getmodrefinfo-cs-cs.ll new file mode 100644 index 00000000000..f0f1a631d08 --- /dev/null +++ b/test/Analysis/BasicAA/getmodrefinfo-cs-cs.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + + +; CHECK: Just Ref: call void @ro() <-> call void @f0() + +declare void @f0() +declare void @ro() readonly + +define void @test0() { + call void @f0() + call void @ro() + ret void +} + +; CHECK: NoModRef: call void @llvm.memset.p0i8.i64(i8* @A, i8 0, i64 1, i32 1, i1 false) <-> call void @llvm.memset.p0i8.i64(i8* @B, i8 0, i64 1, i32 1, i1 false) +; CHECK: NoModRef: call void @llvm.memset.p0i8.i64(i8* @B, i8 0, i64 1, i32 1, i1 false) <-> call void @llvm.memset.p0i8.i64(i8* @A, i8 0, i64 1, i32 1, i1 false) + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind + +@A = external global i8 +@B = external global i8 +define void @test1() { + call void @llvm.memset.p0i8.i64(i8* @A, i8 0, i64 1, i32 1, i1 false) + call void @llvm.memset.p0i8.i64(i8* @B, i8 0, i64 1, i32 1, i1 false) + ret void +} diff --git a/test/Analysis/BasicAA/global-size.ll b/test/Analysis/BasicAA/global-size.ll new file mode 100644 index 00000000000..a7e5aab6c1f --- /dev/null +++ b/test/Analysis/BasicAA/global-size.ll @@ -0,0 +1,40 @@ +; A store or load cannot alias a global if the accessed amount is larger then +; the global. + +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@B = global i16 8 + +; CHECK: @test1 +define i16 @test1(i32* %P) { + %X = load i16* @B + store i32 7, i32* %P + %Y = load i16* @B + %Z = sub i16 %Y, %X + ret i16 %Z +; CHECK: ret i16 0 +} + +; Cannot know anything about the size of this global. +; rdar://8813415 +@window = external global [0 x i8] + +; CHECK: @test2 +define i8 @test2(i32 %tmp79, i32 %w.2, i32 %indvar89) nounwind { + %tmp92 = add i32 %tmp79, %indvar89 + %arrayidx412 = getelementptr [0 x i8]* @window, i32 0, i32 %tmp92 + %tmp93 = add i32 %w.2, %indvar89 + %arrayidx416 = getelementptr [0 x i8]* @window, i32 0, i32 %tmp93 + + %A = load i8* %arrayidx412, align 1 + store i8 4, i8* %arrayidx416, align 1 + + %B = load i8* %arrayidx412, align 1 + %C = sub i8 %A, %B + ret i8 %C + +; CHECK: %B = load i8 +; CHECK: ret i8 %C +} + diff --git a/test/Analysis/BasicAA/intrinsics.ll b/test/Analysis/BasicAA/intrinsics.ll new file mode 100644 index 00000000000..59725cfded0 --- /dev/null +++ b/test/Analysis/BasicAA/intrinsics.ll @@ -0,0 +1,39 @@ +; RUN: opt -basicaa -gvn -S < %s | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" + +; BasicAA should prove that these calls don't interfere, since they are +; IntrArgReadMem and have noalias pointers. + +; CHECK: define <8 x i16> @test0(i8* noalias %p, i8* noalias %q, <8 x i16> %y) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind +; CHECK-NEXT: call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK-NEXT: %c = add <8 x i16> %a, %a +define <8 x i16> @test0(i8* noalias %p, i8* noalias %q, <8 x i16> %y) { +entry: + %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) + %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + %c = add <8 x i16> %a, %b + ret <8 x i16> %c +} + +; CHECK: define <8 x i16> @test1(i8* %p, <8 x i16> %y) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %q = getelementptr i8* %p, i64 16 +; CHECK-NEXT: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind +; CHECK-NEXT: call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK-NEXT: %c = add <8 x i16> %a, %a +define <8 x i16> @test1(i8* %p, <8 x i16> %y) { +entry: + %q = getelementptr i8* %p, i64 16 + %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) + %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + %c = add <8 x i16> %a, %b + ret <8 x i16> %c +} + +declare <8 x i16> @llvm.arm.neon.vld1.v8i16(i8*, i32) nounwind readonly +declare void @llvm.arm.neon.vst1.v8i16(i8*, <8 x i16>, i32) nounwind diff --git a/test/Analysis/BasicAA/lit.local.cfg b/test/Analysis/BasicAA/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/BasicAA/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/BasicAA/memset_pattern.ll b/test/Analysis/BasicAA/memset_pattern.ll new file mode 100644 index 00000000000..590664c5084 --- /dev/null +++ b/test/Analysis/BasicAA/memset_pattern.ll @@ -0,0 +1,21 @@ +; RUN: opt -S -basicaa -gvn < %s | FileCheck %s +; PR10872 +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-apple-macosx10.7" + +@z = internal global i32 0, align 4 +@y = internal global i32 0, align 4 +@x = internal constant i32 0, align 4 + +; CHECK: @test +define i32 @test() nounwind uwtable ssp { +entry: + store i32 1, i32* @z + tail call void @memset_pattern16(i8* bitcast (i32* @y to i8*), i8* bitcast (i32* @x to i8*), i64 4) nounwind +; CHECK-NOT: load + %l = load i32* @z +; CHECK: ret i32 1 + ret i32 %l +} + +declare void @memset_pattern16(i8*, i8*, i64) diff --git a/test/Analysis/BasicAA/modref.ll b/test/Analysis/BasicAA/modref.ll new file mode 100644 index 00000000000..8421faf9c2c --- /dev/null +++ b/test/Analysis/BasicAA/modref.ll @@ -0,0 +1,151 @@ +; RUN: opt < %s -basicaa -gvn -dse -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +declare void @llvm.lifetime.end(i64, i8* nocapture) + +declare void @external(i32*) + +define i32 @test0(i8* %P) { + %A = alloca i32 + call void @external(i32* %A) + + store i32 0, i32* %A + + call void @llvm.memset.p0i8.i32(i8* %P, i8 0, i32 42, i32 1, i1 false) + + %B = load i32* %A + ret i32 %B + +; CHECK: @test0 +; CHECK: ret i32 0 +} + +define i8 @test1() { +; CHECK: @test1 + %A = alloca i8 + %B = alloca i8 + + store i8 2, i8* %B ;; Not written to by memcpy + + call void @llvm.memcpy.p0i8.p0i8.i8(i8* %A, i8* %B, i8 -1, i32 0, i1 false) + + %C = load i8* %B + ret i8 %C +; CHECK: ret i8 2 +} + +define i8 @test2(i8* %P) { +; CHECK: @test2 + %P2 = getelementptr i8* %P, i32 127 + store i8 1, i8* %P2 ;; Not dead across memset + call void @llvm.memset.p0i8.i8(i8* %P, i8 2, i8 127, i32 0, i1 false) + %A = load i8* %P2 + ret i8 %A +; CHECK: ret i8 1 +} + +define i8 @test2a(i8* %P) { +; CHECK: @test2 + %P2 = getelementptr i8* %P, i32 126 + + ;; FIXME: DSE isn't zapping this dead store. + store i8 1, i8* %P2 ;; Dead, clobbered by memset. + + call void @llvm.memset.p0i8.i8(i8* %P, i8 2, i8 127, i32 0, i1 false) + %A = load i8* %P2 + ret i8 %A +; CHECK-NOT: load +; CHECK: ret i8 2 +} + +define void @test3(i8* %P, i8 %X) { +; CHECK: @test3 +; CHECK-NOT: store +; CHECK-NOT: %Y + %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. + + %P2 = getelementptr i8* %P, i32 2 + store i8 %Y, i8* %P2 ;; Not read by lifetime.end, should be removed. +; CHECK: store i8 2, i8* %P2 + call void @llvm.lifetime.end(i64 1, i8* %P) + store i8 2, i8* %P2 +; CHECK-NOT: store + ret void +; CHECK: ret void +} + +define void @test3a(i8* %P, i8 %X) { +; CHECK: @test3a + %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. + + %P2 = getelementptr i8* %P, i32 2 + store i8 %Y, i8* %P2 +; CHECK-NEXT: call void @llvm.lifetime.end + call void @llvm.lifetime.end(i64 10, i8* %P) + ret void +; CHECK-NEXT: ret void +} + +@G1 = external global i32 +@G2 = external global [4000 x i32] + +define i32 @test4(i8* %P) { + %tmp = load i32* @G1 + call void @llvm.memset.p0i8.i32(i8* bitcast ([4000 x i32]* @G2 to i8*), i8 0, i32 4000, i32 1, i1 false) + %tmp2 = load i32* @G1 + %sub = sub i32 %tmp2, %tmp + ret i32 %sub +; CHECK: @test4 +; CHECK-NOT: load +; CHECK: memset.p0i8.i32 +; CHECK-NOT: load +; CHECK: ret i32 0 +} + +; Verify that basicaa is handling variable length memcpy, knowing it doesn't +; write to G1. +define i32 @test5(i8* %P, i32 %Len) { + %tmp = load i32* @G1 + call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast ([4000 x i32]* @G2 to i8*), i8* bitcast (i32* @G1 to i8*), i32 %Len, i32 1, i1 false) + %tmp2 = load i32* @G1 + %sub = sub i32 %tmp2, %tmp + ret i32 %sub +; CHECK: @test5 +; CHECK-NOT: load +; CHECK: memcpy.p0i8.p0i8.i32 +; CHECK-NOT: load +; CHECK: ret i32 0 +} + +define i8 @test6(i8* %p, i8* noalias %a) { + %x = load i8* %a + %t = va_arg i8* %p, float + %y = load i8* %a + %z = add i8 %x, %y + ret i8 %z +; CHECK: @test6 +; CHECK: load i8* %a +; CHECK-NOT: load +; CHECK: ret +} + +; PR10628 +declare void @test7decl(i32* nocapture %x) +define i32 @test7() nounwind uwtable ssp { +entry: + %x = alloca i32, align 4 + store i32 0, i32* %x, align 4 + %add.ptr = getelementptr inbounds i32* %x, i64 1 + call void @test7decl(i32* %add.ptr) + %tmp = load i32* %x, align 4 + ret i32 %tmp +; CHECK: @test7( +; CHECK: store i32 0 +; CHECK: call void @test7decl +; CHECK: load i32* +} + +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) nounwind +declare void @llvm.memset.p0i8.i8(i8* nocapture, i8, i8, i32, i1) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i8(i8* nocapture, i8* nocapture, i8, i32, i1) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind diff --git a/test/Analysis/BasicAA/must-and-partial.ll b/test/Analysis/BasicAA/must-and-partial.ll new file mode 100644 index 00000000000..58139ff30ec --- /dev/null +++ b/test/Analysis/BasicAA/must-and-partial.ll @@ -0,0 +1,39 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info 2>&1 | FileCheck %s + +; When merging MustAlias and PartialAlias, merge to PartialAlias +; instead of MayAlias. + + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + +; CHECK: PartialAlias: i16* %bigbase0, i8* %phi +define i8 @test0(i8* %base, i1 %x) { +entry: + %baseplusone = getelementptr i8* %base, i64 1 + br i1 %x, label %red, label %green +red: + br label %green +green: + %phi = phi i8* [ %baseplusone, %red ], [ %base, %entry ] + store i8 0, i8* %phi + + %bigbase0 = bitcast i8* %base to i16* + store i16 -1, i16* %bigbase0 + + %loaded = load i8* %phi + ret i8 %loaded +} + +; CHECK: PartialAlias: i16* %bigbase1, i8* %sel +define i8 @test1(i8* %base, i1 %x) { +entry: + %baseplusone = getelementptr i8* %base, i64 1 + %sel = select i1 %x, i8* %baseplusone, i8* %base + store i8 0, i8* %sel + + %bigbase1 = bitcast i8* %base to i16* + store i16 -1, i16* %bigbase1 + + %loaded = load i8* %sel + ret i8 %loaded +} diff --git a/test/Analysis/BasicAA/no-escape-call.ll b/test/Analysis/BasicAA/no-escape-call.ll new file mode 100644 index 00000000000..b93db6e0ee7 --- /dev/null +++ b/test/Analysis/BasicAA/no-escape-call.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s +; PR2436 +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin8" + +define i1 @foo(i32 %i) nounwind { +; CHECK: ret i1 true +entry: + %arr = alloca [10 x i8*] ; <[10 x i8*]*> [#uses=1] + %tmp2 = call i8* @getPtr( ) nounwind ; <i8*> [#uses=2] + %tmp4 = getelementptr [10 x i8*]* %arr, i32 0, i32 %i ; <i8**> [#uses=2] + store i8* %tmp2, i8** %tmp4, align 4 + %tmp10 = getelementptr i8* %tmp2, i32 10 ; <i8*> [#uses=1] + store i8 42, i8* %tmp10, align 1 + %tmp14 = load i8** %tmp4, align 4 ; <i8*> [#uses=1] + %tmp16 = getelementptr i8* %tmp14, i32 10 ; <i8*> [#uses=1] + %tmp17 = load i8* %tmp16, align 1 ; <i8> [#uses=1] + %tmp19 = icmp eq i8 %tmp17, 42 ; <i1> [#uses=1] + ret i1 %tmp19 +} + +declare i8* @getPtr() + +declare void @abort() noreturn nounwind diff --git a/test/Analysis/BasicAA/noalias-geps.ll b/test/Analysis/BasicAA/noalias-geps.ll new file mode 100644 index 00000000000..a93d778da07 --- /dev/null +++ b/test/Analysis/BasicAA/noalias-geps.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + +; Check that geps with equal base offsets of noalias base pointers stay noalias. +define i32 @test(i32* %p, i16 %i) { + %pi = getelementptr i32* %p, i32 0 + %pi.next = getelementptr i32* %p, i32 1 + %b = icmp eq i16 %i, 0 + br i1 %b, label %bb1, label %bb2 + +bb1: + %f = getelementptr i32* %pi, i32 1 + %g = getelementptr i32* %pi.next, i32 1 + br label %bb3 +bb2: + %f2 = getelementptr i32* %pi, i32 1 + %g2 = getelementptr i32* %pi.next, i32 1 + br label %bb3 + +bb3: + %ptr_phi = phi i32* [ %f, %bb1 ], [ %f2, %bb2 ] + %ptr_phi2 = phi i32* [ %g, %bb1 ], [ %g2, %bb2 ] +; CHECK: NoAlias: i32* %f1, i32* %g1 + %f1 = getelementptr i32* %ptr_phi , i32 1 + %g1 = getelementptr i32* %ptr_phi2 , i32 1 + +ret i32 0 +} + +; Check that geps with equal indices of noalias base pointers stay noalias. +define i32 @test2([2 x i32]* %p, i32 %i) { + %pi = getelementptr [2 x i32]* %p, i32 0 + %pi.next = getelementptr [2 x i32]* %p, i32 1 + %b = icmp eq i32 %i, 0 + br i1 %b, label %bb1, label %bb2 + +bb1: + %f = getelementptr [2 x i32]* %pi, i32 1 + %g = getelementptr [2 x i32]* %pi.next, i32 1 + br label %bb3 +bb2: + %f2 = getelementptr [2 x i32]* %pi, i32 1 + %g2 = getelementptr [2 x i32]* %pi.next, i32 1 + br label %bb3 +bb3: + %ptr_phi = phi [2 x i32]* [ %f, %bb1 ], [ %f2, %bb2 ] + %ptr_phi2 = phi [2 x i32]* [ %g, %bb1 ], [ %g2, %bb2 ] +; CHECK: NoAlias: i32* %f1, i32* %g1 + %f1 = getelementptr [2 x i32]* %ptr_phi , i32 1, i32 %i + %g1 = getelementptr [2 x i32]* %ptr_phi2 , i32 1, i32 %i + +ret i32 0 +} diff --git a/test/Analysis/BasicAA/nocapture.ll b/test/Analysis/BasicAA/nocapture.ll new file mode 100644 index 00000000000..a8658ec801a --- /dev/null +++ b/test/Analysis/BasicAA/nocapture.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +declare i32* @test(i32* nocapture) + +define i32 @test2() { +; CHECK: ret i32 0 + %P = alloca i32 + %Q = call i32* @test(i32* %P) + %a = load i32* %P + store i32 4, i32* %Q ;; cannot clobber P since it is nocapture. + %b = load i32* %P + %c = sub i32 %a, %b + ret i32 %c +} + diff --git a/test/Analysis/BasicAA/phi-aa.ll b/test/Analysis/BasicAA/phi-aa.ll new file mode 100644 index 00000000000..6aa26c185e0 --- /dev/null +++ b/test/Analysis/BasicAA/phi-aa.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +; rdar://7282591 + +@X = common global i32 0 +@Y = common global i32 0 +@Z = common global i32 0 + +; CHECK: NoAlias: i32* %P, i32* @Z + +define void @foo(i32 %cond) nounwind { +entry: + %"alloca point" = bitcast i32 0 to i32 + %tmp = icmp ne i32 %cond, 0 + br i1 %tmp, label %bb, label %bb1 + +bb: + br label %bb2 + +bb1: + br label %bb2 + +bb2: + %P = phi i32* [ @X, %bb ], [ @Y, %bb1 ] + %tmp1 = load i32* @Z, align 4 + store i32 123, i32* %P, align 4 + %tmp2 = load i32* @Z, align 4 + br label %return + +return: + ret void +} diff --git a/test/Analysis/BasicAA/phi-and-select.ll b/test/Analysis/BasicAA/phi-and-select.ll new file mode 100644 index 00000000000..b8fee00ed0d --- /dev/null +++ b/test/Analysis/BasicAA/phi-and-select.ll @@ -0,0 +1,82 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +; BasicAA should detect NoAliases in PHIs and Selects. + +; CHECK: Function: foo +; CHECK: NoAlias: double* %a, double* %b +; CHECK: Function: bar +; CHECK: NoAlias: double* %a, double* %b +; CHECK: Function: qux +; CHECK: NoAlias: double* %a, double* %b +; CHECK: Function: fin +; CHECK: NoAlias: double* %a, double* %b +; CHECK: ===== Alias Analysis Evaluator Report ===== + +; Two PHIs in the same block. +define void @foo(i1 %m, double* noalias %x, double* noalias %y) { +entry: + br i1 %m, label %true, label %false + +true: + br label %exit + +false: + br label %exit + +exit: + %a = phi double* [ %x, %true ], [ %y, %false ] + %b = phi double* [ %x, %false ], [ %y, %true ] + store volatile double 0.0, double* %a + store volatile double 1.0, double* %b + ret void +} + +; Two selects with the same condition. +define void @bar(i1 %m, double* noalias %x, double* noalias %y) { +entry: + %a = select i1 %m, double* %x, double* %y + %b = select i1 %m, double* %y, double* %x + store volatile double 0.000000e+00, double* %a + store volatile double 1.000000e+00, double* %b + ret void +} + +; Two PHIs with disjoint sets of inputs. +define void @qux(i1 %m, double* noalias %x, double* noalias %y, + i1 %n, double* noalias %v, double* noalias %w) { +entry: + br i1 %m, label %true, label %false + +true: + br label %exit + +false: + br label %exit + +exit: + %a = phi double* [ %x, %true ], [ %y, %false ] + br i1 %n, label %ntrue, label %nfalse + +ntrue: + br label %nexit + +nfalse: + br label %nexit + +nexit: + %b = phi double* [ %v, %ntrue ], [ %w, %nfalse ] + store volatile double 0.0, double* %a + store volatile double 1.0, double* %b + ret void +} + +; Two selects with disjoint sets of arms. +define void @fin(i1 %m, double* noalias %x, double* noalias %y, + i1 %n, double* noalias %v, double* noalias %w) { +entry: + %a = select i1 %m, double* %x, double* %y + %b = select i1 %n, double* %v, double* %w + store volatile double 0.000000e+00, double* %a + store volatile double 1.000000e+00, double* %b + ret void +} diff --git a/test/Analysis/BasicAA/phi-speculation.ll b/test/Analysis/BasicAA/phi-speculation.ll new file mode 100644 index 00000000000..21c65929862 --- /dev/null +++ b/test/Analysis/BasicAA/phi-speculation.ll @@ -0,0 +1,33 @@ +target datalayout = +"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +; ptr_phi and ptr2_phi do not alias. +; CHECK: NoAlias: i32* %ptr2_phi, i32* %ptr_phi + +define i32 @test_noalias(i32* %ptr2, i32 %count, i32* %coeff) { +entry: + %ptr = getelementptr inbounds i32* %ptr2, i64 1 + br label %while.body + +while.body: + %num = phi i32 [ %count, %entry ], [ %dec, %while.body ] + %ptr_phi = phi i32* [ %ptr, %entry ], [ %ptr_inc, %while.body ] + %ptr2_phi = phi i32* [ %ptr2, %entry ], [ %ptr2_inc, %while.body ] + %result.09 = phi i32 [ 0 , %entry ], [ %add, %while.body ] + %dec = add nsw i32 %num, -1 + %0 = load i32* %ptr_phi, align 4 + store i32 %0, i32* %ptr2_phi, align 4 + %1 = load i32* %coeff, align 4 + %2 = load i32* %ptr_phi, align 4 + %mul = mul nsw i32 %1, %2 + %add = add nsw i32 %mul, %result.09 + %tobool = icmp eq i32 %dec, 0 + %ptr_inc = getelementptr inbounds i32* %ptr_phi, i64 1 + %ptr2_inc = getelementptr inbounds i32* %ptr2_phi, i64 1 + br i1 %tobool, label %the_exit, label %while.body + +the_exit: + ret i32 %add +} diff --git a/test/Analysis/BasicAA/pure-const-dce.ll b/test/Analysis/BasicAA/pure-const-dce.ll new file mode 100644 index 00000000000..266e607b21a --- /dev/null +++ b/test/Analysis/BasicAA/pure-const-dce.ll @@ -0,0 +1,51 @@ +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s + +@g = global i32 0 + +; CHECK: @test +; CHECK: entry +; CHECK: %tmp0 = call i32 @TestConst(i32 5) readnone +; CHECK-NEXT: %tmp1 = call i32 @TestPure(i32 6) readonly +; CHECK-NEXT: %tmp2 = call i32 @TestNone(i32 7) +; CHECK-NEXT: store i32 1, i32* @g +; CHECK-NEXT: %tmp5 = call i32 @TestPure(i32 6) readonly +; CHECK-NEXT: %tmp7 = call i32 @TestNone(i32 7) +; CHECK-NEXT: %tmp8 = call i32 @TestNone(i32 7) +; CHECK-NEXT: %sum0 = add i32 %tmp0, %tmp1 +; CHECK-NEXT: %sum1 = add i32 %sum0, %tmp2 +; CHECK-NEXT: %sum2 = add i32 %sum1, %tmp0 +; CHECK-NEXT: %sum3 = add i32 %sum2, %tmp0 +; CHECK-NEXT: %sum4 = add i32 %sum3, %tmp5 +; CHECK-NEXT: %sum5 = add i32 %sum4, %tmp5 +; CHECK-NEXT: %sum6 = add i32 %sum5, %tmp7 +; CHECK-NEXT: %sum7 = add i32 %sum6, %tmp8 +; CHECK-NEXT: ret i32 %sum7 + +define i32 @test() { +entry: + %tmp0 = call i32 @TestConst( i32 5 ) readnone ; <i32> [#uses=1] + %tmp1 = call i32 @TestPure( i32 6 ) readonly ; <i32> [#uses=1] + %tmp2 = call i32 @TestNone( i32 7 ) ; <i32> [#uses=1] + store i32 1, i32* @g + %tmp3 = call i32 @TestConst( i32 5 ) readnone ; <i32> [#uses=1] + %tmp4 = call i32 @TestConst( i32 5 ) readnone ; <i32> [#uses=1] + %tmp5 = call i32 @TestPure( i32 6 ) readonly ; <i32> [#uses=1] + %tmp6 = call i32 @TestPure( i32 6 ) readonly ; <i32> [#uses=1] + %tmp7 = call i32 @TestNone( i32 7 ) ; <i32> [#uses=1] + %tmp8 = call i32 @TestNone( i32 7 ) ; <i32> [#uses=1] + %sum0 = add i32 %tmp0, %tmp1 ; <i32> [#uses=1] + %sum1 = add i32 %sum0, %tmp2 ; <i32> [#uses=1] + %sum2 = add i32 %sum1, %tmp3 ; <i32> [#uses=1] + %sum3 = add i32 %sum2, %tmp4 ; <i32> [#uses=1] + %sum4 = add i32 %sum3, %tmp5 ; <i32> [#uses=1] + %sum5 = add i32 %sum4, %tmp6 ; <i32> [#uses=1] + %sum6 = add i32 %sum5, %tmp7 ; <i32> [#uses=1] + %sum7 = add i32 %sum6, %tmp8 ; <i32> [#uses=1] + ret i32 %sum7 +} + +declare i32 @TestConst(i32) readnone + +declare i32 @TestPure(i32) readonly + +declare i32 @TestNone(i32) diff --git a/test/Analysis/BasicAA/store-promote.ll b/test/Analysis/BasicAA/store-promote.ll new file mode 100644 index 00000000000..0db805c3e21 --- /dev/null +++ b/test/Analysis/BasicAA/store-promote.ll @@ -0,0 +1,54 @@ +; Test that LICM uses basicaa to do alias analysis, which is capable of +; disambiguating some obvious cases. If LICM is able to disambiguate the +; two pointers, then the load should be hoisted, and the store sunk. + +; RUN: opt < %s -basicaa -licm -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@A = global i32 7 ; <i32*> [#uses=3] +@B = global i32 8 ; <i32*> [#uses=2] +@C = global [2 x i32] [ i32 4, i32 8 ] ; <[2 x i32]*> [#uses=2] + +define i32 @test1(i1 %c) { + %Atmp = load i32* @A ; <i32> [#uses=2] + br label %Loop + +Loop: ; preds = %Loop, %0 + %ToRemove = load i32* @A ; <i32> [#uses=1] + store i32 %Atmp, i32* @B + br i1 %c, label %Out, label %Loop + +Out: ; preds = %Loop + %X = sub i32 %ToRemove, %Atmp ; <i32> [#uses=1] + ret i32 %X + +; The Loop block should be empty after the load/store are promoted. +; CHECK: @test1 +; CHECK: load i32* @A +; CHECK: Loop: +; CHECK-NEXT: br i1 %c, label %Out, label %Loop +; CHECK: Out: +; CHECK: store i32 %Atmp, i32* @B +} + +define i32 @test2(i1 %c) { + br label %Loop + +Loop: ; preds = %Loop, %0 + %AVal = load i32* @A ; <i32> [#uses=2] + %C0 = getelementptr [2 x i32]* @C, i64 0, i64 0 ; <i32*> [#uses=1] + store i32 %AVal, i32* %C0 + %BVal = load i32* @B ; <i32> [#uses=2] + %C1 = getelementptr [2 x i32]* @C, i64 0, i64 1 ; <i32*> [#uses=1] + store i32 %BVal, i32* %C1 + br i1 %c, label %Out, label %Loop + +Out: ; preds = %Loop + %X = sub i32 %AVal, %BVal ; <i32> [#uses=1] + ret i32 %X +; The Loop block should be empty after the load/store are promoted. +; CHECK: @test2 +; CHECK: Loop: +; CHECK-NEXT: br i1 %c, label %Out, label %Loop +} + diff --git a/test/Analysis/BasicAA/tailcall-modref.ll b/test/Analysis/BasicAA/tailcall-modref.ll new file mode 100644 index 00000000000..ebeb28c1131 --- /dev/null +++ b/test/Analysis/BasicAA/tailcall-modref.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +define i32 @test() { +; CHECK: ret i32 0 + %A = alloca i32 ; <i32*> [#uses=3] + call void @foo( i32* %A ) + %X = load i32* %A ; <i32> [#uses=1] + tail call void @bar( ) + %Y = load i32* %A ; <i32> [#uses=1] + %Z = sub i32 %X, %Y ; <i32> [#uses=1] + ret i32 %Z +} + +declare void @foo(i32*) + +declare void @bar() diff --git a/test/Analysis/BasicAA/underlying-value.ll b/test/Analysis/BasicAA/underlying-value.ll new file mode 100644 index 00000000000..0671c825068 --- /dev/null +++ b/test/Analysis/BasicAA/underlying-value.ll @@ -0,0 +1,25 @@ +; RUN: opt -basicaa -licm -S < %s +; PR9931 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + +define void @func_20() nounwind { +entry: + br label %for.cond + +for.cond: ; preds = %for.cond2, %entry + br i1 undef, label %for.cond2, label %for.end22 + +for.cond2: ; preds = %for.body5, %for.cond + br i1 false, label %for.body5, label %for.cond + +for.body5: ; preds = %for.cond2 + %arrayidx = getelementptr inbounds [2 x i64]* undef, i32 0, i64 0 + %tmp7 = load i64* %arrayidx, align 8 + %arrayidx9 = getelementptr inbounds [2 x i64]* undef, i32 0, i64 undef + %tmp10 = load i64* %arrayidx9, align 8 + br label %for.cond2 + +for.end22: ; preds = %for.cond + ret void +} diff --git a/test/Analysis/BasicAA/unreachable-block.ll b/test/Analysis/BasicAA/unreachable-block.ll new file mode 100644 index 00000000000..1ca1e66f894 --- /dev/null +++ b/test/Analysis/BasicAA/unreachable-block.ll @@ -0,0 +1,16 @@ +; RUN: opt -basicaa -aa-eval -disable-output < %s >& /dev/null + +; BasicAA shouldn't infinitely recurse on the use-def cycles in +; unreachable code. + +define void @func_2() nounwind { +entry: + unreachable + +bb: + %t = select i1 undef, i32* %t, i32* undef + %p = select i1 undef, i32* %p, i32* %p + %q = select i1 undef, i32* undef, i32* %p + %a = getelementptr i8* %a, i32 0 + unreachable +} diff --git a/test/Analysis/BlockFrequencyInfo/basic.ll b/test/Analysis/BlockFrequencyInfo/basic.ll new file mode 100644 index 00000000000..540d06b1f56 --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/basic.ll @@ -0,0 +1,92 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +define i32 @test1(i32 %i, i32* %a) { +; CHECK: Printing analysis {{.*}} for function 'test1' +; CHECK: entry = 1024 +entry: + br label %body + +; Loop backedges are weighted and thus their bodies have a greater frequency. +; CHECK: body = 31744 +body: + %iv = phi i32 [ 0, %entry ], [ %next, %body ] + %base = phi i32 [ 0, %entry ], [ %sum, %body ] + %arrayidx = getelementptr inbounds i32* %a, i32 %iv + %0 = load i32* %arrayidx + %sum = add nsw i32 %0, %base + %next = add i32 %iv, 1 + %exitcond = icmp eq i32 %next, %i + br i1 %exitcond, label %exit, label %body + +; CHECK: exit = 1024 +exit: + ret i32 %sum +} + +define i32 @test2(i32 %i, i32 %a, i32 %b) { +; CHECK: Printing analysis {{.*}} for function 'test2' +; CHECK: entry = 1024 +entry: + %cond = icmp ult i32 %i, 42 + br i1 %cond, label %then, label %else, !prof !0 + +; The 'then' branch is predicted more likely via branch weight metadata. +; CHECK: then = 963 +then: + br label %exit + +; CHECK: else = 60 +else: + br label %exit + +; FIXME: It may be a bug that we don't sum back to 1024. +; CHECK: exit = 1023 +exit: + %result = phi i32 [ %a, %then ], [ %b, %else ] + ret i32 %result +} + +!0 = metadata !{metadata !"branch_weights", i32 64, i32 4} + +define i32 @test3(i32 %i, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { +; CHECK: Printing analysis {{.*}} for function 'test3' +; CHECK: entry = 1024 +entry: + switch i32 %i, label %case_a [ i32 1, label %case_b + i32 2, label %case_c + i32 3, label %case_d + i32 4, label %case_e ], !prof !1 + +; CHECK: case_a = 51 +case_a: + br label %exit + +; CHECK: case_b = 51 +case_b: + br label %exit + +; The 'case_c' branch is predicted more likely via branch weight metadata. +; CHECK: case_c = 819 +case_c: + br label %exit + +; CHECK: case_d = 51 +case_d: + br label %exit + +; CHECK: case_e = 51 +case_e: + br label %exit + +; FIXME: It may be a bug that we don't sum back to 1024. +; CHECK: exit = 1023 +exit: + %result = phi i32 [ %a, %case_a ], + [ %b, %case_b ], + [ %c, %case_c ], + [ %d, %case_d ], + [ %e, %case_e ] + ret i32 %result +} + +!1 = metadata !{metadata !"branch_weights", i32 4, i32 4, i32 64, i32 4, i32 4} diff --git a/test/Analysis/BlockFrequencyInfo/lit.local.cfg b/test/Analysis/BlockFrequencyInfo/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/BranchProbabilityInfo/basic.ll b/test/Analysis/BranchProbabilityInfo/basic.ll new file mode 100644 index 00000000000..08adfa8a36f --- /dev/null +++ b/test/Analysis/BranchProbabilityInfo/basic.ll @@ -0,0 +1,117 @@ +; RUN: opt < %s -analyze -branch-prob | FileCheck %s + +define i32 @test1(i32 %i, i32* %a) { +; CHECK: Printing analysis {{.*}} for function 'test1' +entry: + br label %body +; CHECK: edge entry -> body probability is 16 / 16 = 100% + +body: + %iv = phi i32 [ 0, %entry ], [ %next, %body ] + %base = phi i32 [ 0, %entry ], [ %sum, %body ] + %arrayidx = getelementptr inbounds i32* %a, i32 %iv + %0 = load i32* %arrayidx + %sum = add nsw i32 %0, %base + %next = add i32 %iv, 1 + %exitcond = icmp eq i32 %next, %i + br i1 %exitcond, label %exit, label %body +; CHECK: edge body -> exit probability is 4 / 128 +; CHECK: edge body -> body probability is 124 / 128 + +exit: + ret i32 %sum +} + +define i32 @test2(i32 %i, i32 %a, i32 %b) { +; CHECK: Printing analysis {{.*}} for function 'test2' +entry: + %cond = icmp ult i32 %i, 42 + br i1 %cond, label %then, label %else, !prof !0 +; CHECK: edge entry -> then probability is 64 / 68 +; CHECK: edge entry -> else probability is 4 / 68 + +then: + br label %exit +; CHECK: edge then -> exit probability is 16 / 16 = 100% + +else: + br label %exit +; CHECK: edge else -> exit probability is 16 / 16 = 100% + +exit: + %result = phi i32 [ %a, %then ], [ %b, %else ] + ret i32 %result +} + +!0 = metadata !{metadata !"branch_weights", i32 64, i32 4} + +define i32 @test3(i32 %i, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { +; CHECK: Printing analysis {{.*}} for function 'test3' +entry: + switch i32 %i, label %case_a [ i32 1, label %case_b + i32 2, label %case_c + i32 3, label %case_d + i32 4, label %case_e ], !prof !1 +; CHECK: edge entry -> case_a probability is 4 / 80 +; CHECK: edge entry -> case_b probability is 4 / 80 +; CHECK: edge entry -> case_c probability is 64 / 80 +; CHECK: edge entry -> case_d probability is 4 / 80 +; CHECK: edge entry -> case_e probability is 4 / 80 + +case_a: + br label %exit +; CHECK: edge case_a -> exit probability is 16 / 16 = 100% + +case_b: + br label %exit +; CHECK: edge case_b -> exit probability is 16 / 16 = 100% + +case_c: + br label %exit +; CHECK: edge case_c -> exit probability is 16 / 16 = 100% + +case_d: + br label %exit +; CHECK: edge case_d -> exit probability is 16 / 16 = 100% + +case_e: + br label %exit +; CHECK: edge case_e -> exit probability is 16 / 16 = 100% + +exit: + %result = phi i32 [ %a, %case_a ], + [ %b, %case_b ], + [ %c, %case_c ], + [ %d, %case_d ], + [ %e, %case_e ] + ret i32 %result +} + +!1 = metadata !{metadata !"branch_weights", i32 4, i32 4, i32 64, i32 4, i32 4} + +define i32 @test4(i32 %x) nounwind uwtable readnone ssp { +; CHECK: Printing analysis {{.*}} for function 'test4' +entry: + %conv = sext i32 %x to i64 + switch i64 %conv, label %return [ + i64 0, label %sw.bb + i64 1, label %sw.bb + i64 2, label %sw.bb + i64 5, label %sw.bb1 + ], !prof !2 +; CHECK: edge entry -> return probability is 7 / 85 +; CHECK: edge entry -> sw.bb probability is 14 / 85 +; CHECK: edge entry -> sw.bb1 probability is 64 / 85 + +sw.bb: + br label %return + +sw.bb1: + br label %return + +return: + %retval.0 = phi i32 [ 5, %sw.bb1 ], [ 1, %sw.bb ], [ 0, %entry ] + ret i32 %retval.0 +} + +!2 = metadata !{metadata !"branch_weights", i32 7, i32 6, i32 4, i32 4, i32 64} diff --git a/test/Analysis/BranchProbabilityInfo/lit.local.cfg b/test/Analysis/BranchProbabilityInfo/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/BranchProbabilityInfo/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/BranchProbabilityInfo/loop.ll b/test/Analysis/BranchProbabilityInfo/loop.ll new file mode 100644 index 00000000000..b648cbb16a6 --- /dev/null +++ b/test/Analysis/BranchProbabilityInfo/loop.ll @@ -0,0 +1,365 @@ +; Test the static branch probability heuristics for no-return functions. +; RUN: opt < %s -analyze -branch-prob | FileCheck %s + +declare void @g1() +declare void @g2() +declare void @g3() +declare void @g4() + +define void @test1(i32 %a, i32 %b) { +entry: + br label %do.body +; CHECK: edge entry -> do.body probability is 16 / 16 = 100% + +do.body: + %i.0 = phi i32 [ 0, %entry ], [ %inc3, %do.end ] + call void @g1() + br label %do.body1 +; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% + +do.body1: + %j.0 = phi i32 [ 0, %do.body ], [ %inc, %do.body1 ] + call void @g2() + %inc = add nsw i32 %j.0, 1 + %cmp = icmp slt i32 %inc, %b + br i1 %cmp, label %do.body1, label %do.end +; CHECK: edge do.body1 -> do.body1 probability is 124 / 128 +; CHECK: edge do.body1 -> do.end probability is 4 / 128 + +do.end: + call void @g3() + %inc3 = add nsw i32 %i.0, 1 + %cmp4 = icmp slt i32 %inc3, %a + br i1 %cmp4, label %do.body, label %do.end5 +; CHECK: edge do.end -> do.body probability is 124 / 128 +; CHECK: edge do.end -> do.end5 probability is 4 / 128 + +do.end5: + call void @g4() + ret void +} + +define void @test2(i32 %a, i32 %b) { +entry: + %cmp9 = icmp sgt i32 %a, 0 + br i1 %cmp9, label %for.body.lr.ph, label %for.end6 +; CHECK: edge entry -> for.body.lr.ph probability is 20 / 32 +; CHECK: edge entry -> for.end6 probability is 12 / 32 + +for.body.lr.ph: + %cmp27 = icmp sgt i32 %b, 0 + br label %for.body +; CHECK: edge for.body.lr.ph -> for.body probability is 16 / 16 = 100% + +for.body: + %i.010 = phi i32 [ 0, %for.body.lr.ph ], [ %inc5, %for.end ] + call void @g1() + br i1 %cmp27, label %for.body3, label %for.end +; CHECK: edge for.body -> for.body3 probability is 62 / 124 = 50% +; CHECK: edge for.body -> for.end probability is 62 / 124 = 50% + +for.body3: + %j.08 = phi i32 [ %inc, %for.body3 ], [ 0, %for.body ] + call void @g2() + %inc = add nsw i32 %j.08, 1 + %exitcond = icmp eq i32 %inc, %b + br i1 %exitcond, label %for.end, label %for.body3 +; CHECK: edge for.body3 -> for.end probability is 4 / 128 +; CHECK: edge for.body3 -> for.body3 probability is 124 / 128 + +for.end: + call void @g3() + %inc5 = add nsw i32 %i.010, 1 + %exitcond11 = icmp eq i32 %inc5, %a + br i1 %exitcond11, label %for.end6, label %for.body +; CHECK: edge for.end -> for.end6 probability is 4 / 128 +; CHECK: edge for.end -> for.body probability is 124 / 128 + +for.end6: + call void @g4() + ret void +} + +define void @test3(i32 %a, i32 %b, i32* %c) { +entry: + br label %do.body +; CHECK: edge entry -> do.body probability is 16 / 16 = 100% + +do.body: + %i.0 = phi i32 [ 0, %entry ], [ %inc4, %if.end ] + call void @g1() + %0 = load i32* %c, align 4 + %cmp = icmp slt i32 %0, 42 + br i1 %cmp, label %do.body1, label %if.end +; CHECK: edge do.body -> do.body1 probability is 62 / 124 = 50% +; CHECK: edge do.body -> if.end probability is 62 / 124 = 50% + +do.body1: + %j.0 = phi i32 [ %inc, %do.body1 ], [ 0, %do.body ] + call void @g2() + %inc = add nsw i32 %j.0, 1 + %cmp2 = icmp slt i32 %inc, %b + br i1 %cmp2, label %do.body1, label %if.end +; CHECK: edge do.body1 -> do.body1 probability is 124 / 128 +; CHECK: edge do.body1 -> if.end probability is 4 / 128 + +if.end: + call void @g3() + %inc4 = add nsw i32 %i.0, 1 + %cmp5 = icmp slt i32 %inc4, %a + br i1 %cmp5, label %do.body, label %do.end6 +; CHECK: edge if.end -> do.body probability is 124 / 128 +; CHECK: edge if.end -> do.end6 probability is 4 / 128 + +do.end6: + call void @g4() + ret void +} + +define void @test4(i32 %a, i32 %b, i32* %c) { +entry: + br label %do.body +; CHECK: edge entry -> do.body probability is 16 / 16 = 100% + +do.body: + %i.0 = phi i32 [ 0, %entry ], [ %inc4, %do.end ] + call void @g1() + %0 = load i32* %c, align 4 + %cmp = icmp slt i32 %0, 42 + br i1 %cmp, label %return, label %do.body1 +; CHECK: edge do.body -> return probability is 4 / 128 +; CHECK: edge do.body -> do.body1 probability is 124 / 128 + +do.body1: + %j.0 = phi i32 [ %inc, %do.body1 ], [ 0, %do.body ] + call void @g2() + %inc = add nsw i32 %j.0, 1 + %cmp2 = icmp slt i32 %inc, %b + br i1 %cmp2, label %do.body1, label %do.end +; CHECK: edge do.body1 -> do.body1 probability is 124 / 128 +; CHECK: edge do.body1 -> do.end probability is 4 / 128 + +do.end: + call void @g3() + %inc4 = add nsw i32 %i.0, 1 + %cmp5 = icmp slt i32 %inc4, %a + br i1 %cmp5, label %do.body, label %do.end6 +; CHECK: edge do.end -> do.body probability is 124 / 128 +; CHECK: edge do.end -> do.end6 probability is 4 / 128 + +do.end6: + call void @g4() + br label %return +; CHECK: edge do.end6 -> return probability is 16 / 16 = 100% + +return: + ret void +} + +define void @test5(i32 %a, i32 %b, i32* %c) { +entry: + br label %do.body +; CHECK: edge entry -> do.body probability is 16 / 16 = 100% + +do.body: + %i.0 = phi i32 [ 0, %entry ], [ %inc4, %do.end ] + call void @g1() + br label %do.body1 +; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% + +do.body1: + %j.0 = phi i32 [ 0, %do.body ], [ %inc, %if.end ] + %0 = load i32* %c, align 4 + %cmp = icmp slt i32 %0, 42 + br i1 %cmp, label %return, label %if.end +; CHECK: edge do.body1 -> return probability is 4 / 128 +; CHECK: edge do.body1 -> if.end probability is 124 / 128 + +if.end: + call void @g2() + %inc = add nsw i32 %j.0, 1 + %cmp2 = icmp slt i32 %inc, %b + br i1 %cmp2, label %do.body1, label %do.end +; CHECK: edge if.end -> do.body1 probability is 124 / 128 +; CHECK: edge if.end -> do.end probability is 4 / 128 + +do.end: + call void @g3() + %inc4 = add nsw i32 %i.0, 1 + %cmp5 = icmp slt i32 %inc4, %a + br i1 %cmp5, label %do.body, label %do.end6 +; CHECK: edge do.end -> do.body probability is 124 / 128 +; CHECK: edge do.end -> do.end6 probability is 4 / 128 + +do.end6: + call void @g4() + br label %return +; CHECK: edge do.end6 -> return probability is 16 / 16 = 100% + +return: + ret void +} + +define void @test6(i32 %a, i32 %b, i32* %c) { +entry: + br label %do.body +; CHECK: edge entry -> do.body probability is 16 / 16 = 100% + +do.body: + %i.0 = phi i32 [ 0, %entry ], [ %inc4, %do.end ] + call void @g1() + br label %do.body1 +; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% + +do.body1: + %j.0 = phi i32 [ 0, %do.body ], [ %inc, %do.cond ] + call void @g2() + %0 = load i32* %c, align 4 + %cmp = icmp slt i32 %0, 42 + br i1 %cmp, label %return, label %do.cond +; CHECK: edge do.body1 -> return probability is 4 / 128 +; CHECK: edge do.body1 -> do.cond probability is 124 / 128 + +do.cond: + %inc = add nsw i32 %j.0, 1 + %cmp2 = icmp slt i32 %inc, %b + br i1 %cmp2, label %do.body1, label %do.end +; CHECK: edge do.cond -> do.body1 probability is 124 / 128 +; CHECK: edge do.cond -> do.end probability is 4 / 128 + +do.end: + call void @g3() + %inc4 = add nsw i32 %i.0, 1 + %cmp5 = icmp slt i32 %inc4, %a + br i1 %cmp5, label %do.body, label %do.end6 +; CHECK: edge do.end -> do.body probability is 124 / 128 +; CHECK: edge do.end -> do.end6 probability is 4 / 128 + +do.end6: + call void @g4() + br label %return +; CHECK: edge do.end6 -> return probability is 16 / 16 = 100% + +return: + ret void +} + +define void @test7(i32 %a, i32 %b, i32* %c) { +entry: + %cmp10 = icmp sgt i32 %a, 0 + br i1 %cmp10, label %for.body.lr.ph, label %for.end7 +; CHECK: edge entry -> for.body.lr.ph probability is 20 / 32 +; CHECK: edge entry -> for.end7 probability is 12 / 32 + +for.body.lr.ph: + %cmp38 = icmp sgt i32 %b, 0 + br label %for.body +; CHECK: edge for.body.lr.ph -> for.body probability is 16 / 16 = 100% + +for.body: + %i.011 = phi i32 [ 0, %for.body.lr.ph ], [ %inc6, %for.inc5 ] + %0 = load i32* %c, align 4 + %cmp1 = icmp eq i32 %0, %i.011 + br i1 %cmp1, label %for.inc5, label %if.end +; CHECK: edge for.body -> for.inc5 probability is 62 / 124 = 50% +; CHECK: edge for.body -> if.end probability is 62 / 124 = 50% + +if.end: + call void @g1() + br i1 %cmp38, label %for.body4, label %for.end +; CHECK: edge if.end -> for.body4 probability is 62 / 124 = 50% +; CHECK: edge if.end -> for.end probability is 62 / 124 = 50% + +for.body4: + %j.09 = phi i32 [ %inc, %for.body4 ], [ 0, %if.end ] + call void @g2() + %inc = add nsw i32 %j.09, 1 + %exitcond = icmp eq i32 %inc, %b + br i1 %exitcond, label %for.end, label %for.body4 +; CHECK: edge for.body4 -> for.end probability is 4 / 128 +; CHECK: edge for.body4 -> for.body4 probability is 124 / 128 + +for.end: + call void @g3() + br label %for.inc5 +; CHECK: edge for.end -> for.inc5 probability is 124 / 124 = 100% + +for.inc5: + %inc6 = add nsw i32 %i.011, 1 + %exitcond12 = icmp eq i32 %inc6, %a + br i1 %exitcond12, label %for.end7, label %for.body +; CHECK: edge for.inc5 -> for.end7 probability is 4 / 128 +; CHECK: edge for.inc5 -> for.body probability is 124 / 128 + +for.end7: + call void @g4() + ret void +} + +define void @test8(i32 %a, i32 %b, i32* %c) { +entry: + %cmp18 = icmp sgt i32 %a, 0 + br i1 %cmp18, label %for.body.lr.ph, label %for.end15 +; CHECK: edge entry -> for.body.lr.ph probability is 20 / 32 +; CHECK: edge entry -> for.end15 probability is 12 / 32 + +for.body.lr.ph: + %cmp216 = icmp sgt i32 %b, 0 + %arrayidx5 = getelementptr inbounds i32* %c, i64 1 + %arrayidx9 = getelementptr inbounds i32* %c, i64 2 + br label %for.body +; CHECK: edge for.body.lr.ph -> for.body probability is 16 / 16 = 100% + +for.body: + %i.019 = phi i32 [ 0, %for.body.lr.ph ], [ %inc14, %for.end ] + call void @g1() + br i1 %cmp216, label %for.body3, label %for.end +; CHECK: edge for.body -> for.body3 probability is 62 / 124 = 50% +; CHECK: edge for.body -> for.end probability is 62 / 124 = 50% + +for.body3: + %j.017 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ] + %0 = load i32* %c, align 4 + %cmp4 = icmp eq i32 %0, %j.017 + br i1 %cmp4, label %for.inc, label %if.end +; CHECK: edge for.body3 -> for.inc probability is 62 / 124 = 50% +; CHECK: edge for.body3 -> if.end probability is 62 / 124 = 50% + +if.end: + %1 = load i32* %arrayidx5, align 4 + %cmp6 = icmp eq i32 %1, %j.017 + br i1 %cmp6, label %for.inc, label %if.end8 +; CHECK: edge if.end -> for.inc probability is 62 / 124 = 50% +; CHECK: edge if.end -> if.end8 probability is 62 / 124 = 50% + +if.end8: + %2 = load i32* %arrayidx9, align 4 + %cmp10 = icmp eq i32 %2, %j.017 + br i1 %cmp10, label %for.inc, label %if.end12 +; CHECK: edge if.end8 -> for.inc probability is 62 / 124 = 50% +; CHECK: edge if.end8 -> if.end12 probability is 62 / 124 = 50% + +if.end12: + call void @g2() + br label %for.inc +; CHECK: edge if.end12 -> for.inc probability is 124 / 124 = 100% + +for.inc: + %inc = add nsw i32 %j.017, 1 + %exitcond = icmp eq i32 %inc, %b + br i1 %exitcond, label %for.end, label %for.body3 +; CHECK: edge for.inc -> for.end probability is 4 / 128 +; CHECK: edge for.inc -> for.body3 probability is 124 / 128 + +for.end: + call void @g3() + %inc14 = add nsw i32 %i.019, 1 + %exitcond20 = icmp eq i32 %inc14, %a + br i1 %exitcond20, label %for.end15, label %for.body +; CHECK: edge for.end -> for.end15 probability is 4 / 128 +; CHECK: edge for.end -> for.body probability is 124 / 128 + +for.end15: + call void @g4() + ret void +} diff --git a/test/Analysis/BranchProbabilityInfo/noreturn.ll b/test/Analysis/BranchProbabilityInfo/noreturn.ll new file mode 100644 index 00000000000..8b9ae11f7d3 --- /dev/null +++ b/test/Analysis/BranchProbabilityInfo/noreturn.ll @@ -0,0 +1,79 @@ +; Test the static branch probability heuristics for no-return functions. +; RUN: opt < %s -analyze -branch-prob | FileCheck %s + +declare void @abort() noreturn + +define i32 @test1(i32 %a, i32 %b) { +; CHECK: Printing analysis {{.*}} for function 'test1' +entry: + %cond = icmp eq i32 %a, 42 + br i1 %cond, label %exit, label %abort +; CHECK: edge entry -> exit probability is 1048575 / 1048576 +; CHECK: edge entry -> abort probability is 1 / 1048576 + +abort: + call void @abort() noreturn + unreachable + +exit: + ret i32 %b +} + +define i32 @test2(i32 %a, i32 %b) { +; CHECK: Printing analysis {{.*}} for function 'test2' +entry: + switch i32 %a, label %exit [i32 1, label %case_a + i32 2, label %case_b + i32 3, label %case_c + i32 4, label %case_d] +; CHECK: edge entry -> exit probability is 1048575 / 1048579 +; CHECK: edge entry -> case_a probability is 1 / 1048579 +; CHECK: edge entry -> case_b probability is 1 / 1048579 +; CHECK: edge entry -> case_c probability is 1 / 1048579 +; CHECK: edge entry -> case_d probability is 1 / 1048579 + +case_a: + br label %case_b + +case_b: + br label %case_c + +case_c: + br label %case_d + +case_d: + call void @abort() noreturn + unreachable + +exit: + ret i32 %b +} + +define i32 @test3(i32 %a, i32 %b) { +; CHECK: Printing analysis {{.*}} for function 'test3' +; Make sure we unify across multiple conditional branches. +entry: + %cond1 = icmp eq i32 %a, 42 + br i1 %cond1, label %exit, label %dom +; CHECK: edge entry -> exit probability is 1048575 / 1048576 +; CHECK: edge entry -> dom probability is 1 / 1048576 + +dom: + %cond2 = icmp ult i32 %a, 42 + br i1 %cond2, label %idom1, label %idom2 +; CHECK: edge dom -> idom1 probability is 1 / 2 +; CHECK: edge dom -> idom2 probability is 1 / 2 + +idom1: + br label %abort + +idom2: + br label %abort + +abort: + call void @abort() noreturn + unreachable + +exit: + ret i32 %b +} diff --git a/test/Analysis/CallGraph/2008-09-09-DirectCall.ll b/test/Analysis/CallGraph/2008-09-09-DirectCall.ll new file mode 100644 index 00000000000..595cc427c45 --- /dev/null +++ b/test/Analysis/CallGraph/2008-09-09-DirectCall.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s + +; CHECK: Call graph node <<null function>> +; CHECK: CS<{{.*}}> calls function 'callee' +; CHECK: Call graph node for function: 'caller' +; CHECK: CS<{{.*}}> calls function 'callee' + +define internal void @callee(...) { +entry: + unreachable +} + +define void @caller() { +entry: + call void (...)* @callee( void (...)* @callee ) + unreachable +} diff --git a/test/Analysis/CallGraph/2008-09-09-UsedByGlobal.ll b/test/Analysis/CallGraph/2008-09-09-UsedByGlobal.ll new file mode 100644 index 00000000000..ac95188899c --- /dev/null +++ b/test/Analysis/CallGraph/2008-09-09-UsedByGlobal.ll @@ -0,0 +1,9 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s + +@a = global void ()* @f ; <void ()**> [#uses=0] + +; CHECK: calls function 'f' + +define internal void @f() { + unreachable +} diff --git a/test/Analysis/CallGraph/lit.local.cfg b/test/Analysis/CallGraph/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/CallGraph/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/CallGraph/no-intrinsics.ll b/test/Analysis/CallGraph/no-intrinsics.ll new file mode 100644 index 00000000000..450dce58e30 --- /dev/null +++ b/test/Analysis/CallGraph/no-intrinsics.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s + +; Check that intrinsics aren't added to the call graph + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) + +define void @f(i8* %out, i8* %in) { + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %out, i8* %in, i32 100, i32 4, i1 false) + ret void +} + +; CHECK: Call graph node for function: 'f' +; CHECK-NOT: calls function 'llvm.memcpy.p0i8.p0i8.i32'
\ No newline at end of file diff --git a/test/Analysis/Dominators/2006-10-02-BreakCritEdges.ll b/test/Analysis/Dominators/2006-10-02-BreakCritEdges.ll new file mode 100644 index 00000000000..45efc423811 --- /dev/null +++ b/test/Analysis/Dominators/2006-10-02-BreakCritEdges.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -domtree -break-crit-edges -analyze -domtree | FileCheck %s +; PR932 + +; CHECK: [3] %brtrue {1,2} + +declare void @use1(i32) + +define void @f(i32 %i, i1 %c) { +entry: + %A = icmp eq i32 %i, 0 ; <i1> [#uses=1] + br i1 %A, label %brtrue, label %brfalse + +brtrue: ; preds = %brtrue, %entry + %B = phi i1 [ true, %brtrue ], [ false, %entry ] ; <i1> [#uses=1] + call void @use1( i32 %i ) + br i1 %B, label %brtrue, label %brfalse + +brfalse: ; preds = %brtrue, %entry + call void @use1( i32 %i ) + ret void +} diff --git a/test/Analysis/Dominators/2007-01-14-BreakCritEdges.ll b/test/Analysis/Dominators/2007-01-14-BreakCritEdges.ll new file mode 100644 index 00000000000..96dc73929d1 --- /dev/null +++ b/test/Analysis/Dominators/2007-01-14-BreakCritEdges.ll @@ -0,0 +1,187 @@ +; RUN: opt < %s -domtree -break-crit-edges -domtree -disable-output +; PR1110 + + %struct.OggVorbis_File = type { i8*, i32, i64, i64, %struct.ogg_sync_state, i32, i64*, i64*, i32*, i64*, %struct.vorbis_info*, %struct.vorbis_comment*, i64, i32, i32, i32, double, double, %struct.ogg_stream_state, %struct.vorbis_dsp_state, %struct.vorbis_block, %struct.ov_callbacks } + %struct.alloc_chain = type { i8*, %struct.alloc_chain* } + %struct.ogg_stream_state = type { i8*, i32, i32, i32, i32*, i64*, i32, i32, i32, i32, [282 x i8], i32, i32, i32, i32, i32, i64, i64 } + %struct.ogg_sync_state = type { i8*, i32, i32, i32, i32, i32, i32 } + %struct.oggpack_buffer = type { i32, i32, i8*, i8*, i32 } + %struct.ov_callbacks = type { i32 (i8*, i32, i32, i8*)*, i32 (i8*, i64, i32)*, i32 (i8*)*, i32 (i8*)* } + %struct.vorbis_block = type { float**, %struct.oggpack_buffer, i32, i32, i32, i32, i32, i32, i64, i64, %struct.vorbis_dsp_state*, i8*, i32, i32, i32, %struct.alloc_chain*, i32, i32, i32, i32, i8* } + %struct.vorbis_comment = type { i8**, i32*, i32, i8* } + %struct.vorbis_dsp_state = type { i32, %struct.vorbis_info*, float**, float**, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i64, i64, i64, i64, i64, i8* } + %struct.vorbis_info = type { i32, i32, i32, i32, i32, i32, i32, i8* } + + +define void @ov_read() { +entry: + br i1 false, label %bb, label %return + +bb: ; preds = %cond_next22, %entry + br i1 false, label %cond_true8, label %cond_next15 + +cond_true8: ; preds = %bb + br i1 false, label %cond_next15, label %bb29 + +cond_next15: ; preds = %cond_true8, %bb + br i1 false, label %return, label %cond_next22 + +cond_next22: ; preds = %cond_next15 + br i1 false, label %bb, label %return + +bb29: ; preds = %cond_true8 + br i1 false, label %cond_true32, label %return + +cond_true32: ; preds = %bb29 + br i1 false, label %cond_false37.i, label %cond_true.i11 + +cond_true.i11: ; preds = %cond_true32 + br i1 false, label %cond_true8.i, label %ov_info.exit + +cond_true8.i: ; preds = %cond_true.i11 + br i1 false, label %cond_true44, label %cond_next48 + +cond_false37.i: ; preds = %cond_true32 + br label %ov_info.exit + +ov_info.exit: ; preds = %cond_false37.i, %cond_true.i11 + br i1 false, label %cond_true44, label %cond_next48 + +cond_true44: ; preds = %ov_info.exit, %cond_true8.i + br label %cond_next48 + +cond_next48: ; preds = %cond_true44, %ov_info.exit, %cond_true8.i + br i1 false, label %cond_next53, label %return + +cond_next53: ; preds = %cond_next48 + br i1 false, label %cond_true56, label %cond_false97 + +cond_true56: ; preds = %cond_next53 + br i1 false, label %bb85, label %cond_next304 + +bb63: ; preds = %bb85 + br i1 false, label %cond_next78, label %cond_false73 + +cond_false73: ; preds = %bb63 + br i1 false, label %cond_true76, label %cond_next78 + +cond_true76: ; preds = %cond_false73 + br label %cond_next78 + +cond_next78: ; preds = %cond_true76, %cond_false73, %bb63 + br label %bb85 + +bb85: ; preds = %bb89, %cond_next78, %cond_true56 + br i1 false, label %bb63, label %bb89 + +bb89: ; preds = %bb85 + br i1 false, label %bb85, label %cond_next304 + +cond_false97: ; preds = %cond_next53 + br i1 false, label %cond_true108, label %bb248 + +cond_true108: ; preds = %cond_false97 + br i1 false, label %bb196, label %bb149 + +bb112: ; preds = %bb149, %bb146 + br i1 false, label %bb119, label %bb146 + +bb119: ; preds = %cond_next134, %bb112 + br i1 false, label %cond_next134, label %cond_false129 + +cond_false129: ; preds = %bb119 + br i1 false, label %cond_true132, label %cond_next134 + +cond_true132: ; preds = %cond_false129 + br label %cond_next134 + +cond_next134: ; preds = %cond_true132, %cond_false129, %bb119 + br i1 false, label %bb119, label %bb146 + +bb146: ; preds = %cond_next134, %bb112 + br i1 false, label %bb112, label %cond_next304 + +bb149: ; preds = %cond_true108 + br i1 false, label %bb112, label %cond_next304 + +bb155: ; preds = %bb196, %bb193 + br i1 false, label %bb165, label %bb193 + +bb165: ; preds = %cond_next180, %bb155 + br i1 false, label %cond_next180, label %cond_false175 + +cond_false175: ; preds = %bb165 + br i1 false, label %cond_true178, label %cond_next180 + +cond_true178: ; preds = %cond_false175 + br label %cond_next180 + +cond_next180: ; preds = %cond_true178, %cond_false175, %bb165 + br i1 false, label %bb165, label %bb193 + +bb193: ; preds = %cond_next180, %bb155 + br i1 false, label %bb155, label %cond_next304 + +bb196: ; preds = %cond_true108 + br i1 false, label %bb155, label %cond_next304 + +bb207: ; preds = %bb241 + br i1 false, label %cond_next225, label %cond_false220 + +cond_false220: ; preds = %bb207 + br i1 false, label %cond_true223, label %cond_next225 + +cond_true223: ; preds = %cond_false220 + br label %cond_next225 + +cond_next225: ; preds = %cond_true223, %cond_false220, %bb207 + br label %bb241 + +bb241: ; preds = %bb248, %bb245, %cond_next225 + br i1 false, label %bb207, label %bb245 + +bb245: ; preds = %bb241 + br i1 false, label %bb241, label %cond_next304 + +bb248: ; preds = %cond_false97 + br i1 false, label %bb241, label %cond_next304 + +bb256: ; preds = %bb290 + br i1 false, label %cond_next274, label %cond_false269 + +cond_false269: ; preds = %bb256 + br i1 false, label %cond_true272, label %cond_next274 + +cond_true272: ; preds = %cond_false269 + br label %cond_next274 + +cond_next274: ; preds = %cond_true272, %cond_false269, %bb256 + br label %bb290 + +bb290: ; preds = %bb294, %cond_next274 + br i1 false, label %bb256, label %bb294 + +bb294: ; preds = %bb290 + br i1 false, label %bb290, label %cond_next304 + +cond_next304: ; preds = %bb294, %bb248, %bb245, %bb196, %bb193, %bb149, %bb146, %bb89, %cond_true56 + br i1 false, label %cond_next11.i, label %cond_true.i + +cond_true.i: ; preds = %cond_next304 + br i1 false, label %vorbis_synthesis_read.exit, label %cond_next11.i + +cond_next11.i: ; preds = %cond_true.i, %cond_next304 + br label %vorbis_synthesis_read.exit + +vorbis_synthesis_read.exit: ; preds = %cond_next11.i, %cond_true.i + br i1 false, label %cond_next321, label %cond_true316 + +cond_true316: ; preds = %vorbis_synthesis_read.exit + ret void + +cond_next321: ; preds = %vorbis_synthesis_read.exit + ret void + +return: ; preds = %cond_next48, %bb29, %cond_next22, %cond_next15, %entry + ret void +} diff --git a/test/Analysis/Dominators/2007-07-11-SplitBlock.ll b/test/Analysis/Dominators/2007-07-11-SplitBlock.ll new file mode 100644 index 00000000000..52fdd2b16db --- /dev/null +++ b/test/Analysis/Dominators/2007-07-11-SplitBlock.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -loop-rotate -loop-unswitch -disable-output + +define i32 @stringSearch_Clib(i32 %count) { +entry: + br i1 false, label %bb36, label %bb44 + +cond_true20: ; preds = %bb36 + %tmp33 = add i32 0, 0 ; <i32> [#uses=1] + br label %bb36 + +bb36: ; preds = %cond_true20, %entry + %c.2 = phi i32 [ %tmp33, %cond_true20 ], [ 0, %entry ] ; <i32> [#uses=1] + br i1 false, label %cond_true20, label %bb41 + +bb41: ; preds = %bb36 + %c.2.lcssa = phi i32 [ %c.2, %bb36 ] ; <i32> [#uses=0] + ret i32 0 + +bb44: ; preds = %entry + ret i32 0 +} diff --git a/test/Analysis/Dominators/2007-07-12-SplitBlock.ll b/test/Analysis/Dominators/2007-07-12-SplitBlock.ll new file mode 100644 index 00000000000..b46f0c75e10 --- /dev/null +++ b/test/Analysis/Dominators/2007-07-12-SplitBlock.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -loop-rotate -licm -loop-unswitch -disable-output + +define i32 @main(i32 %argc, i8** %argv) { +entry: + br label %bb7 + +bb7: ; preds = %bb7, %entry + %tmp54 = icmp slt i32 0, 2000000 ; <i1> [#uses=1] + br i1 %tmp54, label %bb7, label %bb56 + +bb56: ; preds = %bb7 + ret i32 0 +} diff --git a/test/Analysis/Dominators/invoke.ll b/test/Analysis/Dominators/invoke.ll new file mode 100644 index 00000000000..f935750c987 --- /dev/null +++ b/test/Analysis/Dominators/invoke.ll @@ -0,0 +1,19 @@ +; RUN: opt -verify -disable-output %s +; This tests that we handle unreachable blocks correctly + +define void @f() { + %v1 = invoke i32* @g() + to label %bb1 unwind label %bb2 + invoke void @__dynamic_cast() + to label %bb1 unwind label %bb2 +bb1: + %Hidden = getelementptr inbounds i32* %v1, i64 1 + ret void +bb2: + %lpad.loopexit80 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + cleanup + ret void +} +declare i32 @__gxx_personality_v0(...) +declare void @__dynamic_cast() +declare i32* @g() diff --git a/test/Analysis/Dominators/lit.local.cfg b/test/Analysis/Dominators/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/Dominators/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/GlobalsModRef/2008-09-03-ReadGlobals.ll b/test/Analysis/GlobalsModRef/2008-09-03-ReadGlobals.ll new file mode 100644 index 00000000000..d51c159a911 --- /dev/null +++ b/test/Analysis/GlobalsModRef/2008-09-03-ReadGlobals.ll @@ -0,0 +1,20 @@ +; RUN: opt < %s -globalsmodref-aa -gvn -S | FileCheck %s + +@g = internal global i32 0 ; <i32*> [#uses=2] + +define i32 @r() { + %tmp = load i32* @g ; <i32> [#uses=1] + ret i32 %tmp +} + +define i32 @f() { +; CHECK: call i32 @e() +; CHECK: call i32 @e() +entry: + %tmp = call i32 @e( ) ; <i32> [#uses=1] + store i32 %tmp, i32* @g + %tmp2 = call i32 @e( ) ; <i32> [#uses=1] + ret i32 %tmp2 +} + +declare i32 @e() readonly ; might call @r diff --git a/test/Analysis/GlobalsModRef/aliastest.ll b/test/Analysis/GlobalsModRef/aliastest.ll new file mode 100644 index 00000000000..4cfed71bfb7 --- /dev/null +++ b/test/Analysis/GlobalsModRef/aliastest.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -basicaa -globalsmodref-aa -gvn -S | FileCheck %s + +@X = internal global i32 4 ; <i32*> [#uses=1] + +define i32 @test(i32* %P) { +; CHECK: @test +; CHECK-NEXT: store i32 7, i32* %P +; CHECK-NEXT: store i32 12, i32* @X +; CHECK-NEXT: ret i32 7 + store i32 7, i32* %P + store i32 12, i32* @X + %V = load i32* %P ; <i32> [#uses=1] + ret i32 %V +} diff --git a/test/Analysis/GlobalsModRef/chaining-analysis.ll b/test/Analysis/GlobalsModRef/chaining-analysis.ll new file mode 100644 index 00000000000..aeb76e42d29 --- /dev/null +++ b/test/Analysis/GlobalsModRef/chaining-analysis.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -basicaa -globalsmodref-aa -gvn -S | FileCheck %s + +; This test requires the use of previous analyses to determine that +; doesnotmodX does not modify X (because 'sin' doesn't). + +@X = internal global i32 4 ; <i32*> [#uses=2] + +declare double @sin(double) readnone + +define i32 @test(i32* %P) { +; CHECK: @test +; CHECK-NEXT: store i32 12, i32* @X +; CHECK-NEXT: call double @doesnotmodX(double 1.000000e+00) +; CHECK-NEXT: ret i32 12 + store i32 12, i32* @X + call double @doesnotmodX( double 1.000000e+00 ) ; <double>:1 [#uses=0] + %V = load i32* @X ; <i32> [#uses=1] + ret i32 %V +} + +define double @doesnotmodX(double %V) { + %V2 = call double @sin( double %V ) readnone ; <double> [#uses=1] + ret double %V2 +} diff --git a/test/Analysis/GlobalsModRef/indirect-global.ll b/test/Analysis/GlobalsModRef/indirect-global.ll new file mode 100644 index 00000000000..48ac6dd1d16 --- /dev/null +++ b/test/Analysis/GlobalsModRef/indirect-global.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -basicaa -globalsmodref-aa -gvn -instcombine -S | FileCheck %s + +@G = internal global i32* null ; <i32**> [#uses=3] + +declare i8* @malloc(i32) +define void @test() { + %a = call i8* @malloc(i32 4) + %A = bitcast i8* %a to i32* + store i32* %A, i32** @G + ret void +} + +define i32 @test1(i32* %P) { +; CHECK: ret i32 0 + %g1 = load i32** @G ; <i32*> [#uses=2] + %h1 = load i32* %g1 ; <i32> [#uses=1] + store i32 123, i32* %P + %g2 = load i32** @G ; <i32*> [#uses=0] + %h2 = load i32* %g1 ; <i32> [#uses=1] + %X = sub i32 %h1, %h2 ; <i32> [#uses=1] + ret i32 %X +} diff --git a/test/Analysis/GlobalsModRef/lit.local.cfg b/test/Analysis/GlobalsModRef/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/GlobalsModRef/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/GlobalsModRef/modreftest.ll b/test/Analysis/GlobalsModRef/modreftest.ll new file mode 100644 index 00000000000..3eed916e83b --- /dev/null +++ b/test/Analysis/GlobalsModRef/modreftest.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -basicaa -globalsmodref-aa -gvn -S | FileCheck %s + +@X = internal global i32 4 ; <i32*> [#uses=2] + +define i32 @test(i32* %P) { +; CHECK: @test +; CHECK-NEXT: store i32 12, i32* @X +; CHECK-NEXT: call void @doesnotmodX() +; CHECK-NEXT: ret i32 12 + store i32 12, i32* @X + call void @doesnotmodX( ) + %V = load i32* @X ; <i32> [#uses=1] + ret i32 %V +} + +define void @doesnotmodX() { + ret void +} diff --git a/test/Analysis/GlobalsModRef/pr12351.ll b/test/Analysis/GlobalsModRef/pr12351.ll new file mode 100644 index 00000000000..1c5ac43f8d2 --- /dev/null +++ b/test/Analysis/GlobalsModRef/pr12351.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -basicaa -globalsmodref-aa -gvn -S | FileCheck %s + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) +define void @foo(i8* %x, i8* %y) { + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x, i8* %y, i32 1, i32 1, i1 false); + ret void +} + +define void @bar(i8* %y, i8* %z) { + %x = alloca i8 + call void @foo(i8* %x, i8* %y) + %t = load i8* %x + store i8 %t, i8* %y +; CHECK: store i8 %t, i8* %y + ret void +} + + +define i32 @foo2() { + %foo = alloca i32 + call void @bar2(i32* %foo) + %t0 = load i32* %foo, align 4 +; CHECK: %t0 = load i32* %foo, align 4 + ret i32 %t0 +} + +define void @bar2(i32* %foo) { + store i32 0, i32* %foo, align 4 + tail call void @llvm.dbg.value(metadata !{}, i64 0, metadata !{}) + ret void +} + +declare void @llvm.dbg.value(metadata, i64, metadata) nounwind readnone diff --git a/test/Analysis/GlobalsModRef/purecse.ll b/test/Analysis/GlobalsModRef/purecse.ll new file mode 100644 index 00000000000..e030417f955 --- /dev/null +++ b/test/Analysis/GlobalsModRef/purecse.ll @@ -0,0 +1,27 @@ +; Test that pure functions are cse'd away +; RUN: opt < %s -globalsmodref-aa -gvn -instcombine -S | FileCheck %s + +define i32 @pure(i32 %X) { + %Y = add i32 %X, 1 ; <i32> [#uses=1] + ret i32 %Y +} + +define i32 @test1(i32 %X) { +; CHECK: %A = call i32 @pure(i32 %X) +; CHECK-NEXT: ret i32 0 + %A = call i32 @pure( i32 %X ) ; <i32> [#uses=1] + %B = call i32 @pure( i32 %X ) ; <i32> [#uses=1] + %C = sub i32 %A, %B ; <i32> [#uses=1] + ret i32 %C +} + +define i32 @test2(i32 %X, i32* %P) { +; CHECK: %A = call i32 @pure(i32 %X) +; CHECK-NEXT: store i32 %X, i32* %P +; CHECK-NEXT: ret i32 0 + %A = call i32 @pure( i32 %X ) ; <i32> [#uses=1] + store i32 %X, i32* %P ;; Does not invalidate 'pure' call. + %B = call i32 @pure( i32 %X ) ; <i32> [#uses=1] + %C = sub i32 %A, %B ; <i32> [#uses=1] + ret i32 %C +} diff --git a/test/Analysis/GlobalsModRef/volatile-instrs.ll b/test/Analysis/GlobalsModRef/volatile-instrs.ll new file mode 100644 index 00000000000..49bce670b7f --- /dev/null +++ b/test/Analysis/GlobalsModRef/volatile-instrs.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -basicaa -dse -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.8.0" + +%struct.anon = type { i32, i32, i32 } +@b = global %struct.anon { i32 1, i32 0, i32 0 }, align 4 +@c = common global i32 0, align 4 +@a = common global %struct.anon zeroinitializer, align 4 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +declare i32 @printf(i8* nocapture, ...) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + + +; Make sure that the initial memcpy call does not go away +; because the volatile load is in the way. PR12899 + +; CHECK: main_entry: +; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64 + +define i32 @main() nounwind uwtable ssp { +main_entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.anon* @b to i8*), i8* bitcast (%struct.anon* @a to i8*), i64 12, i32 4, i1 false) + %0 = load volatile i32* getelementptr inbounds (%struct.anon* @b, i64 0, i32 0), align 4, !tbaa !0 + store i32 %0, i32* @c, align 4, !tbaa !0 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.anon* @b to i8*), i8* bitcast (%struct.anon* @a to i8*), i64 12, i32 4, i1 false) nounwind + %call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %0) nounwind + ret i32 0 +} + +!0 = metadata !{metadata !"int", metadata !1} +!1 = metadata !{metadata !"omnipotent char", metadata !2} +!2 = metadata !{metadata !"Simple C/C++ TBAA"} diff --git a/test/Analysis/LoopDependenceAnalysis/alias.ll b/test/Analysis/LoopDependenceAnalysis/alias.ll new file mode 100644 index 00000000000..78d0bf4fee1 --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/alias.ll @@ -0,0 +1,44 @@ +; RUN: opt < %s -analyze -basicaa -lda | FileCheck %s + +;; x[5] = x[6] // with x being a pointer passed as argument + +define void @f1(i32* nocapture %xptr) nounwind { +entry: + %x.ld.addr = getelementptr i32* %xptr, i64 6 + %x.st.addr = getelementptr i32* %xptr, i64 5 + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x = load i32* %x.ld.addr + store i32 %x, i32* %x.st.addr +; CHECK: 0,1: dep + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; x[5] = x[6] // with x being an array on the stack + +define void @foo(...) nounwind { +entry: + %xptr = alloca [256 x i32], align 4 + %x.ld.addr = getelementptr [256 x i32]* %xptr, i64 0, i64 6 + %x.st.addr = getelementptr [256 x i32]* %xptr, i64 0, i64 5 + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x = load i32* %x.ld.addr + store i32 %x, i32* %x.st.addr +; CHECK: 0,1: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Analysis/LoopDependenceAnalysis/lit.local.cfg b/test/Analysis/LoopDependenceAnalysis/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/LoopDependenceAnalysis/siv-strong.ll b/test/Analysis/LoopDependenceAnalysis/siv-strong.ll new file mode 100644 index 00000000000..401e466d666 --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/siv-strong.ll @@ -0,0 +1,110 @@ +; RUN: opt < %s -analyze -basicaa -lda | FileCheck %s + +@x = common global [256 x i32] zeroinitializer, align 4 +@y = common global [256 x i32] zeroinitializer, align 4 + +;; for (i = 0; i < 256; i++) +;; x[i] = x[i] + y[i] + +define void @f1(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %y.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %x = load i32* %x.addr ; 0 + %y = load i32* %y.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; for (i = 0; i < 256; i++) +;; x[i+1] = x[i] + y[i] + +define void @f2(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %i.next = add i64 %i, 1 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.next + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; for (i = 0; i < 10; i++) +;; x[i+20] = x[i] + y[i] + +define void @f3(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %i.20 = add i64 %i, 20 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.20 + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 10 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; for (i = 0; i < 10; i++) +;; x[10*i+1] = x[10*i] + y[i] + +define void @f4(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %i.10 = mul i64 %i, 10 + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i.10 + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.10 + %i.10.1 = add i64 %i.10, 1 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.10.1 + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 10 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Analysis/LoopDependenceAnalysis/siv-weak-crossing.ll b/test/Analysis/LoopDependenceAnalysis/siv-weak-crossing.ll new file mode 100644 index 00000000000..9d0128c5fec --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/siv-weak-crossing.ll @@ -0,0 +1,118 @@ +; RUN: opt < %s -analyze -basicaa -lda | FileCheck %s + +@x = common global [256 x i32] zeroinitializer, align 4 +@y = common global [256 x i32] zeroinitializer, align 4 + +;; for (i = 0; i < 256; i++) +;; x[i] = x[255 - i] + y[i] + +define void @f1(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %i.255 = sub i64 255, %i + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.255 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; for (i = 0; i < 100; i++) +;; x[i] = x[255 - i] + y[i] + +define void @f2(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %i.255 = sub i64 255, %i + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.255 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; // the first iteration (i=0) leads to an out-of-bounds access of x. as the +;; // result of this access is undefined, _any_ dependence result is safe. +;; for (i = 0; i < 256; i++) +;; x[i] = x[256 - i] + y[i] + +define void @f3(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %i.256 = sub i64 0, %i + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x.ld.addr = getelementptr [256 x i32]* @x, i64 1, i64 %i.256 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; // slightly contrived but valid IR for the following loop, where all +;; // accesses in all iterations are within bounds. while this example's first +;; // (ZIV-)subscript is (0, 1), accesses are dependent. +;; for (i = 1; i < 256; i++) +;; x[i] = x[256 - i] + y[i] + +define void @f4(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %i.1 = add i64 1, %i + %i.256 = sub i64 -1, %i + %y.ld.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i.1 + %x.ld.addr = getelementptr [256 x i32]* @x, i64 1, i64 %i.256 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i.1 + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.ld.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.st.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Analysis/LoopDependenceAnalysis/siv-weak-zero.ll b/test/Analysis/LoopDependenceAnalysis/siv-weak-zero.ll new file mode 100644 index 00000000000..1c5ae4c490e --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/siv-weak-zero.ll @@ -0,0 +1,56 @@ +; RUN: opt < %s -analyze -basicaa -lda | FileCheck %s + +@x = common global [256 x i32] zeroinitializer, align 4 +@y = common global [256 x i32] zeroinitializer, align 4 + +;; for (i = 0; i < 256; i++) +;; x[i] = x[42] + y[i] + +define void @f1(...) nounwind { +entry: + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 42 + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %y.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; for (i = 0; i < 250; i++) +;; x[i] = x[255] + y[i] + +define void @f2(...) nounwind { +entry: + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 255 + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x.addr = getelementptr [256 x i32]* @x, i64 0, i64 %i + %y.addr = getelementptr [256 x i32]* @y, i64 0, i64 %i + %x = load i32* %x.ld.addr ; 0 + %y = load i32* %y.addr ; 1 + %r = add i32 %y, %x + store i32 %r, i32* %x.addr ; 2 +; CHECK: 0,2: dep +; CHECK: 1,2: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 250 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Analysis/LoopDependenceAnalysis/ziv.ll b/test/Analysis/LoopDependenceAnalysis/ziv.ll new file mode 100644 index 00000000000..645ae7f152e --- /dev/null +++ b/test/Analysis/LoopDependenceAnalysis/ziv.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -analyze -basicaa -lda | FileCheck %s + +@x = common global [256 x i32] zeroinitializer, align 4 + +;; x[5] = x[6] + +define void @f1(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x = load i32* getelementptr ([256 x i32]* @x, i32 0, i64 6) + store i32 %x, i32* getelementptr ([256 x i32]* @x, i32 0, i64 5) +; CHECK: 0,1: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; x[c] = x[c+1] // with c being a loop-invariant constant + +define void @f2(i64 %c0) nounwind { +entry: + %c1 = add i64 %c0, 1 + %x.ld.addr = getelementptr [256 x i32]* @x, i64 0, i64 %c0 + %x.st.addr = getelementptr [256 x i32]* @x, i64 0, i64 %c1 + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x = load i32* %x.ld.addr + store i32 %x, i32* %x.st.addr +; CHECK: 0,1: ind + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +;; x[6] = x[6] + +define void @f3(...) nounwind { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] + %x = load i32* getelementptr ([256 x i32]* @x, i32 0, i64 6) + store i32 %x, i32* getelementptr ([256 x i32]* @x, i32 0, i64 6) +; CHECK: 0,1: dep + %i.next = add i64 %i, 1 + %exitcond = icmp eq i64 %i.next, 256 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Analysis/LoopInfo/2003-05-15-NestingProblem.ll b/test/Analysis/LoopInfo/2003-05-15-NestingProblem.ll new file mode 100644 index 00000000000..7119007ffde --- /dev/null +++ b/test/Analysis/LoopInfo/2003-05-15-NestingProblem.ll @@ -0,0 +1,30 @@ +; This testcase was incorrectly computing that the loopentry.7 loop was +; not a child of the loopentry.6 loop. +; +; RUN: opt < %s -analyze -loops | \ +; RUN: grep "^ Loop at depth 4 containing: %loopentry.7<header><latch><exiting>" + +define void @getAndMoveToFrontDecode() { + br label %endif.2 + +endif.2: ; preds = %loopexit.5, %0 + br i1 false, label %loopentry.5, label %UnifiedExitNode + +loopentry.5: ; preds = %loopexit.6, %endif.2 + br i1 false, label %loopentry.6, label %UnifiedExitNode + +loopentry.6: ; preds = %loopentry.7, %loopentry.5 + br i1 false, label %loopentry.7, label %loopexit.6 + +loopentry.7: ; preds = %loopentry.7, %loopentry.6 + br i1 false, label %loopentry.7, label %loopentry.6 + +loopexit.6: ; preds = %loopentry.6 + br i1 false, label %loopentry.5, label %loopexit.5 + +loopexit.5: ; preds = %loopexit.6 + br i1 false, label %endif.2, label %UnifiedExitNode + +UnifiedExitNode: ; preds = %loopexit.5, %loopentry.5, %endif.2 + ret void +} diff --git a/test/Analysis/LoopInfo/lit.local.cfg b/test/Analysis/LoopInfo/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/LoopInfo/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/PostDominators/lit.local.cfg b/test/Analysis/PostDominators/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/PostDominators/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/PostDominators/pr1098.ll b/test/Analysis/PostDominators/pr1098.ll new file mode 100644 index 00000000000..afb47769ee4 --- /dev/null +++ b/test/Analysis/PostDominators/pr1098.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -postdomtree -analyze | grep entry +; PR932 + +define void @foo(i1 %x) { +entry: + br i1 %x, label %bb1, label %bb0 +bb0: ; preds = %entry, bb0 + br label %bb0 +bb1: ; preds = %entry + br label %bb2 +bb2: ; preds = %bb1 + ret void +} + diff --git a/test/Analysis/PostDominators/pr6047_a.ll b/test/Analysis/PostDominators/pr6047_a.ll new file mode 100644 index 00000000000..ec1455b46fe --- /dev/null +++ b/test/Analysis/PostDominators/pr6047_a.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -postdomtree -analyze | FileCheck %s +define internal void @f() { +entry: + br i1 undef, label %bb35, label %bb3.i + +bb3.i: + br label %bb3.i + +bb35.loopexit3: + br label %bb35 + +bb35: + ret void +} +; CHECK: [3] %entry diff --git a/test/Analysis/PostDominators/pr6047_b.ll b/test/Analysis/PostDominators/pr6047_b.ll new file mode 100644 index 00000000000..7bd2c86b737 --- /dev/null +++ b/test/Analysis/PostDominators/pr6047_b.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -postdomtree -analyze | FileCheck %s +define internal void @f() { +entry: + br i1 undef, label %a, label %bb3.i + +a: + br i1 undef, label %bb35, label %bb3.i + +bb3.i: + br label %bb3.i + + +bb35.loopexit3: + br label %bb35 + +bb35: + ret void +} +; CHECK: [4] %entry diff --git a/test/Analysis/PostDominators/pr6047_c.ll b/test/Analysis/PostDominators/pr6047_c.ll new file mode 100644 index 00000000000..08c9551f156 --- /dev/null +++ b/test/Analysis/PostDominators/pr6047_c.ll @@ -0,0 +1,147 @@ +; RUN: opt < %s -postdomtree -analyze | FileCheck %s +define internal void @f() { +entry: + br i1 undef, label %bb35, label %bb3.i + +bb3.i: + br label %bb3.i + +bb: + br label %bb35 + +bb.i: + br label %bb35 + +_float32_unpack.exit: + br label %bb35 + +bb.i5: + br label %bb35 + +_float32_unpack.exit8: + br label %bb35 + +bb32.preheader: + br label %bb35 + +bb3: + br label %bb35 + +bb3.split.us: + br label %bb35 + +bb.i4.us: + br label %bb35 + +bb7.i.us: + br label %bb35 + +bb.i4.us.backedge: + br label %bb35 + +bb1.i.us: + br label %bb35 + +bb6.i.us: + br label %bb35 + +bb4.i.us: + br label %bb35 + +bb8.i.us: + br label %bb35 + +bb3.i.loopexit.us: + br label %bb35 + +bb.nph21: + br label %bb35 + +bb4: + br label %bb35 + +bb5: + br label %bb35 + +bb14.preheader: + br label %bb35 + +bb.nph18: + br label %bb35 + +bb8.us.preheader: + br label %bb35 + +bb8.preheader: + br label %bb35 + +bb8.us: + br label %bb35 + +bb8: + br label %bb35 + +bb15.loopexit: + br label %bb35 + +bb15.loopexit2: + br label %bb35 + +bb15: + br label %bb35 + +bb16: + br label %bb35 + +bb17.loopexit.split: + br label %bb35 + +bb.nph14: + br label %bb35 + +bb19: + br label %bb35 + +bb20: + br label %bb35 + +bb29.preheader: + br label %bb35 + +bb.nph: + br label %bb35 + +bb23.us.preheader: + br label %bb35 + +bb23.preheader: + br label %bb35 + +bb23.us: + br label %bb35 + +bb23: + br label %bb35 + +bb30.loopexit: + br label %bb35 + +bb30.loopexit1: + br label %bb35 + +bb30: + br label %bb35 + +bb31: + br label %bb35 + +bb35.loopexit: + br label %bb35 + +bb35.loopexit3: + br label %bb35 + +bb35: + ret void +} +; CHECK: [3] %entry diff --git a/test/Analysis/PostDominators/pr6047_d.ll b/test/Analysis/PostDominators/pr6047_d.ll new file mode 100644 index 00000000000..4cfa88029ae --- /dev/null +++ b/test/Analysis/PostDominators/pr6047_d.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -postdomtree -analyze | FileCheck %s +define internal void @f() { +entry: + br i1 1, label %a, label %b + +a: +br label %c + +b: +br label %c + +c: + br i1 undef, label %bb35, label %bb3.i + +bb3.i: + br label %bb3.i + +bb35.loopexit3: + br label %bb35 + +bb35: + ret void +} +; CHECK: [4] %entry diff --git a/test/Analysis/Profiling/edge-profiling.ll b/test/Analysis/Profiling/edge-profiling.ll new file mode 100644 index 00000000000..cbaf47617fb --- /dev/null +++ b/test/Analysis/Profiling/edge-profiling.ll @@ -0,0 +1,139 @@ +; Test the edge profiling instrumentation. +; RUN: opt < %s -insert-edge-profiling -S | FileCheck %s + +; ModuleID = '<stdin>' + +@.str = private constant [12 x i8] c"hello world\00", align 1 ; <[12 x i8]*> [#uses=1] +@.str1 = private constant [6 x i8] c"franz\00", align 1 ; <[6 x i8]*> [#uses=1] +@.str2 = private constant [9 x i8] c"argc > 2\00", align 1 ; <[9 x i8]*> [#uses=1] +@.str3 = private constant [9 x i8] c"argc = 1\00", align 1 ; <[9 x i8]*> [#uses=1] +@.str4 = private constant [6 x i8] c"fritz\00", align 1 ; <[6 x i8]*> [#uses=1] +@.str5 = private constant [10 x i8] c"argc <= 1\00", align 1 ; <[10 x i8]*> [#uses=1] +; CHECK:@EdgeProfCounters +; CHECK:[19 x i32] +; CHECK:zeroinitializer + +define void @oneblock() nounwind { +entry: +; CHECK:entry: +; CHECK:%OldFuncCounter +; CHECK:load +; CHECK:getelementptr +; CHECK:@EdgeProfCounters +; CHECK:i32 0 +; CHECK:i32 0 +; CHECK:%NewFuncCounter +; CHECK:add +; CHECK:%OldFuncCounter +; CHECK:store +; CHECK:%NewFuncCounter +; CHECK:getelementptr +; CHECK:@EdgeProfCounters + %0 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + ret void +} + +declare i32 @puts(i8*) + +define i32 @main(i32 %argc, i8** %argv) nounwind { +entry: +; CHECK:entry: + %argc_addr = alloca i32 ; <i32*> [#uses=4] + %argv_addr = alloca i8** ; <i8***> [#uses=1] + %retval = alloca i32 ; <i32*> [#uses=2] + %j = alloca i32 ; <i32*> [#uses=4] + %i = alloca i32 ; <i32*> [#uses=4] + %0 = alloca i32 ; <i32*> [#uses=2] +; CHECK:call +; CHECK:@llvm_start_edge_profiling +; CHECK:@EdgeProfCounters + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store i32 %argc, i32* %argc_addr + store i8** %argv, i8*** %argv_addr + store i32 0, i32* %i, align 4 + br label %bb10 + +bb: ; preds = %bb10 +; CHECK:bb: + %1 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %2 = icmp sgt i32 %1, 1 ; <i1> [#uses=1] + br i1 %2, label %bb1, label %bb8 + +bb1: ; preds = %bb +; CHECK:bb1: + store i32 0, i32* %j, align 4 + br label %bb6 + +bb2: ; preds = %bb6 +; CHECK:bb2: + %3 = call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @.str1, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + %4 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %5 = icmp sgt i32 %4, 2 ; <i1> [#uses=1] + br i1 %5, label %bb3, label %bb4 + +bb3: ; preds = %bb2 +; CHECK:bb3: + %6 = call i32 @puts(i8* getelementptr inbounds ([9 x i8]* @.str2, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb5 + +bb4: ; preds = %bb2 +; CHECK:bb4: + %7 = call i32 @puts(i8* getelementptr inbounds ([9 x i8]* @.str3, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb11 + +bb5: ; preds = %bb3 +; CHECK:bb5: + %8 = call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @.str4, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + %9 = load i32* %j, align 4 ; <i32> [#uses=1] + %10 = add nsw i32 %9, 1 ; <i32> [#uses=1] + store i32 %10, i32* %j, align 4 + br label %bb6 + +bb6: ; preds = %bb5, %bb1 +; CHECK:bb6: + %11 = load i32* %j, align 4 ; <i32> [#uses=1] + %12 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %13 = icmp slt i32 %11, %12 ; <i1> [#uses=1] + br i1 %13, label %bb2, label %bb7 + +bb7: ; preds = %bb6 +; CHECK:bb7: + br label %bb9 + +bb8: ; preds = %bb +; CHECK:bb8: + %14 = call i32 @puts(i8* getelementptr inbounds ([10 x i8]* @.str5, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb9 + +bb9: ; preds = %bb8, %bb7 +; CHECK:bb9: + %15 = load i32* %i, align 4 ; <i32> [#uses=1] + %16 = add nsw i32 %15, 1 ; <i32> [#uses=1] + store i32 %16, i32* %i, align 4 + br label %bb10 + +bb10: ; preds = %bb9, %entry +; CHECK:bb10: + %17 = load i32* %i, align 4 ; <i32> [#uses=1] + %18 = icmp ne i32 %17, 3 ; <i1> [#uses=1] + br i1 %18, label %bb, label %bb11 +; CHECK:br +; CHECK:label %bb10.bb11_crit_edge + +; CHECK:bb10.bb11_crit_edge: +; CHECK:br +; CHECK:label %bb11 + +bb11: ; preds = %bb10, %bb4 +; CHECK:bb11: + call void @oneblock() nounwind + store i32 0, i32* %0, align 4 + %19 = load i32* %0, align 4 ; <i32> [#uses=1] + store i32 %19, i32* %retval, align 4 + br label %return + +return: ; preds = %bb11 +; CHECK:return: + %retval12 = load i32* %retval ; <i32> [#uses=1] + ret i32 %retval12 +} diff --git a/test/Analysis/Profiling/lit.local.cfg b/test/Analysis/Profiling/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/Profiling/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/Profiling/load-branch-weights-ifs.ll b/test/Analysis/Profiling/load-branch-weights-ifs.ll new file mode 100644 index 00000000000..ddbaf96916c --- /dev/null +++ b/test/Analysis/Profiling/load-branch-weights-ifs.ll @@ -0,0 +1,122 @@ +; RUN: opt -insert-edge-profiling -o %t1 < %s +; RUN: rm -f %t1.prof_data +; RUN: lli -load %llvmshlibdir/libprofile_rt%shlibext %t1 \ +; RUN: -llvmprof-output %t1.prof_data +; RUN: opt -profile-file %t1.prof_data -profile-metadata-loader -S -o - < %s \ +; RUN: | FileCheck %s +; RUN: rm -f %t1.prof_data + +; FIXME: profile_rt.dll could be built on win32. +; REQUIRES: loadable_module + +;; func_mod - Branch taken 6 times in 7. +define i32 @func_mod(i32 %N) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %N.addr = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + %0 = load i32* %N.addr, align 4 + %rem = srem i32 %0, 7 + %tobool = icmp ne i32 %rem, 0 + br i1 %tobool, label %if.then, label %if.else +; CHECK: br i1 %tobool, label %if.then, label %if.else, !prof !0 + +if.then: + store i32 1, i32* %retval + br label %return + +if.else: + store i32 0, i32* %retval + br label %return + +return: + %1 = load i32* %retval + ret i32 %1 +} + +;; func_const_true - conditional branch which 100% taken probability. +define i32 @func_const_true(i32 %N) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %N.addr = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + %0 = load i32* %N.addr, align 4 + %cmp = icmp eq i32 %0, 1 + br i1 %cmp, label %if.then, label %if.end +; CHECK: br i1 %cmp, label %if.then, label %if.end, !prof !1 + +if.then: + store i32 1, i32* %retval + br label %return + +if.end: + store i32 0, i32* %retval + br label %return + +return: + %1 = load i32* %retval + ret i32 %1 +} + +;; func_const_true - conditional branch which 100% not-taken probability. +define i32 @func_const_false(i32 %N) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %N.addr = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + %0 = load i32* %N.addr, align 4 + %cmp = icmp eq i32 %0, 1 + br i1 %cmp, label %if.then, label %if.end +; CHECK: br i1 %cmp, label %if.then, label %if.end, !prof !2 + +if.then: + store i32 1, i32* %retval + br label %return + +if.end: + store i32 0, i32* %retval + br label %return + +return: + %1 = load i32* %retval + ret i32 %1 +} + +define i32 @main(i32 %argc, i8** %argv) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %argc.addr = alloca i32, align 4 + %argv.addr = alloca i8**, align 8 + %loop = alloca i32, align 4 + store i32 0, i32* %retval + store i32 0, i32* %loop, align 4 + br label %for.cond + +for.cond: + %0 = load i32* %loop, align 4 + %cmp = icmp slt i32 %0, 7000 + br i1 %cmp, label %for.body, label %for.end +; CHECK: br i1 %cmp, label %for.body, label %for.end, !prof !3 + +for.body: + %1 = load i32* %loop, align 4 + %call = call i32 @func_mod(i32 %1) + br label %for.inc + +for.inc: + %2 = load i32* %loop, align 4 + %inc = add nsw i32 %2, 1 + store i32 %inc, i32* %loop, align 4 + br label %for.cond + +for.end: + %call1 = call i32 @func_const_true(i32 1) + %call2 = call i32 @func_const_false(i32 0) + ret i32 0 +} + +; CHECK: !0 = metadata !{metadata !"branch_weights", i32 6000, i32 1000} +; CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 0} +; CHECK: !2 = metadata !{metadata !"branch_weights", i32 0, i32 1} +; CHECK: !3 = metadata !{metadata !"branch_weights", i32 7000, i32 1} +; CHECK-NOT: !4 diff --git a/test/Analysis/Profiling/load-branch-weights-loops.ll b/test/Analysis/Profiling/load-branch-weights-loops.ll new file mode 100644 index 00000000000..476f377b47a --- /dev/null +++ b/test/Analysis/Profiling/load-branch-weights-loops.ll @@ -0,0 +1,188 @@ +; RUN: opt -insert-edge-profiling -o %t1 < %s +; RUN: rm -f %t1.prof_data +; RUN: lli -load %llvmshlibdir/libprofile_rt%shlibext %t1 \ +; RUN: -llvmprof-output %t1.prof_data +; RUN: opt -profile-file %t1.prof_data -profile-metadata-loader -S -o - < %s \ +; RUN: | FileCheck %s +; RUN: rm -f %t1.prof_data + +; FIXME: profile_rt.dll could be built on win32. +; REQUIRES: loadable_module + +;; func_for - Test branch probabilities for a vanilla for loop. +define i32 @func_for(i32 %N) nounwind uwtable { +entry: + %N.addr = alloca i32, align 4 + %ret = alloca i32, align 4 + %loop = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + store i32 0, i32* %ret, align 4 + store i32 0, i32* %loop, align 4 + br label %for.cond + +for.cond: + %0 = load i32* %loop, align 4 + %1 = load i32* %N.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %for.body, label %for.end +; CHECK: br i1 %cmp, label %for.body, label %for.end, !prof !0 + +for.body: + %2 = load i32* %N.addr, align 4 + %3 = load i32* %ret, align 4 + %add = add nsw i32 %3, %2 + store i32 %add, i32* %ret, align 4 + br label %for.inc + +for.inc: + %4 = load i32* %loop, align 4 + %inc = add nsw i32 %4, 1 + store i32 %inc, i32* %loop, align 4 + br label %for.cond + +for.end: + %5 = load i32* %ret, align 4 + ret i32 %5 +} + +;; func_for_odd - Test branch probabilities for a for loop with a continue and +;; a break. +define i32 @func_for_odd(i32 %N) nounwind uwtable { +entry: + %N.addr = alloca i32, align 4 + %ret = alloca i32, align 4 + %loop = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + store i32 0, i32* %ret, align 4 + store i32 0, i32* %loop, align 4 + br label %for.cond + +for.cond: + %0 = load i32* %loop, align 4 + %1 = load i32* %N.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %for.body, label %for.end +; CHECK: br i1 %cmp, label %for.body, label %for.end, !prof !1 + +for.body: + %2 = load i32* %loop, align 4 + %rem = srem i32 %2, 10 + %tobool = icmp ne i32 %rem, 0 + br i1 %tobool, label %if.then, label %if.end +; CHECK: br i1 %tobool, label %if.then, label %if.end, !prof !2 + +if.then: + br label %for.inc + +if.end: + %3 = load i32* %loop, align 4 + %cmp1 = icmp eq i32 %3, 500 + br i1 %cmp1, label %if.then2, label %if.end3 +; CHECK: br i1 %cmp1, label %if.then2, label %if.end3, !prof !3 + +if.then2: + br label %for.end + +if.end3: + %4 = load i32* %N.addr, align 4 + %5 = load i32* %ret, align 4 + %add = add nsw i32 %5, %4 + store i32 %add, i32* %ret, align 4 + br label %for.inc + +for.inc: + %6 = load i32* %loop, align 4 + %inc = add nsw i32 %6, 1 + store i32 %inc, i32* %loop, align 4 + br label %for.cond + +for.end: + %7 = load i32* %ret, align 4 + ret i32 %7 +} + +;; func_while - Test branch probability in a vanilla while loop. +define i32 @func_while(i32 %N) nounwind uwtable { +entry: + %N.addr = alloca i32, align 4 + %ret = alloca i32, align 4 + %loop = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + store i32 0, i32* %ret, align 4 + store i32 0, i32* %loop, align 4 + br label %while.cond + +while.cond: + %0 = load i32* %loop, align 4 + %1 = load i32* %N.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %while.body, label %while.end +; CHECK: br i1 %cmp, label %while.body, label %while.end, !prof !0 + +while.body: + %2 = load i32* %N.addr, align 4 + %3 = load i32* %ret, align 4 + %add = add nsw i32 %3, %2 + store i32 %add, i32* %ret, align 4 + %4 = load i32* %loop, align 4 + %inc = add nsw i32 %4, 1 + store i32 %inc, i32* %loop, align 4 + br label %while.cond + +while.end: + %5 = load i32* %ret, align 4 + ret i32 %5 +} + +;; func_while - Test branch probability in a vanilla do-while loop. +define i32 @func_do_while(i32 %N) nounwind uwtable { +entry: + %N.addr = alloca i32, align 4 + %ret = alloca i32, align 4 + %loop = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + store i32 0, i32* %ret, align 4 + store i32 0, i32* %loop, align 4 + br label %do.body + +do.body: + %0 = load i32* %N.addr, align 4 + %1 = load i32* %ret, align 4 + %add = add nsw i32 %1, %0 + store i32 %add, i32* %ret, align 4 + %2 = load i32* %loop, align 4 + %inc = add nsw i32 %2, 1 + store i32 %inc, i32* %loop, align 4 + br label %do.cond + +do.cond: + %3 = load i32* %loop, align 4 + %4 = load i32* %N.addr, align 4 + %cmp = icmp slt i32 %3, %4 + br i1 %cmp, label %do.body, label %do.end +; CHECK: br i1 %cmp, label %do.body, label %do.end, !prof !4 + +do.end: + %5 = load i32* %ret, align 4 + ret i32 %5 +} + +define i32 @main(i32 %argc, i8** %argv) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %argc.addr = alloca i32, align 4 + %argv.addr = alloca i8**, align 8 + store i32 0, i32* %retval + %call = call i32 @func_for(i32 1000) + %call1 = call i32 @func_for_odd(i32 1000) + %call2 = call i32 @func_while(i32 1000) + %call3 = call i32 @func_do_while(i32 1000) + ret i32 0 +} + +!0 = metadata !{metadata !"branch_weights", i32 1000, i32 1} +!1 = metadata !{metadata !"branch_weights", i32 501, i32 0} +!2 = metadata !{metadata !"branch_weights", i32 450, i32 51} +!3 = metadata !{metadata !"branch_weights", i32 1, i32 50} +!4 = metadata !{metadata !"branch_weights", i32 999, i32 1} +; CHECK-NOT: !5 diff --git a/test/Analysis/Profiling/load-branch-weights-switches.ll b/test/Analysis/Profiling/load-branch-weights-switches.ll new file mode 100644 index 00000000000..be11f040a76 --- /dev/null +++ b/test/Analysis/Profiling/load-branch-weights-switches.ll @@ -0,0 +1,165 @@ +; RUN: opt -insert-edge-profiling -o %t1 < %s +; RUN: rm -f %t1.prof_data +; RUN: lli -load %llvmshlibdir/libprofile_rt%shlibext %t1 \ +; RUN: -llvmprof-output %t1.prof_data +; RUN: opt -profile-file %t1.prof_data -profile-metadata-loader -S -o - < %s \ +; RUN: | FileCheck %s +; RUN: rm -f %t1.prof_data + +; FIXME: profile_rt.dll could be built on win32. +; REQUIRES: loadable_module + +;; func_switch - Test branch probabilities for a switch instruction with an +;; even chance of taking each case (or no case). +define i32 @func_switch(i32 %N) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %N.addr = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + %0 = load i32* %N.addr, align 4 + %rem = srem i32 %0, 4 + switch i32 %rem, label %sw.epilog [ + i32 0, label %sw.bb + i32 1, label %sw.bb1 + i32 2, label %sw.bb2 + ] +; CHECK: ], !prof !0 + +sw.bb: + store i32 5, i32* %retval + br label %return + +sw.bb1: + store i32 6, i32* %retval + br label %return + +sw.bb2: + store i32 7, i32* %retval + br label %return + +sw.epilog: + store i32 8, i32* %retval + br label %return + +return: + %1 = load i32* %retval + ret i32 %1 +} + +;; func_switch_switch - Test branch probabilities in a switch-instruction that +;; leads to further switch instructions. The first-tier switch occludes some +;; possibilities in the second-tier switches, leading to some branches having a +;; 0 probability. +define i32 @func_switch_switch(i32 %N) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %N.addr = alloca i32, align 4 + store i32 %N, i32* %N.addr, align 4 + %0 = load i32* %N.addr, align 4 + %rem = srem i32 %0, 2 + switch i32 %rem, label %sw.default11 [ + i32 0, label %sw.bb + i32 1, label %sw.bb5 + ] +; CHECK: ], !prof !1 + +sw.bb: + %1 = load i32* %N.addr, align 4 + %rem1 = srem i32 %1, 4 + switch i32 %rem1, label %sw.default [ + i32 0, label %sw.bb2 + i32 1, label %sw.bb3 + i32 2, label %sw.bb4 + ] +; CHECK: ], !prof !2 + +sw.bb2: + store i32 5, i32* %retval + br label %return + +sw.bb3: + store i32 6, i32* %retval + br label %return + +sw.bb4: + store i32 7, i32* %retval + br label %return + +sw.default: + store i32 8, i32* %retval + br label %return + +sw.bb5: + %2 = load i32* %N.addr, align 4 + %rem6 = srem i32 %2, 4 + switch i32 %rem6, label %sw.default10 [ + i32 0, label %sw.bb7 + i32 1, label %sw.bb8 + i32 2, label %sw.bb9 + ] +; CHECK: ], !prof !3 + +sw.bb7: + store i32 9, i32* %retval + br label %return + +sw.bb8: + store i32 10, i32* %retval + br label %return + +sw.bb9: + store i32 11, i32* %retval + br label %return + +sw.default10: + store i32 12, i32* %retval + br label %return + +sw.default11: + store i32 13, i32* %retval + br label %return + +return: + %3 = load i32* %retval + ret i32 %3 +} + +define i32 @main(i32 %argc, i8** %argv) nounwind uwtable { +entry: + %retval = alloca i32, align 4 + %argc.addr = alloca i32, align 4 + %argv.addr = alloca i8**, align 8 + %loop = alloca i32, align 4 + store i32 0, i32* %retval + store i32 0, i32* %loop, align 4 + br label %for.cond + +for.cond: + %0 = load i32* %loop, align 4 + %cmp = icmp slt i32 %0, 4000 + br i1 %cmp, label %for.body, label %for.end +; CHECK: br i1 %cmp, label %for.body, label %for.end, !prof !4 + +for.body: + %1 = load i32* %loop, align 4 + %call = call i32 @func_switch(i32 %1) + %2 = load i32* %loop, align 4 + %call1 = call i32 @func_switch_switch(i32 %2) + br label %for.inc + +for.inc: + %3 = load i32* %loop, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, i32* %loop, align 4 + br label %for.cond + +for.end: + ret i32 0 +} + +; CHECK: !0 = metadata !{metadata !"branch_weights", i32 1000, i32 1000, i32 1000, i32 1000} +; CHECK: !1 = metadata !{metadata !"branch_weights", i32 0, i32 2000, i32 2000} +; CHECK: !2 = metadata !{metadata !"branch_weights", i32 0, i32 1000, i32 0, i32 1000} +; CHECK: !3 = metadata !{metadata !"branch_weights", i32 1000, i32 0, i32 1000, i32 0} +; CHECK: !4 = metadata !{metadata !"branch_weights", i32 4000, i32 1} +; CHECK-NOT: !5 diff --git a/test/Analysis/Profiling/profiling-tool-chain.ll b/test/Analysis/Profiling/profiling-tool-chain.ll new file mode 100644 index 00000000000..9135a85dc3a --- /dev/null +++ b/test/Analysis/Profiling/profiling-tool-chain.ll @@ -0,0 +1,212 @@ +; RUN: llvm-as %s -o %t1 + +; FIXME: The RUX parts of the test are disabled for now, they aren't working on +; llvm-gcc-x86_64-darwin10-selfhost. + +; Test the edge optimal profiling instrumentation. +; RUN: opt %t1 -insert-optimal-edge-profiling -o %t2 +; RUX: llvm-dis < %t2 | FileCheck --check-prefix=INST %s + +; Test the creation, reading and displaying of profile +; RUX: rm -f llvmprof.out +; RUX: lli -load %llvmshlibdir/profile_rt%shlibext %t2 +; RUX: lli -load %llvmshlibdir/profile_rt%shlibext %t2 1 2 +; RUX: llvm-prof -print-all-code %t1 | FileCheck --check-prefix=PROF %s + +; Test the loaded profile also with verifier. +; RUX opt %t1 -profile-loader -profile-verifier -o %t3 + +; Test profile estimator. +; RUN: opt %t1 -profile-estimator -profile-verifier -o %t3 + +; PROF: 1. 2/4 oneblock +; PROF: 2. 2/4 main +; PROF: 1. 15.7895% 12/76 main() - bb6 +; PROF: 2. 11.8421% 9/76 main() - bb2 +; PROF: 3. 11.8421% 9/76 main() - bb3 +; PROF: 4. 11.8421% 9/76 main() - bb5 +; PROF: 5. 10.5263% 8/76 main() - bb10 +; PROF: 6. 7.89474% 6/76 main() - bb +; PROF: 7. 7.89474% 6/76 main() - bb9 +; PROF: 8. 3.94737% 3/76 main() - bb1 +; PROF: 9. 3.94737% 3/76 main() - bb7 +; PROF: 10. 3.94737% 3/76 main() - bb8 +; PROF: 11. 2.63158% 2/76 oneblock() - entry +; PROF: 12. 2.63158% 2/76 main() - entry +; PROF: 13. 2.63158% 2/76 main() - bb11 +; PROF: 14. 2.63158% 2/76 main() - return + +; ModuleID = '<stdin>' + +@.str = private constant [12 x i8] c"hello world\00", align 1 ; <[12 x i8]*> [#uses=1] +@.str1 = private constant [6 x i8] c"franz\00", align 1 ; <[6 x i8]*> [#uses=1] +@.str2 = private constant [9 x i8] c"argc > 2\00", align 1 ; <[9 x i8]*> [#uses=1] +@.str3 = private constant [9 x i8] c"argc = 1\00", align 1 ; <[9 x i8]*> [#uses=1] +@.str4 = private constant [6 x i8] c"fritz\00", align 1 ; <[6 x i8]*> [#uses=1] +@.str5 = private constant [10 x i8] c"argc <= 1\00", align 1 ; <[10 x i8]*> [#uses=1] +; INST:@OptEdgeProfCounters +; INST:[21 x i32] +; INST:[i32 0, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 0, +; INST:i32 0, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 0, +; INST:i32 0, +; INST:i32 -1, +; INST:i32 -1, +; INST:i32 0, +; INST:i32 -1, +; INST:i32 -1] + +; PROF:;;; %oneblock called 2 times. +; PROF:;;; +define void @oneblock() nounwind { +entry: +; PROF:entry: +; PROF: ;;; Basic block executed 2 times. + %0 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + ret void +} + +declare i32 @puts(i8*) + +; PROF:;;; %main called 2 times. +; PROF:;;; +define i32 @main(i32 %argc, i8** %argv) nounwind { +entry: +; PROF:entry: +; PROF: ;;; Basic block executed 2 times. + %argc_addr = alloca i32 ; <i32*> [#uses=4] + %argv_addr = alloca i8** ; <i8***> [#uses=1] + %retval = alloca i32 ; <i32*> [#uses=2] + %j = alloca i32 ; <i32*> [#uses=4] + %i = alloca i32 ; <i32*> [#uses=4] + %0 = alloca i32 ; <i32*> [#uses=2] +; INST:call +; INST:@llvm_start_opt_edge_profiling +; INST:@OptEdgeProfCounters + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store i32 %argc, i32* %argc_addr + store i8** %argv, i8*** %argv_addr + store i32 0, i32* %i, align 4 + br label %bb10 +; PROF: ;;; Out-edge counts: [2.000000e+00 -> bb10] + +bb: ; preds = %bb10 +; PROF:bb: +; PROF: ;;; Basic block executed 6 times. + %1 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %2 = icmp sgt i32 %1, 1 ; <i1> [#uses=1] + br i1 %2, label %bb1, label %bb8 +; PROF: ;;; Out-edge counts: [3.000000e+00 -> bb1] [3.000000e+00 -> bb8] + +bb1: ; preds = %bb +; PROF:bb1: +; PROF: ;;; Basic block executed 3 times. + store i32 0, i32* %j, align 4 + br label %bb6 +; PROF: ;;; Out-edge counts: [3.000000e+00 -> bb6] + +bb2: ; preds = %bb6 +; PROF:bb2: +; PROF: ;;; Basic block executed 9 times. + %3 = call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @.str1, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + %4 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %5 = icmp sgt i32 %4, 2 ; <i1> [#uses=1] + br i1 %5, label %bb3, label %bb4 +; PROF: ;;; Out-edge counts: [9.000000e+00 -> bb3] + +bb3: ; preds = %bb2 +; PROF:bb3: +; PROF: ;;; Basic block executed 9 times. + %6 = call i32 @puts(i8* getelementptr inbounds ([9 x i8]* @.str2, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb5 +; PROF: ;;; Out-edge counts: [9.000000e+00 -> bb5] + +bb4: ; preds = %bb2 +; PROF:bb4: +; PROF: ;;; Never executed! + %7 = call i32 @puts(i8* getelementptr inbounds ([9 x i8]* @.str3, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb11 + +bb5: ; preds = %bb3 +; PROF:bb5: +; PROF: ;;; Basic block executed 9 times. + %8 = call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @.str4, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + %9 = load i32* %j, align 4 ; <i32> [#uses=1] + %10 = add nsw i32 %9, 1 ; <i32> [#uses=1] + store i32 %10, i32* %j, align 4 + br label %bb6 +; PROF: ;;; Out-edge counts: [9.000000e+00 -> bb6] + +bb6: ; preds = %bb5, %bb1 +; PROF:bb6: +; PROF: ;;; Basic block executed 12 times. + %11 = load i32* %j, align 4 ; <i32> [#uses=1] + %12 = load i32* %argc_addr, align 4 ; <i32> [#uses=1] + %13 = icmp slt i32 %11, %12 ; <i1> [#uses=1] + br i1 %13, label %bb2, label %bb7 +; PROF: ;;; Out-edge counts: [9.000000e+00 -> bb2] [3.000000e+00 -> bb7] + +bb7: ; preds = %bb6 +; PROF:bb7: +; PROF: ;;; Basic block executed 3 times. + br label %bb9 +; PROF: ;;; Out-edge counts: [3.000000e+00 -> bb9] + +bb8: ; preds = %bb +; PROF:bb8: +; PROF: ;;; Basic block executed 3 times. + %14 = call i32 @puts(i8* getelementptr inbounds ([10 x i8]* @.str5, i64 0, i64 0)) nounwind ; <i32> [#uses=0] + br label %bb9 +; PROF: ;;; Out-edge counts: [3.000000e+00 -> bb9] + +bb9: ; preds = %bb8, %bb7 +; PROF:bb9: +; PROF: ;;; Basic block executed 6 times. + %15 = load i32* %i, align 4 ; <i32> [#uses=1] + %16 = add nsw i32 %15, 1 ; <i32> [#uses=1] + store i32 %16, i32* %i, align 4 + br label %bb10 +; PROF: ;;; Out-edge counts: [6.000000e+00 -> bb10] + +bb10: ; preds = %bb9, %entry +; PROF:bb10: +; PROF: ;;; Basic block executed 8 times. + %17 = load i32* %i, align 4 ; <i32> [#uses=1] + %18 = icmp ne i32 %17, 3 ; <i1> [#uses=1] + br i1 %18, label %bb, label %bb11 +; INST:br +; INST:label %bb10.bb11_crit_edge +; PROF: ;;; Out-edge counts: [6.000000e+00 -> bb] [2.000000e+00 -> bb11] + +; INST:bb10.bb11_crit_edge: +; INST:br +; INST:label %bb11 + +bb11: ; preds = %bb10, %bb4 +; PROF:bb11: +; PROF: ;;; Basic block executed 2 times. + call void @oneblock() nounwind + store i32 0, i32* %0, align 4 + %19 = load i32* %0, align 4 ; <i32> [#uses=1] + store i32 %19, i32* %retval, align 4 + br label %return +; PROF: ;;; Out-edge counts: [2.000000e+00 -> return] + +return: ; preds = %bb11 +; PROF:return: +; PROF: ;;; Basic block executed 2 times. + %retval12 = load i32* %retval ; <i32> [#uses=1] + ret i32 %retval12 +} diff --git a/test/Analysis/RegionInfo/20100809_bb_not_in_domtree.ll b/test/Analysis/RegionInfo/20100809_bb_not_in_domtree.ll new file mode 100644 index 00000000000..218b4375f70 --- /dev/null +++ b/test/Analysis/RegionInfo/20100809_bb_not_in_domtree.ll @@ -0,0 +1,20 @@ +; RUN: opt -regions %s +define i32 @main() nounwind { +entry: + br label %for.cond + +test: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + br i1 true, label %for.body, label %for.end + +for.body: ; preds = %for.cond + br label %for.inc + +for.inc: ; preds = %for.body + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 0 +} diff --git a/test/Analysis/RegionInfo/block_sort.ll b/test/Analysis/RegionInfo/block_sort.ll new file mode 100644 index 00000000000..ac77ab36e6f --- /dev/null +++ b/test/Analysis/RegionInfo/block_sort.ll @@ -0,0 +1,42 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats -analyze < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @BZ2_blockSort() nounwind { +start: + br label %while + +while: + br label %while.body134.i.i + +while.body134.i.i: + br i1 1, label %end, label %w + +w: + br label %if.end140.i.i + +if.end140.i.i: + br i1 1, label %while.end186.i.i, label %if.end183.i.i + +if.end183.i.i: + br label %while.body134.i.i + +while.end186.i.i: + br label %while + +end: + ret void +} +; CHECK-NOT: => +; CHECK: [0] start => <Function Return> +; CHECK: [1] while => end + +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: start, while, while.body134.i.i, end, w, if.end140.i.i, while.end186.i.i, if.end183.i.i, +; BBIT: while, while.body134.i.i, w, if.end140.i.i, while.end186.i.i, if.end183.i.i, + +; RNIT: start, while => end, end, +; RNIT: while, while.body134.i.i, w, if.end140.i.i, while.end186.i.i, if.end183.i.i, diff --git a/test/Analysis/RegionInfo/cond_loop.ll b/test/Analysis/RegionInfo/cond_loop.ll new file mode 100644 index 00000000000..1145ffdba03 --- /dev/null +++ b/test/Analysis/RegionInfo/cond_loop.ll @@ -0,0 +1,33 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +5: + br label %"0" + +0: + br label %"1" +1: + br i1 1, label %"2", label %"3" +2: + ret void +3: + br i1 1, label %"1", label %"4" +4: + br label %"0" +} + +; CHECK-NOT: => +; CHECK: [0] 5 => <Function Return> +; CHECK: [1] 0 => 2 + +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 5, 0, 1, 2, 3, 4, +; BBIT: 0, 1, 3, 4, + +; RNIT: 5, 0 => 2, 2, +; RNIT: 0, 1, 3, 4, diff --git a/test/Analysis/RegionInfo/condition_complicated.ll b/test/Analysis/RegionInfo/condition_complicated.ll new file mode 100644 index 00000000000..6b398800db9 --- /dev/null +++ b/test/Analysis/RegionInfo/condition_complicated.ll @@ -0,0 +1,60 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc zeroext i8 @handle_compress() nounwind { +end165: + br i1 1, label %false239, label %true181 + +true181: + br i1 1, label %then187, label %else232 + +then187: + br label %end265 + +else232: + br i1 1, label %false239, label %then245 + +false239: + br i1 1, label %then245, label %else259 + +then245: + br i1 1, label %then251, label %end253 + +then251: + br label %end253 + +end253: + br label %end265 + +else259: + br label %end265 + +end265: + br i1 1, label %then291, label %end298 + +then291: + br label %end298 + +end298: + ret i8 1 +} + +; CHECK-NOT: => +; CHECK: [0] end165 => <Function Return> +; CHECK-NEXT: [1] end165 => end265 +; CHECK-NEXT: [2] then245 => end253 +; CHECK-NEXT: [1] end265 => end298 + +; STAT: 4 region - The # of regions + +; BBIT: end165, false239, then245, then251, end253, end265, then291, end298, else259, true181, then187, else232, +; BBIT: end165, false239, then245, then251, end253, else259, true181, then187, else232, +; BBIT: then245, then251, +; BBIT: end265, then291, + +; RNIT: end165 => end265, end265 => end298, end298, +; RNIT: end165, false239, then245 => end253, end253, else259, true181, then187, else232, +; RNIT: then245, then251, +; RNIT: end265, then291, diff --git a/test/Analysis/RegionInfo/condition_complicated_2.ll b/test/Analysis/RegionInfo/condition_complicated_2.ll new file mode 100644 index 00000000000..f551108d608 --- /dev/null +++ b/test/Analysis/RegionInfo/condition_complicated_2.ll @@ -0,0 +1,44 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc void @compress() nounwind { +end33: + br i1 1, label %end124, label %lor.lhs.false95 + +lor.lhs.false95: + br i1 1, label %then107, label %end172 + +then107: + br i1 1, label %end124, label %then113 + +then113: + br label %end124 + +end124: + br label %exit + +end172: + br label %exit + + +exit: + unreachable + + +} +; CHECK-NOT: => +; CHECK: [0] end33 => <Function Return> +; CHECK-NEXT: [1] end33 => exit +; CHECK-NEXT: [2] then107 => end124 + +; STAT: 3 region - The # of regions + +; BBIT: end33, end124, exit, lor.lhs.false95, then107, then113, end172, +; BBIT: end33, end124, lor.lhs.false95, then107, then113, end172, +; BBIT: then107, then113, + +; RNIT: end33 => exit, exit, +; RNIT: end33, end124, lor.lhs.false95, then107 => end124, end172, +; RNIT: then107, then113, diff --git a/test/Analysis/RegionInfo/condition_forward_edge.ll b/test/Analysis/RegionInfo/condition_forward_edge.ll new file mode 100644 index 00000000000..5e4d9d2f8b2 --- /dev/null +++ b/test/Analysis/RegionInfo/condition_forward_edge.ll @@ -0,0 +1,26 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"1" +1: + br i1 1, label %"2", label %"3" +2: + br label %"3" +3: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK: [1] 1 => 3 + +; STAT: 2 region - The # of regions + +; BBIT: 0, 1, 2, 3, +; BBIT: 1, 2, + +; RNIT: 0, 1 => 3, 3, +; RNIT: 1, 2, diff --git a/test/Analysis/RegionInfo/condition_same_exit.ll b/test/Analysis/RegionInfo/condition_same_exit.ll new file mode 100644 index 00000000000..e48413a4c2d --- /dev/null +++ b/test/Analysis/RegionInfo/condition_same_exit.ll @@ -0,0 +1,31 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br i1 1, label %"1", label %"4" + +1: + br i1 1, label %"2", label %"3" +2: + br label %"4" +3: + br label %"4" +4: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 0 => 4 +; CHECK-NEXT: [2] 1 => 4 +; STAT: 3 region - The # of regions + +; BBIT: 0, 1, 2, 4, 3, +; BBIT: 0, 1, 2, 3, +; BBIT: 1, 2, 3, + +; RNIT: 0 => 4, 4, +; RNIT: 0, 1 => 4, +; RNIT: 1, 2, 3, diff --git a/test/Analysis/RegionInfo/condition_simple.ll b/test/Analysis/RegionInfo/condition_simple.ll new file mode 100644 index 00000000000..00d9ed24e17 --- /dev/null +++ b/test/Analysis/RegionInfo/condition_simple.ll @@ -0,0 +1,28 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"1" +1: + br i1 1, label %"2", label %"3" +2: + br label %"4" +3: + br label %"4" +4: + ret void +} + +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 1 => 4 +; STAT: 2 region - The # of regions + +; BBIT: 0, 1, 2, 4, 3, +; BBIT: 1, 2, 3, + +; RNIT: 0, 1 => 4, 4, +; RNIT: 1, 2, 3, diff --git a/test/Analysis/RegionInfo/exit_in_condition.ll b/test/Analysis/RegionInfo/exit_in_condition.ll new file mode 100644 index 00000000000..b84abecc164 --- /dev/null +++ b/test/Analysis/RegionInfo/exit_in_condition.ll @@ -0,0 +1,38 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc zeroext i8 @handle_compress() nounwind { +entry: + br label %outer + +outer: + br label %body + +body: + br i1 1, label %body.i, label %if.end + +body.i: + br i1 1, label %end, label %if.end + +if.end: + br label %if.then64 + +if.then64: + br label %outer + +end: + ret i8 1 +} +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK-NEXT: [1] outer => end +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: entry, outer, body, body.i, end, if.end, if.then64, +; BBIT: outer, body, body.i, if.end, if.then64, + +; RNIT: entry, outer => end, end, +; RNIT: outer, body, body.i, if.end, if.then64, diff --git a/test/Analysis/RegionInfo/infinite_loop.ll b/test/Analysis/RegionInfo/infinite_loop.ll new file mode 100644 index 00000000000..8e588286a58 --- /dev/null +++ b/test/Analysis/RegionInfo/infinite_loop.ll @@ -0,0 +1,20 @@ +; RUN: opt -regions -analyze < %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s + +define void @normal_condition() nounwind { +0: + br label %"1" +1: + br i1 1, label %"2", label %"3" +2: + br label %"2" +3: + br label %"4" +4: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK: [1] 1 => 4 +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions diff --git a/test/Analysis/RegionInfo/infinite_loop_2.ll b/test/Analysis/RegionInfo/infinite_loop_2.ll new file mode 100644 index 00000000000..a8227e340c5 --- /dev/null +++ b/test/Analysis/RegionInfo/infinite_loop_2.ll @@ -0,0 +1,36 @@ +; RUN: opt -regions -analyze < %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"1" +1: + br i1 1, label %"2", label %"3" +2: + br label %"5" +5: + br i1 1, label %"11", label %"12" +11: + br label %"6" +12: + br label %"6" +6: + br label %"2" +3: + br label %"4" +4: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK: [1] 1 => 3 +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 0, 1, 2, 5, 11, 6, 12, 3, 4, +; BBIT: 1, 2, 5, 11, 6, 12, + +; RNIT: 0, 1 => 3, 3, 4, +; RNIT: 1, 2, 5, 11, 6, 12, diff --git a/test/Analysis/RegionInfo/infinite_loop_3.ll b/test/Analysis/RegionInfo/infinite_loop_3.ll new file mode 100644 index 00000000000..b09c9c1e591 --- /dev/null +++ b/test/Analysis/RegionInfo/infinite_loop_3.ll @@ -0,0 +1,52 @@ +; RUN: opt -regions -analyze < %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s + +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"7" +7: + br i1 1, label %"1", label %"8" +1: + br i1 1, label %"2", label %"3" +2: + br label %"5" +5: + br i1 1, label %"11", label %"12" +11: + br label %"6" +12: + br label %"6" +6: + br label %"2" +8: + br label %"9" +9: + br i1 1, label %"13", label %"14" +13: + br label %"10" +14: + br label %"10" +10: + br label %"8" +3: + br label %"4" +4: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 1 => 3 +; CHECK-NEXT: [1] 7 => 1 +; STAT: 3 region - The # of regions +; STAT: 2 region - The # of simple regions + +; BBIT: 0, 7, 1, 2, 5, 11, 6, 12, 3, 4, 8, 9, 13, 10, 14, +; BBIT: 7, 8, 9, 13, 10, 14, +; BBIT: 1, 2, 5, 11, 6, 12, + +; RNIT: 0, 7 => 1, 1 => 3, 3, 4, +; RNIT: 7, 8, 9, 13, 10, 14, +; RNIT: 1, 2, 5, 11, 6, 12, diff --git a/test/Analysis/RegionInfo/infinite_loop_4.ll b/test/Analysis/RegionInfo/infinite_loop_4.ll new file mode 100644 index 00000000000..681c305ce97 --- /dev/null +++ b/test/Analysis/RegionInfo/infinite_loop_4.ll @@ -0,0 +1,48 @@ +; RUN: opt -regions -analyze < %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"7" +7: + br i1 1, label %"1", label %"8" +1: + br i1 1, label %"2", label %"3" +2: + br label %"5" +5: + br i1 1, label %"11", label %"12" +11: + br label %"6" +12: + br label %"6" +6: + br i1 1, label %"2", label %"10" +8: + br label %"9" +9: + br i1 1, label %"13", label %"14" +13: + br label %"10" +14: + br label %"10" +10: + br label %"8" +3: + br label %"4" +4: + ret void +} +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 7 => 3 +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 0, 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12, 3, 4, +; BBIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12, + +; RNIT: 0, 7 => 3, 3, 4, +; RNIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12, diff --git a/test/Analysis/RegionInfo/lit.local.cfg b/test/Analysis/RegionInfo/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/RegionInfo/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/RegionInfo/loop_with_condition.ll b/test/Analysis/RegionInfo/loop_with_condition.ll new file mode 100644 index 00000000000..08d2ba8e35a --- /dev/null +++ b/test/Analysis/RegionInfo/loop_with_condition.ll @@ -0,0 +1,46 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s + +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition() nounwind { +0: + br label %"1" +1: + br i1 1, label %"6", label %"2" +2: + br i1 1, label %"3", label %"4" +3: + br label %"5" +4: + br label %"5" +5: + br label %"8" +8: + br i1 1, label %"7", label %"9" +9: + br label %"2" +7: + br label %"6" +6: + ret void +} + +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 1 => 6 +; CHECK-NEXT: [2] 2 => 7 +; CHECK-NEXT: [3] 2 => 5 +; STAT: 4 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 0, 1, 6, 2, 3, 5, 8, 7, 9, 4, +; BBIT: 1, 2, 3, 5, 8, 7, 9, 4, +; BBIT: 2, 3, 5, 8, 9, 4, +; BBIT: 2, 3, 4, + +; RNIT: 0, 1 => 6, 6, +; RNIT: 1, 2 => 7, 7, +; RNIT: 2 => 5, 5, 8, 9, +; RNIT: 2, 3, 4, diff --git a/test/Analysis/RegionInfo/loops_1.ll b/test/Analysis/RegionInfo/loops_1.ll new file mode 100644 index 00000000000..6449949df84 --- /dev/null +++ b/test/Analysis/RegionInfo/loops_1.ll @@ -0,0 +1,40 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc zeroext i8 @loops_1() nounwind { +entry: + br i1 1, label %outer , label %a + +a: + br label %body + +outer: + br label %body + +body: + br i1 1, label %land, label %if + +land: + br i1 1, label %exit, label %end + +exit: + br i1 1, label %if, label %end + +if: + br label %outer + +end: + ret i8 1 +} +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK-NEXT: [1] entry => end +; STAT: 2 region - The # of regions + +; BBIT: entry, outer, body, land, exit, if, end, a, +; BBIT: entry, outer, body, land, exit, if, a, + +; RNIT: entry => end, end, +; RNIT: entry, outer, body, land, exit, if, a, diff --git a/test/Analysis/RegionInfo/loops_2.ll b/test/Analysis/RegionInfo/loops_2.ll new file mode 100644 index 00000000000..dc4a1adffba --- /dev/null +++ b/test/Analysis/RegionInfo/loops_2.ll @@ -0,0 +1,49 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @meread_() nounwind { +entry: + br label %bb23 + +bb23: + br label %bb.i + +bb.i: ; preds = %bb.i, %bb54 + br label %pflini_.exit + +pflini_.exit: ; preds = %bb.i + br label %bb58thread-split + +bb58thread-split: ; preds = %bb64, %bb61, %pflini_.exit + br label %bb58 + +bb58: ; preds = %bb60, %bb58thread-split + br i1 1, label %bb59, label %bb23 + +bb59: ; preds = %bb58 + switch i32 1, label %bb60 [ + i32 1, label %l98 + ] + +bb60: ; preds = %bb59 + br i1 1, label %bb61, label %bb58 + +bb61: ; preds = %bb60 + br label %bb58thread-split + +l98: ; preds = %bb69, %bb59 + ret void +} +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK: [1] bb23 => l98 +; STAT: 2 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: entry, bb23, bb.i, pflini_.exit, bb58thread-split, bb58, bb59, bb60, bb61, l98, +; BBIT: bb23, bb.i, pflini_.exit, bb58thread-split, bb58, bb59, bb60, bb61, + +; RNIT: entry, bb23 => l98, l98, +; RNIT: bb23, bb.i, pflini_.exit, bb58thread-split, bb58, bb59, bb60, bb61, diff --git a/test/Analysis/RegionInfo/mix_1.ll b/test/Analysis/RegionInfo/mix_1.ll new file mode 100644 index 00000000000..1474e033e57 --- /dev/null +++ b/test/Analysis/RegionInfo/mix_1.ll @@ -0,0 +1,69 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s + +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @a_linear_impl_fig_1() nounwind { +0: + + br i1 1, label %"1", label %"15" +1: + switch i32 0, label %"2" [ i32 0, label %"3" + i32 1, label %"7"] +2: + br label %"4" +3: + br label %"5" +4: + br label %"6" +5: + br label %"6" +6: + br label %"7" +7: + br label %"15" +15: + br label %"8" +8: + br label %"16" +16: + br label %"9" +9: + br i1 1, label %"10", label %"11" +11: + br i1 1, label %"13", label %"12" +13: + br label %"14" +12: + br label %"14" +14: + br label %"8" +10: + br label %"17" +17: + br label %"18" +18: + ret void +} + +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 0 => 15 +; CHECK-NEXT: [2] 1 => 7 +; CHECK-NEXT: [1] 8 => 10 +; CHECK-NEXT: [2] 11 => 14 +; STAT: 5 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 0, 1, 2, 4, 6, 7, 15, 8, 16, 9, 10, 17, 18, 11, 13, 14, 12, 3, 5, +; BBIT: 0, 1, 2, 4, 6, 7, 3, 5, +; BBIT: 1, 2, 4, 6, 3, 5, +; BBIT: 8, 16, 9, 11, 13, 14, 12, +; BBIT: 11, 13, 12, + +; RNIT: 0 => 15, 15, 8 => 10, 10, 17, 18, +; RNIT: 0, 1 => 7, 7, +; RNIT: 1, 2, 4, 6, 3, 5, +; RNIT: 8, 16, 9, 11 => 14, 14, +; RNIT: 11, 13, 12, diff --git a/test/Analysis/RegionInfo/multiple_exiting_edge.ll b/test/Analysis/RegionInfo/multiple_exiting_edge.ll new file mode 100644 index 00000000000..8de64722994 --- /dev/null +++ b/test/Analysis/RegionInfo/multiple_exiting_edge.ll @@ -0,0 +1,38 @@ +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @normal_condition_0() nounwind { +bb38: ; preds = %bb34, %bb34, %bb37 + switch i32 undef, label %bb42 [ + i32 67, label %bb42 + i32 90, label %bb41 + ] +bb41: ; preds = %bb38 + br label %bb42 +bb42: ; preds = %bb38, %bb38, %bb41 + ret void +} + +; BBIT: bb38, bb42, bb41, +; BBIT: bb38, bb41, + +; RNIT: bb38 => bb42, bb42, +; RNIT: bb38, bb41, + +define void @normal_condition_1() nounwind { +bb38: ; preds = %bb34, %bb34, %bb37 + switch i32 undef, label %bb41 [ + i32 67, label %bb42 + i32 90, label %bb42 + ] +bb41: ; preds = %bb38 + br label %bb42 +bb42: ; preds = %bb38, %bb38, %bb41 + ret void +} + +; BBIT: bb38, bb41, bb42, +; BBIT: bb38, bb41, + +; RNIT: bb38 => bb42, bb42, +; RNIT: bb38, bb41, diff --git a/test/Analysis/RegionInfo/nested_loops.ll b/test/Analysis/RegionInfo/nested_loops.ll new file mode 100644 index 00000000000..a3707a19872 --- /dev/null +++ b/test/Analysis/RegionInfo/nested_loops.ll @@ -0,0 +1,33 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s + +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc zeroext i8 @handle_compress() nounwind { +entry: + br label %outer + +outer: + br label %body + +body: + br i1 1, label %exit172, label %end + +exit172: + br i1 1, label %end, label %outer + +end: + ret i8 1 +} +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK-NEXT: [1] outer => end + +; STAT: 2 region - The # of regions + +; BBIT: entry, outer, body, exit172, end, +; BBIT: outer, body, exit172, + +; RNIT: entry, outer => end, end, +; RNIT: outer, body, exit172, diff --git a/test/Analysis/RegionInfo/next.ll b/test/Analysis/RegionInfo/next.ll new file mode 100644 index 00000000000..890b4f23001 --- /dev/null +++ b/test/Analysis/RegionInfo/next.ll @@ -0,0 +1,49 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @MAIN__() nounwind { +entry: + br label %__label_002001.outer + +__label_002001.outer: ; preds = %bb236, %bb92 + br label %__label_002001 + +__label_002001: ; preds = %bb229, %__label_002001.outer + br i1 1, label %bb93, label %__label_000020 + +bb93: ; preds = %__label_002001 + br i1 1, label %__label_000020, label %bb197 + +bb197: ; preds = %bb193 + br i1 1, label %bb229, label %bb224 + +bb224: ; preds = %bb223, %bb227 + br i1 1, label %bb229, label %bb224 + +bb229: ; preds = %bb227, %bb223 + br i1 1, label %__label_002001, label %__label_002001.outer + +__label_000020: ; preds = %__label_002001, %bb194 + ret void +} + +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK-NEXT: [1] __label_002001.outer => __label_000020 +; CHECK-NEXT: [2] bb197 => bb229 +; CHECK-NEXT: [3] bb224 => bb229 + +; STAT: 4 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: entry, __label_002001.outer, __label_002001, bb93, __label_000020, bb197, bb229, bb224, +; BBIT: __label_002001.outer, __label_002001, bb93, bb197, bb229, bb224, +; BBIT: bb197, bb224, +; BBIT: bb224, + +; RNIT: entry, __label_002001.outer => __label_000020, __label_000020, +; RNIT: __label_002001.outer, __label_002001, bb93, bb197 => bb229, bb229, +; RNIT: bb197, bb224 => bb229, +; RNIT: bb224, diff --git a/test/Analysis/RegionInfo/paper.ll b/test/Analysis/RegionInfo/paper.ll new file mode 100644 index 00000000000..96c87e0559b --- /dev/null +++ b/test/Analysis/RegionInfo/paper.ll @@ -0,0 +1,55 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define void @a_linear_impl_fig_1() nounwind { +0: + br label %"1" +1: + br label %"2" +2: + br label %"3" +3: + br i1 1, label %"13", label %"4" +4: + br i1 1, label %"5", label %"1" +5: + br i1 1, label %"8", label %"6" +6: + br i1 1, label %"7", label %"4" +7: + ret void +8: + br i1 1, label %"9", label %"1" +9: + br label %"10" +10: + br i1 1, label %"12", label %"11" +11: + br i1 1, label %"9", label %"8" +13: + br i1 1, label %"2", label %"1" +12: + switch i32 0, label %"1" [ i32 0, label %"9" + i32 1, label %"8"] +} + +; CHECK-NOT: => +; CHECK: [0] 0 => <Function Return> +; CHECK-NEXT: [1] 1 => 7 +; CHECK-NEXT: [2] 1 => 4 +; CHECK-NEXT: [2] 8 => 1 + +; STAT: 4 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: 0, 1, 2, 3, 13, 4, 5, 8, 9, 10, 12, 11, 6, 7, +; BBIT: 1, 2, 3, 13, 4, 5, 8, 9, 10, 12, 11, 6, +; BBIT: 1, 2, 3, 13, +; BBIT: 8, 9, 10, 12, 11, + +; RNIT: 0, 1 => 7, 7, +; RNIT: 1 => 4, 4, 5, 8 => 1, 6, +; RNIT: 1, 2, 3, 13, +; RNIT: 8, 9, 10, 12, 11, diff --git a/test/Analysis/RegionInfo/two_loops_same_header.ll b/test/Analysis/RegionInfo/two_loops_same_header.ll new file mode 100644 index 00000000000..e75661e8905 --- /dev/null +++ b/test/Analysis/RegionInfo/two_loops_same_header.ll @@ -0,0 +1,46 @@ +; RUN: opt -regions -analyze < %s | FileCheck %s +; RUN: opt -regions -stats < %s 2>&1 | FileCheck -check-prefix=STAT %s +; RUN: opt -regions -print-region-style=bb -analyze < %s 2>&1 | FileCheck -check-prefix=BBIT %s +; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s + +define internal fastcc zeroext i8 @handle_compress() nounwind { +entry: + br label %outer + +outer: + br label %body + +body: + br i1 1, label %else, label %true77 + +true77: + br i1 1, label %then83, label %else + +then83: + br label %outer + +else: + br label %else106 + +else106: + br i1 1, label %end, label %outer + +end: + ret i8 1 +} + +; CHECK-NOT: => +; CHECK: [0] entry => <Function Return> +; CHECK-NEXT: [1] outer => end +; CHECK-NEXT: [2] outer => else + +; STAT: 3 region - The # of regions +; STAT: 1 region - The # of simple regions + +; BBIT: entry, outer, body, else, else106, end, true77, then83, +; BBIT: outer, body, else, else106, true77, then83, +; BBIT: outer, body, true77, then83, + +; RNIT: entry, outer => end, end, +; RNIT: outer => else, else, else106, +; RNIT: outer, body, true77, then83, diff --git a/test/Analysis/ScalarEvolution/2007-07-15-NegativeStride.ll b/test/Analysis/ScalarEvolution/2007-07-15-NegativeStride.ll new file mode 100644 index 00000000000..e0c5583cbb9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-07-15-NegativeStride.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep "Loop %bb: backedge-taken count is 100" +; PR1533 + +@array = weak global [101 x i32] zeroinitializer, align 32 ; <[100 x i32]*> [#uses=1] + +define void @loop(i32 %x) { +entry: + br label %bb + +bb: ; preds = %bb, %entry + %i.01.0 = phi i32 [ 100, %entry ], [ %tmp4, %bb ] ; <i32> [#uses=2] + %tmp1 = getelementptr [101 x i32]* @array, i32 0, i32 %i.01.0 ; <i32*> [#uses=1] + store i32 %x, i32* %tmp1 + %tmp4 = add i32 %i.01.0, -1 ; <i32> [#uses=2] + %tmp7 = icmp sgt i32 %tmp4, -1 ; <i1> [#uses=1] + br i1 %tmp7, label %bb, label %return + +return: ; preds = %bb + ret void +} diff --git a/test/Analysis/ScalarEvolution/2007-08-06-MisinterpretBranch.ll b/test/Analysis/ScalarEvolution/2007-08-06-MisinterpretBranch.ll new file mode 100644 index 00000000000..e67e4d00d62 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-08-06-MisinterpretBranch.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -indvars -adce -simplifycfg -S | grep "icmp s" +; PR1598 + +define i32 @f(i32 %a, i32 %b, i32 %x, i32 %y) { +entry: + %tmp3 = icmp eq i32 %a, %b ; <i1> [#uses=1] + br i1 %tmp3, label %return, label %bb + +bb: ; preds = %bb, %entry + %x_addr.0 = phi i32 [ %tmp6, %bb ], [ %x, %entry ] ; <i32> [#uses=1] + %tmp6 = add i32 %x_addr.0, 1 ; <i32> [#uses=3] + %tmp9 = icmp slt i32 %tmp6, %y ; <i1> [#uses=1] + br i1 %tmp9, label %bb, label %return + +return: ; preds = %bb, %entry + %x_addr.1 = phi i32 [ %x, %entry ], [ %tmp6, %bb ] ; <i32> [#uses=1] + ret i32 %x_addr.1 +} diff --git a/test/Analysis/ScalarEvolution/2007-08-06-Unsigned.ll b/test/Analysis/ScalarEvolution/2007-08-06-Unsigned.ll new file mode 100644 index 00000000000..036abf5b7c1 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-08-06-Unsigned.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -scalar-evolution -analyze | grep "Loop %bb: backedge-taken count is (-1 + (-1 \* %x) + %y)" +; PR1597 + +define i32 @f(i32 %x, i32 %y) { +entry: + %tmp63 = icmp ult i32 %x, %y ; <i1> [#uses=1] + br i1 %tmp63, label %bb.preheader, label %bb8 + +bb.preheader: ; preds = %entry + br label %bb + +bb: ; preds = %bb3, %bb.preheader + %x_addr.0 = phi i32 [ %tmp2, %bb3 ], [ %x, %bb.preheader ] ; <i32> [#uses=1] + %tmp2 = add i32 %x_addr.0, 1 ; <i32> [#uses=3] + br label %bb3 + +bb3: ; preds = %bb + %tmp6 = icmp ult i32 %tmp2, %y ; <i1> [#uses=1] + br i1 %tmp6, label %bb, label %bb8.loopexit + +bb8.loopexit: ; preds = %bb3 + br label %bb8 + +bb8: ; preds = %bb8.loopexit, %entry + %x_addr.1 = phi i32 [ %x, %entry ], [ %tmp2, %bb8.loopexit ] ; <i32> [#uses=1] + br label %return + +return: ; preds = %bb8 + ret i32 %x_addr.1 +} diff --git a/test/Analysis/ScalarEvolution/2007-09-27-LargeStepping.ll b/test/Analysis/ScalarEvolution/2007-09-27-LargeStepping.ll new file mode 100644 index 00000000000..a3192b9c01f --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-09-27-LargeStepping.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep "backedge-taken count is 13" +; PR1706 + +define i32 @f() { +entry: + br label %bb5 + +bb: ; preds = %bb5 + %tmp2 = shl i32 %j.0, 1 ; <i32> [#uses=1] + %tmp4 = add i32 %i.0, 268435456 ; <i32> [#uses=1] + br label %bb5 + +bb5: ; preds = %bb, %entry + %j.0 = phi i32 [ 1, %entry ], [ %tmp2, %bb ] ; <i32> [#uses=2] + %i.0 = phi i32 [ -1879048192, %entry ], [ %tmp4, %bb ] ; <i32> [#uses=2] + %tmp7 = icmp slt i32 %i.0, 1610612736 ; <i1> [#uses=1] + br i1 %tmp7, label %bb, label %return + +return: ; preds = %bb5 + ret i32 %j.0 +} diff --git a/test/Analysis/ScalarEvolution/2007-11-14-SignedAddRec.ll b/test/Analysis/ScalarEvolution/2007-11-14-SignedAddRec.ll new file mode 100644 index 00000000000..514920f0f6f --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-11-14-SignedAddRec.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -indvars -S | grep printd | grep 1206807378 +; PR1798 + +declare void @printd(i32) + +define i32 @test() { +entry: + br label %bb6 + +bb: ; preds = %bb6 + %tmp3 = add i32 %x.0, %i.0 ; <i32> [#uses=1] + %tmp5 = add i32 %i.0, 1 ; <i32> [#uses=1] + br label %bb6 + +bb6: ; preds = %bb, %entry + %i.0 = phi i32 [ 0, %entry ], [ %tmp5, %bb ] ; <i32> [#uses=3] + %x.0 = phi i32 [ 0, %entry ], [ %tmp3, %bb ] ; <i32> [#uses=3] + %tmp8 = icmp slt i32 %i.0, 123456789 ; <i1> [#uses=1] + br i1 %tmp8, label %bb, label %bb10 + +bb10: ; preds = %bb6 + call void @printd(i32 %x.0) + ret i32 0 +} diff --git a/test/Analysis/ScalarEvolution/2007-11-18-OrInstruction.ll b/test/Analysis/ScalarEvolution/2007-11-18-OrInstruction.ll new file mode 100644 index 00000000000..c12721d82f0 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2007-11-18-OrInstruction.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s +; PR1810 + +define void @fun() { +entry: + br label %header +header: + %i = phi i32 [ 1, %entry ], [ %i.next, %body ] + %cond = icmp eq i32 %i, 10 + br i1 %cond, label %exit, label %body +body: + %a = mul i32 %i, 5 + %b = or i32 %a, 1 + %i.next = add i32 %i, 1 + br label %header +exit: + ret void +} + +; CHECK: --> %b + diff --git a/test/Analysis/ScalarEvolution/2008-02-11-ReversedCondition.ll b/test/Analysis/ScalarEvolution/2008-02-11-ReversedCondition.ll new file mode 100644 index 00000000000..d0644f7b3f9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-02-11-ReversedCondition.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -scalar-evolution -analyze | grep "Loop %header: backedge-taken count is (0 smax %n)" + +define void @foo(i32 %n) { +entry: + br label %header +header: + %i = phi i32 [ 0, %entry ], [ %i.inc, %next ] + %cond = icmp sgt i32 %n, %i + br i1 %cond, label %next, label %return +next: + %i.inc = add i32 %i, 1 + br label %header +return: + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-02-12-SMAXTripCount.ll b/test/Analysis/ScalarEvolution/2008-02-12-SMAXTripCount.ll new file mode 100644 index 00000000000..ce0329d9ce8 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-02-12-SMAXTripCount.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s +; PR2002 + +; CHECK: Loop %loop: backedge-taken count is (100 + (-100 smax %n)) +define void @foo(i8 %n) { +entry: + br label %loop +loop: + %i = phi i8 [ -100, %entry ], [ %i.inc, %next ] + %cond = icmp slt i8 %i, %n + br i1 %cond, label %next, label %return +next: + %i.inc = add i8 %i, 1 + br label %loop +return: + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-02-15-UMax.ll b/test/Analysis/ScalarEvolution/2008-02-15-UMax.ll new file mode 100644 index 00000000000..52c7985045d --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-02-15-UMax.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep umax +; PR2003 + +define i32 @foo(i32 %n) { +entry: + br label %header +header: + %i = phi i32 [ 100, %entry ], [ %i.inc, %next ] + %cond = icmp ult i32 %i, %n + br i1 %cond, label %next, label %return +next: + %i.inc = add i32 %i, 1 + br label %header +return: + ret i32 %i +} + diff --git a/test/Analysis/ScalarEvolution/2008-05-25-NegativeStepToZero.ll b/test/Analysis/ScalarEvolution/2008-05-25-NegativeStepToZero.ll new file mode 100644 index 00000000000..41734d70f07 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-05-25-NegativeStepToZero.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep "backedge-taken count is 61" +; PR2364 + +define i32 @func_6() nounwind { +entry: + br label %bb5 + +bb: ; preds = %bb5 + %tmp2 = add i32 %i.0, 1 ; <i32> [#uses=1] + %tmp4 = add i8 %x.0, -4 ; <i8> [#uses=1] + br label %bb5 + +bb5: ; preds = %bb, %entry + %x.0 = phi i8 [ 0, %entry ], [ %tmp4, %bb ] ; <i8> [#uses=2] + %i.0 = phi i32 [ 0, %entry ], [ %tmp2, %bb ] ; <i32> [#uses=2] + %tmp7 = icmp eq i8 %x.0, 12 ; <i1> [#uses=1] + br i1 %tmp7, label %return, label %bb + +return: ; preds = %bb5 + ret i32 %i.0 +} diff --git a/test/Analysis/ScalarEvolution/2008-06-12-BinomialInt64.ll b/test/Analysis/ScalarEvolution/2008-06-12-BinomialInt64.ll new file mode 100644 index 00000000000..d503329292c --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-06-12-BinomialInt64.ll @@ -0,0 +1,43 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>/dev/null +; PR2433 + +define i32 @main1(i32 %argc, i8** %argv) nounwind { +entry: + br i1 false, label %bb10, label %bb23 + +bb10: ; preds = %bb10, %entry + %accum.03 = phi i64 [ %tmp14, %bb10 ], [ 0, %entry ] ; <i64> [#uses=1] + %i.02 = phi i32 [ %tmp16, %bb10 ], [ 0, %entry ] ; <i32> [#uses=1] + %d.1.01 = phi i64 [ %tmp5.i, %bb10 ], [ 0, %entry ] ; <i64> [#uses=1] + %tmp5.i = add i64 %d.1.01, 1 ; <i64> [#uses=2] + %tmp14 = add i64 %accum.03, %tmp5.i ; <i64> [#uses=2] + %tmp16 = add i32 %i.02, 1 ; <i32> [#uses=2] + %tmp20 = icmp slt i32 %tmp16, 0 ; <i1> [#uses=1] + br i1 %tmp20, label %bb10, label %bb23 + +bb23: ; preds = %bb10, %entry + %accum.0.lcssa = phi i64 [ 0, %entry ], [ %tmp14, %bb10 ] ; <i64> [#uses=0] + ret i32 0 +} + +define i32 @main2(i32 %argc, i8** %argv) { +entry: + %tmp8 = tail call i32 @atoi( i8* null ) nounwind readonly ; <i32> [#uses=1] + br i1 false, label %bb9, label %bb21 + +bb9: ; preds = %bb9, %entry + %accum.03 = phi i64 [ %tmp12, %bb9 ], [ 0, %entry ] ; <i64> [#uses=1] + %i.02 = phi i32 [ %tmp14, %bb9 ], [ 0, %entry ] ; <i32> [#uses=1] + %d.1.01 = phi i64 [ %tmp4.i, %bb9 ], [ 0, %entry ] ; <i64> [#uses=1] + %tmp4.i = add i64 %d.1.01, 1 ; <i64> [#uses=2] + %tmp12 = add i64 %accum.03, %tmp4.i ; <i64> [#uses=2] + %tmp14 = add i32 %i.02, 1 ; <i32> [#uses=2] + %tmp18 = icmp slt i32 %tmp14, %tmp8 ; <i1> [#uses=1] + br i1 %tmp18, label %bb9, label %bb21 + +bb21: ; preds = %bb9, %entry + %accum.0.lcssa = phi i64 [ 0, %entry ], [ %tmp12, %bb9 ] ; <i64> [#uses=0] + ret i32 0 +} + +declare i32 @atoi(i8*) nounwind readonly diff --git a/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect1.ll b/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect1.ll new file mode 100644 index 00000000000..5cf17a21014 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect1.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | not grep smax +; PR2261 + +@lut = common global [256 x i8] zeroinitializer, align 32 ; <[256 x i8]*> [#uses=1] + +define void @foo(i32 %count, i32* %srcptr, i32* %dstptr) nounwind { +entry: + icmp sgt i32 %count, 0 ; <i1>:0 [#uses=1] + br i1 %0, label %bb.nph, label %return + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %j.01 = phi i32 [ %8, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=1] + load i32* %srcptr, align 4 ; <i32>:1 [#uses=2] + and i32 %1, 255 ; <i32>:2 [#uses=1] + and i32 %1, -256 ; <i32>:3 [#uses=1] + getelementptr [256 x i8]* @lut, i32 0, i32 %2 ; <i8*>:4 [#uses=1] + load i8* %4, align 1 ; <i8>:5 [#uses=1] + zext i8 %5 to i32 ; <i32>:6 [#uses=1] + or i32 %6, %3 ; <i32>:7 [#uses=1] + store i32 %7, i32* %dstptr, align 4 + add i32 %j.01, 1 ; <i32>:8 [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + icmp slt i32 %8, %count ; <i1>:9 [#uses=1] + br i1 %9, label %bb, label %bb1.return_crit_edge + +bb1.return_crit_edge: ; preds = %bb1 + br label %return + +return: ; preds = %bb1.return_crit_edge, %entry + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect2.ll b/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect2.ll new file mode 100644 index 00000000000..195dfaaaee9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-12-UnneededSelect2.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | not grep smax +; PR2070 + +define i32 @a(i32 %x) nounwind { +entry: + icmp sgt i32 %x, 1 ; <i1>:0 [#uses=1] + br i1 %0, label %bb.nph, label %bb2 + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %z.02 = phi i32 [ %1, %bb1 ], [ 1, %bb.nph ] ; <i32> [#uses=1] + %i.01 = phi i32 [ %2, %bb1 ], [ 1, %bb.nph ] ; <i32> [#uses=2] + mul i32 %z.02, %i.01 ; <i32>:1 [#uses=2] + add i32 %i.01, 1 ; <i32>:2 [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + icmp slt i32 %2, %x ; <i1>:3 [#uses=1] + br i1 %3, label %bb, label %bb1.bb2_crit_edge + +bb1.bb2_crit_edge: ; preds = %bb1 + %.lcssa = phi i32 [ %1, %bb1 ] ; <i32> [#uses=1] + br label %bb2 + +bb2: ; preds = %bb1.bb2_crit_edge, %entry + %z.0.lcssa = phi i32 [ %.lcssa, %bb1.bb2_crit_edge ], [ 1, %entry ] ; <i32> [#uses=1] + ret i32 %z.0.lcssa +} diff --git a/test/Analysis/ScalarEvolution/2008-07-19-InfiniteLoop.ll b/test/Analysis/ScalarEvolution/2008-07-19-InfiniteLoop.ll new file mode 100644 index 00000000000..1865c059a99 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-19-InfiniteLoop.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep Unpredictable +; PR2088 + +define void @fun() { +entry: + br label %loop +loop: + %i = phi i8 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i8 %i, 4 + %cond = icmp ne i8 %i.next, 6 + br i1 %cond, label %loop, label %exit +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-07-19-WrappingIV.ll b/test/Analysis/ScalarEvolution/2008-07-19-WrappingIV.ll new file mode 100644 index 00000000000..cbf200e40f9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-19-WrappingIV.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep "backedge-taken count is 113" +; PR2088 + +define void @fun() { +entry: + br label %loop +loop: + %i = phi i8 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i8 %i, 18 + %cond = icmp ne i8 %i.next, 4 + br i1 %cond, label %loop, label %exit +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-07-29-SGTTripCount.ll b/test/Analysis/ScalarEvolution/2008-07-29-SGTTripCount.ll new file mode 100644 index 00000000000..75bd634b3ef --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-29-SGTTripCount.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | FileCheck %s +; PR2607 + +define i32 @_Z1aj(i32 %j) nounwind { +entry: + icmp sgt i32 0, %j ; <i1>:0 [#uses=1] + br i1 %0, label %bb.preheader, label %return + +bb.preheader: ; preds = %entry + br label %bb + +bb: ; preds = %bb, %bb.preheader + %i.01 = phi i32 [ %1, %bb ], [ 0, %bb.preheader ] ; <i32> [#uses=1] + add i32 %i.01, -1 ; <i32>:1 [#uses=3] + icmp sgt i32 %1, %j ; <i1>:2 [#uses=1] + br i1 %2, label %bb, label %return.loopexit + +return.loopexit: ; preds = %bb + br label %return + +return: ; preds = %return.loopexit, %entry + %i.0.lcssa = phi i32 [ 0, %entry ], [ %1, %return.loopexit ] ; <i32> [#uses=1] + ret i32 %i.0.lcssa +} + +; CHECK: backedge-taken count is (-1 + (-1 * %j)) + diff --git a/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll b/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll new file mode 100644 index 00000000000..3542ad2a41e --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | FileCheck %s +; PR2607 + +define i32 @b(i32 %x, i32 %y) nounwind { +entry: + %cmp2 = icmp slt i32 %y, %x + %cond3 = select i1 %cmp2, i32 %y, i32 %x + %cmp54 = icmp slt i32 %cond3, -2147483632 + br i1 %cmp54, label %forinc, label %afterfor + +forinc: ; preds = %forinc, %entry + %j.01 = phi i32 [ %dec, %forinc ], [ -2147483632, %entry ] + %dec = add i32 %j.01, -1 + %cmp = icmp slt i32 %y, %x + %cond = select i1 %cmp, i32 %y, i32 %x + %cmp5 = icmp sgt i32 %dec, %cond + br i1 %cmp5, label %forinc, label %afterfor + +afterfor: ; preds = %forinc, %entry + %j.0.lcssa = phi i32 [ -2147483632, %entry ], [ %dec, %forinc ] + ret i32 %j.0.lcssa +} + +; CHECK: backedge-taken count is (-2147483632 + ((-1 + (-1 * %{{[xy]}})) smax (-1 + (-1 * %{{[xy]}})))) + diff --git a/test/Analysis/ScalarEvolution/2008-08-04-IVOverflow.ll b/test/Analysis/ScalarEvolution/2008-08-04-IVOverflow.ll new file mode 100644 index 00000000000..3b31d797cf4 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-08-04-IVOverflow.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | FileCheck %s +; PR2621 + +define i32 @a() nounwind { +entry: + br label %bb1 + +bb: + trunc i32 %i.0 to i16 + add i16 %0, %x16.0 + add i32 %i.0, 1 + br label %bb1 + +bb1: + %i.0 = phi i32 [ 0, %entry ], [ %2, %bb ] + %x16.0 = phi i16 [ 0, %entry ], [ %1, %bb ] + icmp ult i32 %i.0, 888888 + br i1 %3, label %bb, label %bb2 + +bb2: + zext i16 %x16.0 to i32 + ret i32 %4 +} + +; CHECK: Exits: 20028 + diff --git a/test/Analysis/ScalarEvolution/2008-08-04-LongAddRec.ll b/test/Analysis/ScalarEvolution/2008-08-04-LongAddRec.ll new file mode 100644 index 00000000000..b296a19716c --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-08-04-LongAddRec.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | FileCheck %s +; PR2621 + +define i32 @a() nounwind { +entry: + br label %bb1 + +bb: ; preds = %bb1 + add i16 %x17.0, 1 ; <i16>:0 [#uses=2] + add i16 %0, %x16.0 ; <i16>:1 [#uses=2] + add i16 %1, %x15.0 ; <i16>:2 [#uses=2] + add i16 %2, %x14.0 ; <i16>:3 [#uses=2] + add i16 %3, %x13.0 ; <i16>:4 [#uses=2] + add i16 %4, %x12.0 ; <i16>:5 [#uses=2] + add i16 %5, %x11.0 ; <i16>:6 [#uses=2] + add i16 %6, %x10.0 ; <i16>:7 [#uses=2] + add i16 %7, %x9.0 ; <i16>:8 [#uses=2] + add i16 %8, %x8.0 ; <i16>:9 [#uses=2] + add i16 %9, %x7.0 ; <i16>:10 [#uses=2] + add i16 %10, %x6.0 ; <i16>:11 [#uses=2] + add i16 %11, %x5.0 ; <i16>:12 [#uses=2] + add i16 %12, %x4.0 ; <i16>:13 [#uses=2] + add i16 %13, %x3.0 ; <i16>:14 [#uses=2] + add i16 %14, %x2.0 ; <i16>:15 [#uses=2] + add i16 %15, %x1.0 ; <i16>:16 [#uses=1] + add i32 %i.0, 1 ; <i32>:17 [#uses=1] + br label %bb1 + +bb1: ; preds = %bb, %entry + %x2.0 = phi i16 [ 0, %entry ], [ %15, %bb ] ; <i16> [#uses=1] + %x3.0 = phi i16 [ 0, %entry ], [ %14, %bb ] ; <i16> [#uses=1] + %x4.0 = phi i16 [ 0, %entry ], [ %13, %bb ] ; <i16> [#uses=1] + %x5.0 = phi i16 [ 0, %entry ], [ %12, %bb ] ; <i16> [#uses=1] + %x6.0 = phi i16 [ 0, %entry ], [ %11, %bb ] ; <i16> [#uses=1] + %x7.0 = phi i16 [ 0, %entry ], [ %10, %bb ] ; <i16> [#uses=1] + %x8.0 = phi i16 [ 0, %entry ], [ %9, %bb ] ; <i16> [#uses=1] + %x9.0 = phi i16 [ 0, %entry ], [ %8, %bb ] ; <i16> [#uses=1] + %x10.0 = phi i16 [ 0, %entry ], [ %7, %bb ] ; <i16> [#uses=1] + %x11.0 = phi i16 [ 0, %entry ], [ %6, %bb ] ; <i16> [#uses=1] + %x12.0 = phi i16 [ 0, %entry ], [ %5, %bb ] ; <i16> [#uses=1] + %x13.0 = phi i16 [ 0, %entry ], [ %4, %bb ] ; <i16> [#uses=1] + %x14.0 = phi i16 [ 0, %entry ], [ %3, %bb ] ; <i16> [#uses=1] + %x15.0 = phi i16 [ 0, %entry ], [ %2, %bb ] ; <i16> [#uses=1] + %x16.0 = phi i16 [ 0, %entry ], [ %1, %bb ] ; <i16> [#uses=1] + %x17.0 = phi i16 [ 0, %entry ], [ %0, %bb ] ; <i16> [#uses=1] + %i.0 = phi i32 [ 0, %entry ], [ %17, %bb ] ; <i32> [#uses=2] + %x1.0 = phi i16 [ 0, %entry ], [ %16, %bb ] ; <i16> [#uses=2] + icmp ult i32 %i.0, 8888 ; <i1>:18 [#uses=1] + br i1 %18, label %bb, label %bb2 + +bb2: ; preds = %bb1 + zext i16 %x1.0 to i32 ; <i32>:19 [#uses=1] + ret i32 %19 +} + +; CHECK: Exits: -19168 + diff --git a/test/Analysis/ScalarEvolution/2008-11-02-QuadraticCrash.ll b/test/Analysis/ScalarEvolution/2008-11-02-QuadraticCrash.ll new file mode 100644 index 00000000000..7722122117d --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-11-02-QuadraticCrash.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -analyze -scalar-evolution +; PR1827 + +declare void @use(i32) + +define void @foo() { +entry: + br label %loop_1 + +loop_1: ; preds = %loop_1, %entry + %a = phi i32 [ 2, %entry ], [ %b, %loop_1 ] ; <i32> [#uses=2] + %c = phi i32 [ 5, %entry ], [ %d, %loop_1 ] ; <i32> [#uses=1] + %b = add i32 %a, 1 ; <i32> [#uses=1] + %d = add i32 %c, %a ; <i32> [#uses=3] + %A = icmp ult i32 %d, 50 ; <i1> [#uses=1] + br i1 %A, label %loop_1, label %endloop + +endloop: ; preds = %loop_1 + call void @use(i32 %d) + ret void +} diff --git a/test/Analysis/ScalarEvolution/2008-11-15-CubicOOM.ll b/test/Analysis/ScalarEvolution/2008-11-15-CubicOOM.ll new file mode 100644 index 00000000000..2e2aabc475a --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-11-15-CubicOOM.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -analyze -scalar-evolution +; PR2602 + +define i32 @a() nounwind { +entry: + br label %bb + +bb: ; preds = %bb, %entry + %w.0 = phi i32 [ 0, %entry ], [ %tmp, %bb ] ; <i32> [#uses=2] + %e.0 = phi i32 [ 0, %entry ], [ %e.1, %bb ] ; <i32> [#uses=2] + %w.1 = add i32 0, %w.0 ; <i32>:0 [#uses=1] + %tmp = add i32 %e.0, %w.0 ; <i32>:1 [#uses=1] + %e.1 = add i32 %e.0, 1 ; <i32>:2 [#uses=1] + %cond = icmp eq i32 %w.1, -1 ; <i1>:3 [#uses=1] + br i1 %cond, label %return, label %bb + +return: ; preds = %bb + ret i32 undef +} diff --git a/test/Analysis/ScalarEvolution/2008-11-18-LessThanOrEqual.ll b/test/Analysis/ScalarEvolution/2008-11-18-LessThanOrEqual.ll new file mode 100644 index 00000000000..c25e4a3b2b2 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-11-18-LessThanOrEqual.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | \ +; RUN: grep "Loop %bb: backedge-taken count is (7 + (-1 \* %argc))" + +define i32 @main(i32 %argc, i8** %argv) nounwind { +entry: + %0 = icmp ugt i32 %argc, 7 ; <i1> [#uses=1] + br i1 %0, label %bb2, label %bb.nph + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb.nph, %bb1 + %indvar = phi i32 [ 0, %bb.nph ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %argc_addr.04 = add i32 %indvar, %argc ; <i32> [#uses=1] + tail call void (...)* @Test() nounwind + %1 = add i32 %argc_addr.04, 1 ; <i32> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb + %phitmp = icmp ugt i32 %1, 7 ; <i1> [#uses=1] + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br i1 %phitmp, label %bb1.bb2_crit_edge, label %bb + +bb1.bb2_crit_edge: ; preds = %bb1 + br label %bb2 + +bb2: ; preds = %bb1.bb2_crit_edge, %entry + ret i32 0 +} + +declare void @Test(...) diff --git a/test/Analysis/ScalarEvolution/2008-11-18-Stride1.ll b/test/Analysis/ScalarEvolution/2008-11-18-Stride1.ll new file mode 100644 index 00000000000..56a83438830 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-11-18-Stride1.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | grep "Loop %bb: Unpredictable backedge-taken count\." + +; ScalarEvolution can't compute a trip count because it doesn't know if +; dividing by the stride will have a remainder. This could theoretically +; be teaching it how to use a more elaborate trip count computation. + +define i32 @f(i32 %x) nounwind readnone { +entry: + %0 = icmp ugt i32 %x, 4 ; <i1> [#uses=1] + br i1 %0, label %bb.nph, label %bb2 + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb.nph, %bb1 + %indvar = phi i32 [ 0, %bb.nph ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %tmp = mul i32 %indvar, -3 ; <i32> [#uses=1] + %x_addr.04 = add i32 %tmp, %x ; <i32> [#uses=1] + %1 = add i32 %x_addr.04, -3 ; <i32> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %2 = icmp ugt i32 %1, 4 ; <i1> [#uses=1] + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br i1 %2, label %bb, label %bb1.bb2_crit_edge + +bb1.bb2_crit_edge: ; preds = %bb1 + %.lcssa = phi i32 [ %1, %bb1 ] ; <i32> [#uses=1] + br label %bb2 + +bb2: ; preds = %bb1.bb2_crit_edge, %entry + %x_addr.0.lcssa = phi i32 [ %.lcssa, %bb1.bb2_crit_edge ], [ %x, %entry ] ; <i32> [#uses=1] + ret i32 %x_addr.0.lcssa +} diff --git a/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll b/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll new file mode 100644 index 00000000000..aaf6770676b --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | grep "/u 3" +; XFAIL: * + +; This is a tricky testcase for unsigned wrap detection which ScalarEvolution +; doesn't yet know how to do. + +define i32 @f(i32 %x) nounwind readnone { +entry: + %0 = icmp ugt i32 %x, 999 ; <i1> [#uses=1] + br i1 %0, label %bb2, label %bb.nph + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb.nph, %bb1 + %indvar = phi i32 [ 0, %bb.nph ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %tmp = mul i32 %indvar, 3 ; <i32> [#uses=1] + %x_addr.04 = add i32 %tmp, %x ; <i32> [#uses=1] + %1 = add i32 %x_addr.04, 3 ; <i32> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %2 = icmp ugt i32 %1, 999 ; <i1> [#uses=1] + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br i1 %2, label %bb1.bb2_crit_edge, label %bb + +bb1.bb2_crit_edge: ; preds = %bb1 + %.lcssa = phi i32 [ %1, %bb1 ] ; <i32> [#uses=1] + br label %bb2 + +bb2: ; preds = %bb1.bb2_crit_edge, %entry + %x_addr.0.lcssa = phi i32 [ %.lcssa, %bb1.bb2_crit_edge ], [ %x, %entry ] ; <i32> [#uses=1] + ret i32 %x_addr.0.lcssa +} diff --git a/test/Analysis/ScalarEvolution/2008-12-08-FiniteSGE.ll b/test/Analysis/ScalarEvolution/2008-12-08-FiniteSGE.ll new file mode 100644 index 00000000000..a1b3b719165 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-12-08-FiniteSGE.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep "backedge-taken count is 255" + +define i32 @foo(i32 %x, i32 %y, i32* %lam, i32* %alp) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %indvar = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=4] + %i.0.reg2mem.0 = sub i32 255, %indvar ; <i32> [#uses=2] + %0 = getelementptr i32* %alp, i32 %i.0.reg2mem.0 ; <i32*> [#uses=1] + %1 = load i32* %0, align 4 ; <i32> [#uses=1] + %2 = getelementptr i32* %lam, i32 %i.0.reg2mem.0 ; <i32*> [#uses=1] + store i32 %1, i32* %2, align 4 + %3 = sub i32 254, %indvar ; <i32> [#uses=1] + %4 = icmp slt i32 %3, 0 ; <i1> [#uses=1] + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br i1 %4, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + %tmp10 = mul i32 %indvar, %x ; <i32> [#uses=1] + %z.0.reg2mem.0 = add i32 %tmp10, %y ; <i32> [#uses=1] + %5 = add i32 %z.0.reg2mem.0, %x ; <i32> [#uses=1] + ret i32 %5 +} diff --git a/test/Analysis/ScalarEvolution/2008-12-11-SMaxOverflow.ll b/test/Analysis/ScalarEvolution/2008-12-11-SMaxOverflow.ll new file mode 100644 index 00000000000..12254e37dcc --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-12-11-SMaxOverflow.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; CHECK: @f +; CHECK: Loop %bb16.preheader: backedge-taken count is (-1 + %c.idx.val) + +define i32 @f(i32 %c.idx.val) { + +bb2: + %k.018 = add i32 %c.idx.val, -1 ; <i32> [#uses=2] + %a14 = icmp slt i32 %k.018, 0 ; <i1> [#uses=1] + br i1 %a14, label %bb19, label %bb16.preheader + +bb16.preheader: + %k.019 = phi i32 [ %k.0, %bb18 ], [ %k.018, %bb2 ] ; <i32> [#uses=5] + %x = phi i32 [ 0, %bb2 ], [ %x.1, %bb18] + br label %bb18 + +bb18: ; preds = %bb18.loopexit + %x.1 = add i32 %x, 1 + %k.0 = add i32 %k.019, -1 ; <i32> [#uses=2] + %a107 = icmp slt i32 %k.0, 0 ; <i1> [#uses=1] + br i1 %a107, label %bb18.bb19_crit_edge, label %bb16.preheader + +bb18.bb19_crit_edge: + ret i32 %x + +bb19: + ret i32 0 + +} diff --git a/test/Analysis/ScalarEvolution/2008-12-14-StrideAndSigned.ll b/test/Analysis/ScalarEvolution/2008-12-14-StrideAndSigned.ll new file mode 100644 index 00000000000..bb149193a0f --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-12-14-StrideAndSigned.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | \ +; RUN: grep "(((-1 * %i0) + (100005 smax %i0)) /u 5)" +; XFAIL: * + +define i32 @foo0(i32 %i0) nounwind { +entry: + br label %bb1 + +bb: ; preds = %bb1 + %0 = add i32 %j.0, 1 ; <i32> [#uses=1] + %1 = add i32 %i.0, 5 ; <i32> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb, %entry + %j.0 = phi i32 [ 0, %entry ], [ %0, %bb ] ; <i32> [#uses=2] + %i.0 = phi i32 [ %i0, %entry ], [ %1, %bb ] ; <i32> [#uses=2] + %2 = icmp sgt i32 %i.0, 100000 ; <i1> [#uses=1] + br i1 %2, label %return, label %bb + +return: ; preds = %bb1 + ret i32 %j.0 +} diff --git a/test/Analysis/ScalarEvolution/2008-12-15-DontUseSDiv.ll b/test/Analysis/ScalarEvolution/2008-12-15-DontUseSDiv.ll new file mode 100644 index 00000000000..70006260cb9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2008-12-15-DontUseSDiv.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -analyze -scalar-evolution 2>&1 | grep "/u 5" +; XFAIL: * + +define i8 @foo0(i8 %i0) nounwind { +entry: + br label %bb1 + +bb: ; preds = %bb1 + %0 = add i8 %j.0, 1 ; <i8> [#uses=1] + %1 = add i8 %i.0, 5 ; <i8> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb, %entry + %j.0 = phi i8 [ 0, %entry ], [ %0, %bb ] ; <i8> [#uses=2] + %i.0 = phi i8 [ %i0, %entry ], [ %1, %bb ] ; <i8> [#uses=2] + %2 = icmp sgt i8 %i.0, 100 ; <i1> [#uses=1] + br i1 %2, label %return, label %bb + +return: ; preds = %bb1 + ret i8 %j.0 +} diff --git a/test/Analysis/ScalarEvolution/2009-01-02-SignedNegativeStride.ll b/test/Analysis/ScalarEvolution/2009-01-02-SignedNegativeStride.ll new file mode 100644 index 00000000000..82f2608e574 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2009-01-02-SignedNegativeStride.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -analyze -scalar-evolution | not grep "/u -1" +; PR3275 + +@g_16 = external global i16 ; <i16*> [#uses=3] +@.str = external constant [4 x i8] ; <[4 x i8]*> [#uses=0] + +define void @func_15() nounwind { +entry: + %0 = load i16* @g_16, align 2 ; <i16> [#uses=1] + %1 = icmp sgt i16 %0, 0 ; <i1> [#uses=1] + br i1 %1, label %bb2, label %bb.nph + +bb.nph: ; preds = %entry + %g_16.promoted = load i16* @g_16 ; <i16> [#uses=1] + br label %bb + +bb: ; preds = %bb1, %bb.nph + %g_16.tmp.0 = phi i16 [ %g_16.promoted, %bb.nph ], [ %2, %bb1 ] ; <i16> [#uses=1] + %2 = add i16 %g_16.tmp.0, -1 ; <i16> [#uses=3] + br label %bb1 + +bb1: ; preds = %bb + %3 = icmp sgt i16 %2, 0 ; <i1> [#uses=1] + br i1 %3, label %bb1.bb2_crit_edge, label %bb + +bb1.bb2_crit_edge: ; preds = %bb1 + store i16 %2, i16* @g_16 + br label %bb2 + +bb2: ; preds = %bb1.bb2_crit_edge, %entry + br label %return + +return: ; preds = %bb2 + ret void +} + +declare i32 @main() nounwind + +declare i32 @printf(i8*, ...) nounwind + diff --git a/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll b/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll new file mode 100644 index 00000000000..ebd9f7377d0 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep "(trunc i" | not grep ext + +define i16 @test1(i8 %x) { + %A = sext i8 %x to i32 + %B = trunc i32 %A to i16 + ret i16 %B +} + +define i8 @test2(i16 %x) { + %A = sext i16 %x to i32 + %B = trunc i32 %A to i8 + ret i8 %B +} + +define i16 @test3(i16 %x) { + %A = sext i16 %x to i32 + %B = trunc i32 %A to i16 + ret i16 %B +} + +define i16 @test4(i8 %x) { + %A = zext i8 %x to i32 + %B = trunc i32 %A to i16 + ret i16 %B +} + +define i8 @test5(i16 %x) { + %A = zext i16 %x to i32 + %B = trunc i32 %A to i8 + ret i8 %B +} + +define i16 @test6(i16 %x) { + %A = zext i16 %x to i32 + %B = trunc i32 %A to i16 + ret i16 %B +} diff --git a/test/Analysis/ScalarEvolution/2009-05-09-PointerEdgeCount.ll b/test/Analysis/ScalarEvolution/2009-05-09-PointerEdgeCount.ll new file mode 100644 index 00000000000..8a780431345 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2009-05-09-PointerEdgeCount.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep "count is 2" +; PR3171 +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.Foo = type { i32 } + %struct.NonPod = type { [2 x %struct.Foo] } + +define void @_Z3foov() nounwind { +entry: + %x = alloca %struct.NonPod, align 8 ; <%struct.NonPod*> [#uses=2] + %0 = getelementptr %struct.NonPod* %x, i32 0, i32 0 ; <[2 x %struct.Foo]*> [#uses=1] + %1 = getelementptr [2 x %struct.Foo]* %0, i32 1, i32 0 ; <%struct.Foo*> [#uses=1] + br label %bb1.i + +bb1.i: ; preds = %bb2.i, %entry + %.0.i = phi %struct.Foo* [ %1, %entry ], [ %4, %bb2.i ] ; <%struct.Foo*> [#uses=2] + %2 = getelementptr %struct.NonPod* %x, i32 0, i32 0, i32 0 ; <%struct.Foo*> [#uses=1] + %3 = icmp eq %struct.Foo* %.0.i, %2 ; <i1> [#uses=1] + br i1 %3, label %_ZN6NonPodD1Ev.exit, label %bb2.i + +bb2.i: ; preds = %bb1.i + %4 = getelementptr %struct.Foo* %.0.i, i32 -1 ; <%struct.Foo*> [#uses=1] + br label %bb1.i + +_ZN6NonPodD1Ev.exit: ; preds = %bb1.i + ret void +} + diff --git a/test/Analysis/ScalarEvolution/2009-07-04-GroupConstantsWidthMismatch.ll b/test/Analysis/ScalarEvolution/2009-07-04-GroupConstantsWidthMismatch.ll new file mode 100644 index 00000000000..a4358aa6321 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2009-07-04-GroupConstantsWidthMismatch.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -analyze -scalar-evolution +; PR4501 + +define void @test() { +entry: + %0 = load i16* undef, align 1 + %1 = lshr i16 %0, 8 + %2 = and i16 %1, 3 + %3 = zext i16 %2 to i32 + %4 = load i8* undef, align 1 + %5 = lshr i8 %4, 4 + %6 = and i8 %5, 1 + %7 = zext i8 %6 to i32 + %t1 = add i32 %3, %7 + ret void +} diff --git a/test/Analysis/ScalarEvolution/2010-09-03-RequiredTransitive.ll b/test/Analysis/ScalarEvolution/2010-09-03-RequiredTransitive.ll new file mode 100644 index 00000000000..aba0ce74678 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2010-09-03-RequiredTransitive.ll @@ -0,0 +1,24 @@ +; RUN: opt -indvars -scalar-evolution -analyze %s +; This test checks if the SCEV analysis is printed out at all. +; It failed once as the RequiredTransitive option was not implemented +; correctly. + +define i32 @main() nounwind { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %indvar1 = phi i64 [ %indvar.next2, %for.inc ], [ 0, %entry ] ; <i64> [#uses=3] + %exitcond = icmp ne i64 %indvar1, 1024 ; <i1> [#uses=1] + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + br label %for.inc + +for.inc: ; preds = %for.body + %indvar.next2 = add i64 %indvar1, 1 ; <i64> [#uses=1] + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 0 +} diff --git a/test/Analysis/ScalarEvolution/2011-03-09-ExactNoMaxBECount.ll b/test/Analysis/ScalarEvolution/2011-03-09-ExactNoMaxBECount.ll new file mode 100644 index 00000000000..9f17e27577c --- /dev/null +++ b/test/Analysis/ScalarEvolution/2011-03-09-ExactNoMaxBECount.ll @@ -0,0 +1,34 @@ +; RUN: opt -indvars %s +; PR9424: Attempt to use a SCEVCouldNotCompute object! +; The inner loop computes the Step and Start of the outer loop. +; Call that Vexit. The outer End value is max(2,Vexit), because +; the condition "icmp %4 < 2" does not guard the outer loop. +; SCEV knows that Vexit has range [2,4], so End == Vexit == Start. +; Now we have ExactBECount == 0. However, MinStart == 2 and MaxEnd == 4. +; Since the stride is variable and may wrap, we cannot compute +; MaxBECount. SCEV should override MaxBECount with ExactBECount. + +define void @bar() nounwind { +entry: + %. = select i1 undef, i32 2, i32 1 + br label %"5.preheader" + +"4": ; preds = %"5.preheader", %"4" + %0 = phi i32 [ 0, %"5.preheader" ], [ %1, %"4" ] + %1 = add nsw i32 %0, 1 + %2 = icmp sgt i32 %., %1 + br i1 %2, label %"4", label %"9" + +"9": ; preds = %"4" + %3 = add i32 %6, 1 + %4 = add i32 %3, %1 + %5 = icmp slt i32 %4, 2 + br i1 %5, label %"5.preheader", label %return + +"5.preheader": ; preds = %"9", %entry + %6 = phi i32 [ 0, %entry ], [ %4, %"9" ] + br label %"4" + +return: ; preds = %"9" + ret void +} diff --git a/test/Analysis/ScalarEvolution/2011-04-26-FoldAddRec.ll b/test/Analysis/ScalarEvolution/2011-04-26-FoldAddRec.ll new file mode 100644 index 00000000000..1600d5f05a1 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2011-04-26-FoldAddRec.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -analyze -iv-users +; PR9633: Tests that SCEV handles the mul.i2 recurrence being folded to +; constant zero. + +define signext i8 @func_14(i8 signext %p_18) nounwind readnone ssp { +entry: + br label %for.inc + +for.inc: + %p_17.addr.012 = phi i32 [ 0, %entry ], [ %add, %for.inc ] + %add = add nsw i32 %p_17.addr.012, 1 + br i1 false, label %for.inc, label %for.cond + +for.cond: + %tobool.i = icmp ult i32 %add, 8192 + %shl.i = select i1 %tobool.i, i32 13, i32 0 + %shl.left.i = shl i32 %add, %shl.i + %conv.i4 = trunc i32 %shl.left.i to i8 + br i1 undef, label %for.inc9, label %if.then + +for.inc9: + %p_18.addr.011 = phi i8 [ %add12, %for.inc9 ], [ %p_18, %for.cond ] + %add12 = add i8 %p_18.addr.011, 1 + %mul.i2 = mul i8 %add12, %conv.i4 + %mul.i2.lobit = lshr i8 %mul.i2, 7 + %lor.ext.shr.i = select i1 undef, i8 %mul.i2.lobit, i8 %mul.i2 + %tobool = icmp eq i8 %lor.ext.shr.i, 0 + br i1 %tobool, label %for.inc9, label %if.then + +if.then: + ret i8 0 + +}
\ No newline at end of file diff --git a/test/Analysis/ScalarEvolution/2011-10-04-ConstEvolve.ll b/test/Analysis/ScalarEvolution/2011-10-04-ConstEvolve.ll new file mode 100644 index 00000000000..29bb64ad642 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2011-10-04-ConstEvolve.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; Exercise getConstantEvolvingPHIOperands on an interesting loop. +; This should complete in milliseconds, not minutes. + +; Just check that it actually ran trip count analysis. +; CHECK: Determining loop execution counts for: @test +define void @test() nounwind { +entry: + br label %loop + +loop: + %iv = phi i32 [ %30, %loop ], [ 0, %entry ] + %0 = add i32 %iv, 1 + %1 = add i32 %0, 2 + %2 = add i32 %1, %0 + %3 = add i32 %2, %1 + %4 = add i32 %3, %2 + %5 = add i32 %4, %3 + %6 = add i32 %5, %4 + %7 = add i32 %6, %5 + %8 = add i32 %7, %6 + %9 = add i32 %8, %7 + %10 = add i32 %9, %8 + %11 = add i32 %10, %9 + %12 = add i32 %11, %10 + %13 = add i32 %12, %11 + %14 = add i32 %13, %12 + %15 = add i32 %14, %13 + %16 = add i32 %15, %14 + %17 = add i32 %16, %15 + %18 = add i32 %17, %16 + %19 = add i32 %18, %17 + %20 = add i32 %19, %18 + %21 = add i32 %20, %19 + %22 = add i32 %21, %20 + %23 = add i32 %22, %21 + %24 = add i32 %23, %22 + %25 = add i32 %24, %23 + %26 = add i32 %25, %24 + %27 = add i32 %26, %25 + %28 = add i32 %27, %26 + %29 = add i32 %28, %27 + %30 = add i32 %29, %28 + %cmp = icmp eq i32 %30, -108 + br i1 %cmp, label %exit, label %loop + +exit: + unreachable +} diff --git a/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll b/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll new file mode 100644 index 00000000000..138c015f12c --- /dev/null +++ b/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll @@ -0,0 +1,47 @@ +; RUN: opt < %s -basicaa -globalopt -instcombine -loop-rotate -licm -instcombine -indvars -loop-deletion -constmerge -S +; PR11882: ComputeLoadConstantCompareExitLimit crash. +; +; for.body is deleted leaving a loop-invariant load. +; CHECK-NOT: for.body +target datalayout = "e-p:64:64:64-n32:64" + +@func_21_l_773 = external global i32, align 4 +@g_814 = external global i32, align 4 +@g_244 = internal global [1 x [0 x i32]] zeroinitializer, align 4 + +define void @func_21() nounwind uwtable ssp { +entry: + br label %lbl_818 + +lbl_818: ; preds = %for.end, %entry + call void (...)* @func_27() + store i32 0, i32* @g_814, align 4, !tbaa !0 + br label %for.cond + +for.cond: ; preds = %for.body, %lbl_818 + %0 = load i32* @g_814, align 4, !tbaa !0 + %cmp = icmp sle i32 %0, 0 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %idxprom = sext i32 %0 to i64 + %arrayidx = getelementptr inbounds [0 x i32]* getelementptr inbounds ([1 x [0 x i32]]* @g_244, i32 0, i64 0), i32 0, i64 %idxprom + %1 = load i32* %arrayidx, align 1, !tbaa !0 + store i32 %1, i32* @func_21_l_773, align 4, !tbaa !0 + store i32 1, i32* @g_814, align 4, !tbaa !0 + br label %for.cond + +for.end: ; preds = %for.cond + %2 = load i32* @func_21_l_773, align 4, !tbaa !0 + %tobool = icmp ne i32 %2, 0 + br i1 %tobool, label %lbl_818, label %if.end + +if.end: ; preds = %for.end + ret void +} + +declare void @func_27(...) + +!0 = metadata !{metadata !"int", metadata !1} +!1 = metadata !{metadata !"omnipotent char", metadata !2} +!2 = metadata !{metadata !"Simple C/C++ TBAA", null} diff --git a/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll b/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll new file mode 100644 index 00000000000..52e6683c9f0 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -iv-users -S -disable-output +; +; PR12868: Infinite recursion: +; getUDivExpr()->getZeroExtendExpr()->isLoopBackedgeGuardedBy() +; +; We actually want SCEV simplification to fail gracefully in this +; case, so there's no output to check, just the absense of stack overflow. + +@c = common global i8 0, align 1 + +define i32 @func() { +entry: + br label %for.cond + +for.cond: ; preds = %for.body, %entry + %storemerge = phi i8 [ -1, %entry ], [ %inc, %for.body ] + %ui.0 = phi i32 [ undef, %entry ], [ %div, %for.body ] + %tobool = icmp eq i8 %storemerge, 0 + br i1 %tobool, label %for.end, label %for.body + +for.body: ; preds = %for.cond + %conv = sext i8 %storemerge to i32 + %div = lshr i32 %conv, 1 + %tobool2 = icmp eq i32 %div, 0 + %inc = add i8 %storemerge, 1 + br i1 %tobool2, label %for.cond, label %for.end + +for.end: ; preds = %for.body, %for.cond + ret i32 0 +} diff --git a/test/Analysis/ScalarEvolution/2012-05-29-MulAddRec.ll b/test/Analysis/ScalarEvolution/2012-05-29-MulAddRec.ll new file mode 100644 index 00000000000..3f04e2e21c4 --- /dev/null +++ b/test/Analysis/ScalarEvolution/2012-05-29-MulAddRec.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -S -indvars -loop-unroll | FileCheck %s +; +; loop-unroll fully unrolls the inner loop, creating an interesting +; chain of multiplication. indvars forces SCEV to run again on the +; outer loop. While reducing the recurrence at %mul3, unsigned integer overflow +; causes one of the terms to reach zero. This forces all multiples in +; the recurrence to be zero, reducing the whole thing to a constant expression. +; +; PR12929: cast<Ty>() argument of incompatible type + +; CHECK: @func +; CHECK: for.cond: +; CHECK: %inc1 = phi i8 [ 0, %entry ], [ %0, %for.body ] +; CHECK: br label %for.body + +; CHECK: for.body: +; CHECK: %inc.9 = add i8 %inc.8, 1 +; CHECK: %0 = add i8 %inc1, 10 +; CHECK: br label %for.cond + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +define void @func() noreturn nounwind uwtable ssp { +entry: + br label %for.cond + +for.cond.loopexit: ; preds = %for.body + %mul.lcssa = phi i8 [ %mul, %for.body ] + %0 = add i8 %inc1, 10 + %indvars.iv.next = add i8 %indvars.iv, 10 + br label %for.cond + +for.cond: ; preds = %for.cond.loopexit, %entry + %indvars.iv = phi i8 [ %indvars.iv.next, %for.cond.loopexit ], [ 10, %entry ] + %mul3 = phi i8 [ undef, %entry ], [ %mul.lcssa, %for.cond.loopexit ] + %inc1 = phi i8 [ 0, %entry ], [ %0, %for.cond.loopexit ] + br label %for.body + +for.body: ; preds = %for.body, %for.cond + %inc26 = phi i8 [ %inc1, %for.cond ], [ %inc, %for.body ] + %mul45 = phi i8 [ %mul3, %for.cond ], [ %mul, %for.body ] + %inc = add i8 %inc26, 1 + %mul = mul i8 %inc26, %mul45 + %exitcond = icmp ne i8 %inc, %indvars.iv + br i1 %exitcond, label %for.body, label %for.cond.loopexit +} diff --git a/test/Analysis/ScalarEvolution/SolveQuadraticEquation.ll b/test/Analysis/ScalarEvolution/SolveQuadraticEquation.ll new file mode 100644 index 00000000000..e946d7a64bc --- /dev/null +++ b/test/Analysis/ScalarEvolution/SolveQuadraticEquation.ll @@ -0,0 +1,103 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | FileCheck %s + +; PR1101 + +@A = weak global [1000 x i32] zeroinitializer, align 32 + +define void @test1(i32 %N) { +entry: + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + br label %bb3 + +bb: ; preds = %bb3 + %tmp = getelementptr [1000 x i32]* @A, i32 0, i32 %i.0 ; <i32*> [#uses=1] + store i32 123, i32* %tmp + %tmp2 = add i32 %i.0, 1 ; <i32> [#uses=1] + br label %bb3 + +bb3: ; preds = %bb, %entry + %i.0 = phi i32 [ 2, %entry ], [ %tmp2, %bb ] ; <i32> [#uses=3] + %SQ = mul i32 %i.0, %i.0 + %tmp4 = mul i32 %i.0, 2 + %tmp5 = sub i32 %SQ, %tmp4 + %tmp3 = icmp sle i32 %tmp5, 9999 ; <i1> [#uses=1] + br i1 %tmp3, label %bb, label %bb5 + +bb5: ; preds = %bb3 + br label %return + +return: ; preds = %bb5 + ret void +} +; CHECK: Determining loop execution counts for: @test1 +; CHECK-NEXT: backedge-taken count is 100 + + +; PR10383 +; These next two used to crash. + +define void @test2(i1 %cmp, i64 %n) { +entry: + br label %for.body1 + +for.body1: + %a0.08 = phi i64 [ 0, %entry ], [ %inc512, %for.body1 ] + %inc512 = add i64 %a0.08, 1 + br i1 %cmp, label %preheader, label %for.body1 + +preheader: + br label %for.body2 + +for.body2: + %indvar = phi i64 [ 0, %preheader ], [ %indvar.next, %for.body2 ] + %tmp111 = add i64 %n, %indvar + %tmp114 = mul i64 %a0.08, %indvar + %mul542 = mul i64 %tmp114, %tmp111 + %indvar.next = add i64 %indvar, 1 + br i1 undef, label %end, label %for.body2 + +end: + ret void +} +; CHECK: Determining loop execution counts for: @test2 + +define i32 @test3() { +if.then466: + br i1 undef, label %for.cond539.preheader, label %for.inc479 + +for.inc479: + %a2.07 = phi i32 [ %add495, %for.inc479 ], [ 0, %if.then466 ] + %j.36 = phi i32 [ %inc497, %for.inc479 ], [ undef, %if.then466 ] + %mul484 = mul nsw i32 %j.36, %j.36 + %mul491 = mul i32 %j.36, %j.36 + %mul493 = mul i32 %mul491, %mul484 + %add495 = add nsw i32 %mul493, %a2.07 + %inc497 = add nsw i32 %j.36, 1 + br i1 undef, label %for.cond539.preheader, label %for.inc479 + +for.cond539.preheader: + unreachable +} +; CHECK: Determining loop execution counts for: @test3 + +; PR13489 +; We used to crash on this too. + +define void @test4() { +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %v2.02 = phi i64 [ 2, %entry ], [ %phitmp, %for.body ] + %v1.01 = phi i64 [ -2, %entry ], [ %sub1, %for.body ] + %sub1 = sub i64 %v1.01, %v2.02 + %phitmp = add i64 %v2.02, 2 + %tobool = icmp eq i64 %sub1, %phitmp + br i1 %tobool, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; CHECK: Determining loop execution counts for: @test4 diff --git a/test/Analysis/ScalarEvolution/and-xor.ll b/test/Analysis/ScalarEvolution/and-xor.ll new file mode 100644 index 00000000000..06f4a8582fa --- /dev/null +++ b/test/Analysis/ScalarEvolution/and-xor.ll @@ -0,0 +1,8 @@ +; RUN: opt < %s -scalar-evolution -analyze \ +; RUN: | grep "\--> (zext" | count 2 + +define i32 @foo(i32 %x) { + %n = and i32 %x, 255 + %y = xor i32 %n, 255 + ret i32 %y +} diff --git a/test/Analysis/ScalarEvolution/avoid-infinite-recursion-0.ll b/test/Analysis/ScalarEvolution/avoid-infinite-recursion-0.ll new file mode 100644 index 00000000000..7eeb3084958 --- /dev/null +++ b/test/Analysis/ScalarEvolution/avoid-infinite-recursion-0.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -analyze -scalar-evolution +; PR4537 + +; ModuleID = 'b.bc' +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @test() { +entry: + %0 = load i32** undef, align 8 ; <i32*> [#uses=1] + %1 = ptrtoint i32* %0 to i64 ; <i64> [#uses=1] + %2 = sub i64 undef, %1 ; <i64> [#uses=1] + %3 = lshr i64 %2, 3 ; <i64> [#uses=1] + %4 = trunc i64 %3 to i32 ; <i32> [#uses=2] + br i1 undef, label %bb10, label %bb4.i + +bb4.i: ; preds = %bb4.i, %entry + %i.0.i6 = phi i32 [ %8, %bb4.i ], [ 0, %entry ] ; <i32> [#uses=2] + %5 = sub i32 %4, %i.0.i6 ; <i32> [#uses=1] + %6 = sext i32 %5 to i64 ; <i64> [#uses=1] + %7 = udiv i64 undef, %6 ; <i64> [#uses=1] + %8 = add i32 %i.0.i6, 1 ; <i32> [#uses=2] + %phitmp = icmp eq i64 %7, 0 ; <i1> [#uses=1] + %.not.i = icmp sge i32 %8, %4 ; <i1> [#uses=1] + %or.cond.i = or i1 %phitmp, %.not.i ; <i1> [#uses=1] + br i1 %or.cond.i, label %bb10, label %bb4.i + +bb10: ; preds = %bb4.i, %entry + unreachable +} diff --git a/test/Analysis/ScalarEvolution/avoid-infinite-recursion-1.ll b/test/Analysis/ScalarEvolution/avoid-infinite-recursion-1.ll new file mode 100644 index 00000000000..f61b667dcfa --- /dev/null +++ b/test/Analysis/ScalarEvolution/avoid-infinite-recursion-1.ll @@ -0,0 +1,354 @@ +; RUN: opt < %s -iv-users +; PR4538 + +; ModuleID = 'bugpoint-reduced-simplified.bc' +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-freebsd8.0" +module asm ".ident\09\22$FreeBSD: head/sys/kern/vfs_subr.c 195285 2009-07-02 14:19:33Z jamie $\22" +module asm ".section set_pcpu, \22aw\22, @progbits" +module asm ".previous" + %0 = type <{ [40 x i8] }> ; type %0 + %1 = type <{ %struct.vm_object*, %struct.vm_object** }> ; type %1 + %2 = type <{ %struct.vm_object* }> ; type %2 + %3 = type <{ %struct.vm_page*, %struct.vm_page** }> ; type %3 + %4 = type <{ %struct.pv_entry*, %struct.pv_entry** }> ; type %4 + %5 = type <{ %struct.vm_reserv* }> ; type %5 + %6 = type <{ %struct.bufobj*, %struct.bufobj** }> ; type %6 + %7 = type <{ %struct.proc*, %struct.proc** }> ; type %7 + %8 = type <{ %struct.thread*, %struct.thread** }> ; type %8 + %9 = type <{ %struct.prison*, %struct.prison** }> ; type %9 + %10 = type <{ %struct.prison* }> ; type %10 + %11 = type <{ %struct.task* }> ; type %11 + %12 = type <{ %struct.osd*, %struct.osd** }> ; type %12 + %13 = type <{ %struct.proc* }> ; type %13 + %14 = type <{ %struct.ksiginfo*, %struct.ksiginfo** }> ; type %14 + %15 = type <{ %struct.pv_chunk*, %struct.pv_chunk** }> ; type %15 + %16 = type <{ %struct.pgrp*, %struct.pgrp** }> ; type %16 + %17 = type <{ %struct.knote*, %struct.knote** }> ; type %17 + %18 = type <{ %struct.ktr_request*, %struct.ktr_request** }> ; type %18 + %19 = type <{ %struct.mqueue_notifier* }> ; type %19 + %20 = type <{ %struct.turnstile* }> ; type %20 + %21 = type <{ %struct.namecache* }> ; type %21 + %22 = type <{ %struct.namecache*, %struct.namecache** }> ; type %22 + %23 = type <{ %struct.lockf*, %struct.lockf** }> ; type %23 + %24 = type <{ %struct.lockf_entry*, %struct.lockf_entry** }> ; type %24 + %25 = type <{ %struct.lockf_edge*, %struct.lockf_edge** }> ; type %25 + %struct.__siginfo = type <{ i32, i32, i32, i32, i32, i32, i8*, %union.sigval, %0 }> + %struct.__sigset = type <{ [4 x i32] }> + %struct.acl = type <{ i32, i32, [4 x i32], [254 x %struct.acl_entry] }> + %struct.acl_entry = type <{ i32, i32, i32, i16, i16 }> + %struct.au_mask = type <{ i32, i32 }> + %struct.au_tid_addr = type <{ i32, i32, [4 x i32] }> + %struct.auditinfo_addr = type <{ i32, %struct.au_mask, %struct.au_tid_addr, i32, i64 }> + %struct.bintime = type <{ i64, i64 }> + %struct.buf = type <{ %struct.bufobj*, i64, i8*, i8*, i32, i8, i8, i8, i8, i64, i64, void (%struct.buf*)*, i64, i64, %struct.buflists, %struct.buf*, %struct.buf*, i32, i8, i8, i8, i8, %struct.buflists, i16, i8, i8, i32, i8, i8, i8, i8, i8, i8, i8, i8, %struct.lock, i64, i64, i8*, i32, i8, i8, i8, i8, i64, %struct.vnode*, i32, i32, %struct.ucred*, %struct.ucred*, i8*, %union.pager_info, i8, i8, i8, i8, %union.anon, [32 x %struct.vm_page*], i32, i8, i8, i8, i8, %struct.workhead, i8*, i8*, i8*, i32, i8, i8, i8, i8 }> + %struct.buf_ops = type <{ i8*, i32 (%struct.buf*)*, void (%struct.bufobj*, %struct.buf*)*, i32 (%struct.bufobj*, i32)*, void (%struct.bufobj*, %struct.buf*)* }> + %struct.buflists = type <{ %struct.buf*, %struct.buf** }> + %struct.bufobj = type <{ %struct.mtx, %struct.bufv, %struct.bufv, i64, i32, i8, i8, i8, i8, %struct.buf_ops*, i32, i8, i8, i8, i8, %struct.vm_object*, %6, i8*, %struct.vnode* }> + %struct.bufv = type <{ %struct.buflists, %struct.buf*, i32, i8, i8, i8, i8 }> + %struct.callout = type <{ %union.anon, i32, i8, i8, i8, i8, i8*, void (i8*)*, %struct.lock_object*, i32, i32 }> + %struct.cdev_privdata = type opaque + %struct.cluster_save = type <{ i64, i64, i8*, i32, i8, i8, i8, i8, %struct.buf** }> + %struct.componentname = type <{ i64, i64, %struct.thread*, %struct.ucred*, i32, i8, i8, i8, i8, i8*, i8*, i64, i64 }> + %struct.cpuset = type opaque + %struct.cv = type <{ i8*, i32, i8, i8, i8, i8 }> + %struct.fid = type <{ i16, i16, [16 x i8] }> + %struct.file = type <{ i8*, %struct.fileops*, %struct.ucred*, %struct.vnode*, i16, i16, i32, i32, i32, i64, %struct.cdev_privdata*, i64, i8* }> + %struct.filedesc = type opaque + %struct.filedesc_to_leader = type opaque + %struct.fileops = type <{ i32 (%struct.file*, %struct.uio*, %struct.ucred*, i32, %struct.thread*)*, i32 (%struct.file*, %struct.uio*, %struct.ucred*, i32, %struct.thread*)*, i32 (%struct.file*, i64, %struct.ucred*, %struct.thread*)*, i32 (%struct.file*, i64, i8*, %struct.ucred*, %struct.thread*)*, i32 (%struct.file*, i32, %struct.ucred*, %struct.thread*)*, i32 (%struct.file*, %struct.knote*)*, i32 (%struct.file*, %struct.stat*, %struct.ucred*, %struct.thread*)*, i32 (%struct.file*, %struct.thread*)*, i32, i8, i8, i8, i8 }> + %struct.filterops = type <{ i32, i8, i8, i8, i8, i32 (%struct.knote*)*, void (%struct.knote*)*, i32 (%struct.knote*, i64)* }> + %struct.flock = type <{ i64, i64, i32, i16, i16, i32, i8, i8, i8, i8 }> + %struct.freelst = type <{ %struct.vnode*, %struct.vnode** }> + %struct.fsid = type <{ [2 x i32] }> + %struct.in6_addr = type opaque + %struct.in_addr = type opaque + %struct.inode = type opaque + %struct.iovec = type <{ i8*, i64 }> + %struct.itimers = type opaque + %struct.itimerval = type <{ %struct.bintime, %struct.bintime }> + %struct.kaioinfo = type opaque + %struct.kaudit_record = type opaque + %struct.kdtrace_proc = type opaque + %struct.kdtrace_thread = type opaque + %struct.kevent = type <{ i64, i16, i16, i32, i64, i8* }> + %struct.klist = type <{ %struct.knote* }> + %struct.knlist = type <{ %struct.klist, void (i8*)*, void (i8*)*, void (i8*)*, void (i8*)*, i8* }> + %struct.knote = type <{ %struct.klist, %struct.klist, %struct.knlist*, %17, %struct.kqueue*, %struct.kevent, i32, i32, i64, %union.sigval, %struct.filterops*, i8* }> + %struct.kqueue = type opaque + %struct.ksiginfo = type <{ %14, %struct.__siginfo, i32, i8, i8, i8, i8, %struct.sigqueue* }> + %struct.ktr_request = type opaque + %struct.label = type opaque + %struct.lock = type <{ %struct.lock_object, i64, i32, i32 }> + %struct.lock_list_entry = type opaque + %struct.lock_object = type <{ i8*, i32, i32, %struct.witness* }> + %struct.lock_owner = type opaque + %struct.lock_profile_object = type opaque + %struct.lockf = type <{ %23, %struct.mtx, %struct.lockf_entry_list, %struct.lockf_entry_list, i32, i8, i8, i8, i8 }> + %struct.lockf_edge = type <{ %25, %25, %struct.lockf_entry*, %struct.lockf_entry* }> + %struct.lockf_edge_list = type <{ %struct.lockf_edge* }> + %struct.lockf_entry = type <{ i16, i16, i8, i8, i8, i8, i64, i64, %struct.lock_owner*, %struct.vnode*, %struct.inode*, %struct.task*, %24, %struct.lockf_edge_list, %struct.lockf_edge_list, i32, i8, i8, i8, i8 }> + %struct.lockf_entry_list = type <{ %struct.lockf_entry* }> + %struct.lpohead = type <{ %struct.lock_profile_object* }> + %struct.md_page = type <{ %4 }> + %struct.mdproc = type <{ %struct.cv*, %struct.system_segment_descriptor }> + %struct.mdthread = type <{ i32, i8, i8, i8, i8, i64 }> + %struct.mntarg = type opaque + %struct.mntlist = type <{ %struct.mount*, %struct.mount** }> + %struct.mount = type <{ %struct.mtx, i32, i8, i8, i8, i8, %struct.mntlist, %struct.vfsops*, %struct.vfsconf*, %struct.vnode*, %struct.vnode*, i32, i8, i8, i8, i8, %struct.freelst, i32, i32, i32, i32, i32, i32, %struct.vfsoptlist*, %struct.vfsoptlist*, i32, i8, i8, i8, i8, %struct.statfs, %struct.ucred*, i8*, i64, i32, i8, i8, i8, i8, %struct.netexport*, %struct.label*, i32, i32, i32, i32, %struct.thread*, i8*, %struct.lock }> + %struct.mqueue_notifier = type opaque + %struct.mtx = type <{ %struct.lock_object, i64 }> + %struct.namecache = type opaque + %struct.netexport = type opaque + %struct.nlminfo = type opaque + %struct.osd = type <{ i32, i8, i8, i8, i8, i8**, %12 }> + %struct.p_sched = type opaque + %struct.pargs = type <{ i32, i32, [1 x i8], i8, i8, i8 }> + %struct.pcb = type opaque + %struct.pgrp = type <{ %16, %13, %struct.session*, %struct.sigiolst, i32, i32, %struct.mtx }> + %struct.plimit = type opaque + %struct.pmap = type <{ %struct.mtx, i64*, %15, i32, i8, i8, i8, i8, %struct.bintime, %struct.vm_page* }> + %struct.prison = type <{ %9, i32, i32, i32, i32, %10, %9, %struct.prison*, %struct.mtx, %struct.task, %struct.osd, %struct.cpuset*, %struct.vnet*, %struct.vnode*, i32, i32, %struct.in_addr*, %struct.in6_addr*, [4 x i8*], i32, i32, i32, i32, i32, [5 x i32], i64, [256 x i8], [1024 x i8], [256 x i8], [256 x i8], [64 x i8] }> + %struct.proc = type <{ %7, %8, %struct.mtx, %struct.ucred*, %struct.filedesc*, %struct.filedesc_to_leader*, %struct.pstats*, %struct.plimit*, %struct.callout, %struct.sigacts*, i32, i32, i32, i8, i8, i8, i8, %7, %7, %struct.proc*, %7, %13, %struct.mtx, %struct.ksiginfo*, %struct.sigqueue, i32, i8, i8, i8, i8, %struct.vmspace*, i32, i8, i8, i8, i8, %struct.itimerval, %struct.rusage, %struct.rusage_ext, %struct.rusage_ext, i32, i32, i32, i8, i8, i8, i8, %struct.vnode*, %struct.ucred*, %struct.vnode*, i32, i8, i8, i8, i8, %struct.sigiolst, i32, i32, i64, i32, i32, i8, i8, i8, i8, i8, i8, i8, i8, %struct.nlminfo*, %struct.kaioinfo*, %struct.thread*, i32, i8, i8, i8, i8, %struct.thread*, i32, i32, %struct.itimers*, i32, i32, [20 x i8], i8, i8, i8, i8, %struct.pgrp*, %struct.sysentvec*, %struct.pargs*, i64, i8, i8, i8, i8, i32, i16, i8, i8, i8, i8, i8, i8, %struct.knlist, i32, i8, i8, i8, i8, %struct.mdproc, %struct.callout, i16, i8, i8, i8, i8, i8, i8, %struct.proc*, %struct.proc*, i8*, %struct.label*, %struct.p_sched*, %18, %19, %struct.kdtrace_proc*, %struct.cv }> + %struct.pstats = type opaque + %struct.pv_chunk = type <{ %struct.pmap*, %15, [3 x i64], [2 x i64], [168 x %struct.pv_entry] }> + %struct.pv_entry = type <{ i64, %4 }> + %struct.rusage = type <{ %struct.bintime, %struct.bintime, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 }> + %struct.rusage_ext = type <{ i64, i64, i64, i64, i64, i64, i64 }> + %struct.selfd = type opaque + %struct.selfdlist = type <{ %struct.selfd*, %struct.selfd** }> + %struct.selinfo = type <{ %struct.selfdlist, %struct.knlist, %struct.mtx* }> + %struct.seltd = type opaque + %struct.session = type <{ i32, i8, i8, i8, i8, %struct.proc*, %struct.vnode*, %struct.tty*, i32, [24 x i8], i8, i8, i8, i8, %struct.mtx }> + %struct.shmmap_state = type opaque + %struct.sigacts = type <{ [128 x void (i32)*], [128 x %struct.__sigset], %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, %struct.__sigset, i32, i32, %struct.mtx }> + %struct.sigaltstack = type <{ i8*, i64, i32, i8, i8, i8, i8 }> + %struct.sigio = type <{ %union.sigval, %struct.sigiolst, %struct.sigio**, %struct.ucred*, i32, i8, i8, i8, i8 }> + %struct.sigiolst = type <{ %struct.sigio* }> + %struct.sigqueue = type <{ %struct.__sigset, %struct.__sigset, %14, %struct.proc*, i32, i8, i8, i8, i8 }> + %struct.sleepqueue = type opaque + %struct.sockaddr = type opaque + %struct.stat = type <{ i32, i32, i16, i16, i32, i32, i32, %struct.bintime, %struct.bintime, %struct.bintime, i64, i64, i32, i32, i32, i32, %struct.bintime }> + %struct.statfs = type <{ i32, i32, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, [10 x i64], i32, i32, %struct.fsid, [80 x i8], [16 x i8], [88 x i8], [88 x i8] }> + %struct.sysctl_req = type <{ %struct.thread*, i32, i8, i8, i8, i8, i8*, i64, i64, i32 (%struct.sysctl_req*, i8*, i64)*, i8*, i64, i64, i32 (%struct.sysctl_req*, i8*, i64)*, i64, i32, i8, i8, i8, i8 }> + %struct.sysentvec = type opaque + %struct.system_segment_descriptor = type <{ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8 }> + %struct.task = type <{ %11, i16, i16, i8, i8, i8, i8, void (i8*, i32)*, i8* }> + %struct.td_sched = type opaque + %struct.thread = type <{ %struct.mtx*, %struct.proc*, %8, %8, %8, %8, %struct.cpuset*, %struct.seltd*, %struct.sleepqueue*, %struct.turnstile*, %struct.umtx_q*, i32, i8, i8, i8, i8, %struct.sigqueue, i32, i32, i32, i32, i32, i8, i8, i8, i8, i8*, i8*, i8, i8, i8, i8, i16, i16, i16, i8, i8, i8, i8, i8, i8, %struct.turnstile*, i8*, %20, %struct.lock_list_entry*, i32, i32, %struct.ucred*, i32, i32, %struct.rusage, i64, i64, i32, i32, i32, i32, i32, %struct.__sigset, %struct.__sigset, i32, %struct.sigaltstack, i32, i8, i8, i8, i8, i64, i32, [20 x i8], %struct.file*, i32, i32, %struct.osd, i8, i8, i8, i8, i8, i8, i8, i8, %struct.pcb*, i32, i8, i8, i8, i8, [2 x i64], %struct.callout, %struct.trapframe*, %struct.vm_object*, i64, i32, i8, i8, i8, i8, %struct.vm_object*, i64, i32, i32, %struct.mdthread, %struct.td_sched*, %struct.kaudit_record*, i32, i8, i8, i8, i8, [2 x %struct.lpohead], %struct.kdtrace_thread*, i32, i8, i8, i8, i8, %struct.vnet*, i8* }> + %struct.trapframe = type <{ i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i32, i16, i16, i64, i32, i16, i16, i64, i64, i64, i64, i64, i64 }> + %struct.tty = type opaque + %struct.turnstile = type opaque + %struct.ucred = type <{ i32, i32, i32, i32, i32, i32, i32, i8, i8, i8, i8, %struct.uidinfo*, %struct.uidinfo*, %struct.prison*, %struct.vimage*, i32, i8, i8, i8, i8, [2 x i8*], %struct.label*, %struct.auditinfo_addr, i32*, i32, i8, i8, i8, i8 }> + %struct.uidinfo = type opaque + %struct.uio = type <{ %struct.iovec*, i32, i8, i8, i8, i8, i64, i64, i32, i32, %struct.thread* }> + %struct.umtx_q = type opaque + %struct.vattr = type <{ i32, i16, i16, i32, i32, i32, i8, i8, i8, i8, i64, i64, i64, %struct.bintime, %struct.bintime, %struct.bintime, %struct.bintime, i64, i64, i32, i8, i8, i8, i8, i64, i64, i32, i8, i8, i8, i8, i64 }> + %struct.vfsconf = type <{ i32, [16 x i8], i8, i8, i8, i8, %struct.vfsops*, i32, i32, i32, i8, i8, i8, i8, %struct.vfsoptdecl*, %struct.vfsconfhead }> + %struct.vfsconfhead = type <{ %struct.vfsconf*, %struct.vfsconf** }> + %struct.vfsops = type <{ i32 (%struct.mount*)*, i32 (%struct.mntarg*, i8*, i32)*, i32 (%struct.mount*, i32)*, i32 (%struct.mount*, i32, %struct.vnode**)*, i32 (%struct.mount*, i32, i32, i8*)*, i32 (%struct.mount*, %struct.statfs*)*, i32 (%struct.mount*, i32)*, i32 (%struct.mount*, i32, i32, %struct.vnode**)*, i32 (%struct.mount*, %struct.fid*, %struct.vnode**)*, i32 (%struct.mount*, %struct.sockaddr*, i32*, %struct.ucred**, i32*, i32**)*, i32 (%struct.vfsconf*)*, i32 (%struct.vfsconf*)*, i32 (%struct.mount*, i32, %struct.vnode*, i32, i8*)*, i32 (%struct.mount*, i32, %struct.sysctl_req*)*, void (%struct.mount*)* }> + %struct.vfsopt = type <{ %struct.vfsoptlist, i8*, i8*, i32, i32, i32, i8, i8, i8, i8 }> + %struct.vfsoptdecl = type opaque + %struct.vfsoptlist = type <{ %struct.vfsopt*, %struct.vfsopt** }> + %struct.vimage = type opaque + %struct.vm_map = type <{ %struct.vm_map_entry, %struct.mtx, %struct.mtx, i32, i8, i8, i8, i8, i64, i32, i8, i8, i8, i8, %struct.vm_map_entry*, %struct.pmap*, %struct.vm_map_entry* }> + %struct.vm_map_entry = type <{ %struct.vm_map_entry*, %struct.vm_map_entry*, %struct.vm_map_entry*, %struct.vm_map_entry*, i64, i64, i64, i64, i64, %union.sigval, i64, i32, i8, i8, i8, i8, i32, i8, i8, i8, i8, i64, %struct.uidinfo* }> + %struct.vm_object = type <{ %struct.mtx, %1, %2, %1, %3, %struct.vm_page*, i64, i32, i32, i32, i8, i8, i16, i16, i16, i32, %struct.vm_object*, i64, %1, %5, %struct.vm_page*, i8*, %union.anon, %struct.uidinfo*, i64 }> + %struct.vm_page = type <{ %3, %3, %struct.vm_page*, %struct.vm_page*, %struct.vm_object*, i64, i64, %struct.md_page, i8, i8, i16, i8, i8, i16, i32, i16, i16, i8, i8, i8, i8, i8, i8, i8, i8 }> + %struct.vm_reserv = type opaque + %struct.vmspace = type <{ %struct.vm_map, %struct.shmmap_state*, i64, i64, i64, i64, i8*, i8*, i8*, i32, i8, i8, i8, i8, %struct.pmap }> + %struct.vnet = type opaque + %struct.vnode = type <{ i32, i8, i8, i8, i8, i8*, %struct.vop_vector*, i8*, %struct.mount*, %struct.freelst, %union.sigval, %struct.freelst, i32, i8, i8, i8, i8, %21, %22, %struct.namecache*, i64, i64, i64, i32, i8, i8, i8, i8, %struct.lock, %struct.mtx, %struct.lock*, i32, i32, i64, i64, i32, i8, i8, i8, i8, %struct.freelst, %struct.bufobj, %struct.vpollinfo*, %struct.label*, %struct.lockf* }> + %struct.vnodeop_desc = type <{ i8*, i32, i8, i8, i8, i8, i32 (%struct.vop_generic_args*)*, i32*, i32, i32, i32, i32 }> + %struct.vop_access_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, %struct.ucred*, %struct.thread* }> + %struct.vop_aclcheck_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, %struct.acl*, %struct.ucred*, %struct.thread* }> + %struct.vop_advlock_args = type <{ %struct.vop_generic_args, %struct.vnode*, i8*, i32, i8, i8, i8, i8, %struct.flock*, i32, i8, i8, i8, i8 }> + %struct.vop_advlockasync_args = type <{ %struct.vop_generic_args, %struct.vnode*, i8*, i32, i8, i8, i8, i8, %struct.flock*, i32, i8, i8, i8, i8, %struct.task*, i8** }> + %struct.vop_bmap_args = type <{ %struct.vop_generic_args, %struct.vnode*, i64, %struct.bufobj**, i64*, i32*, i32* }> + %struct.vop_cachedlookup_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode**, %struct.componentname* }> + %struct.vop_create_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode**, %struct.componentname*, %struct.vattr* }> + %struct.vop_deleteextattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, i8*, %struct.ucred*, %struct.thread* }> + %struct.vop_fsync_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, %struct.thread* }> + %struct.vop_generic_args = type <{ %struct.vnodeop_desc* }> + %struct.vop_getattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vattr*, %struct.ucred* }> + %struct.vop_getextattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, i8*, %struct.uio*, i64*, %struct.ucred*, %struct.thread* }> + %struct.vop_getpages_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vm_page**, i32, i32, i64 }> + %struct.vop_getwritemount_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.mount** }> + %struct.vop_inactive_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.thread* }> + %struct.vop_ioctl_args = type <{ %struct.vop_generic_args, %struct.vnode*, i64, i8*, i32, i8, i8, i8, i8, %struct.ucred*, %struct.thread* }> + %struct.vop_islocked_args = type <{ %struct.vop_generic_args, %struct.vnode* }> + %struct.vop_kqfilter_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.knote* }> + %struct.vop_link_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode*, %struct.componentname* }> + %struct.vop_listextattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, %struct.uio*, i64*, %struct.ucred*, %struct.thread* }> + %struct.vop_lock1_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, i8*, i32, i8, i8, i8, i8 }> + %struct.vop_open_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, %struct.ucred*, %struct.thread*, %struct.file* }> + %struct.vop_openextattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.ucred*, %struct.thread* }> + %struct.vop_pathconf_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, i64* }> + %struct.vop_putpages_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vm_page**, i32, i32, i32*, i64 }> + %struct.vop_read_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.uio*, i32, i8, i8, i8, i8, %struct.ucred* }> + %struct.vop_readdir_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.uio*, %struct.ucred*, i32*, i32*, i64** }> + %struct.vop_readlink_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.uio*, %struct.ucred* }> + %struct.vop_reallocblks_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.cluster_save* }> + %struct.vop_rename_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode*, %struct.componentname*, %struct.vnode*, %struct.vnode*, %struct.componentname* }> + %struct.vop_revoke_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8 }> + %struct.vop_setextattr_args = type <{ %struct.vop_generic_args, %struct.vnode*, i32, i8, i8, i8, i8, i8*, %struct.uio*, %struct.ucred*, %struct.thread* }> + %struct.vop_setlabel_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.label*, %struct.ucred*, %struct.thread* }> + %struct.vop_strategy_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.buf* }> + %struct.vop_symlink_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode**, %struct.componentname*, %struct.vattr*, i8* }> + %struct.vop_vector = type <{ %struct.vop_vector*, i32 (%struct.vop_generic_args*)*, i32 (%struct.vop_islocked_args*)*, i32 (%struct.vop_cachedlookup_args*)*, i32 (%struct.vop_cachedlookup_args*)*, i32 (%struct.vop_create_args*)*, i32 (%struct.vop_whiteout_args*)*, i32 (%struct.vop_create_args*)*, i32 (%struct.vop_open_args*)*, i32 (%struct.vop_access_args*)*, i32 (%struct.vop_access_args*)*, i32 (%struct.vop_access_args*)*, i32 (%struct.vop_getattr_args*)*, i32 (%struct.vop_getattr_args*)*, i32 (%struct.vop_islocked_args*)*, i32 (%struct.vop_read_args*)*, i32 (%struct.vop_read_args*)*, i32 (%struct.vop_ioctl_args*)*, i32 (%struct.vop_access_args*)*, i32 (%struct.vop_kqfilter_args*)*, i32 (%struct.vop_revoke_args*)*, i32 (%struct.vop_fsync_args*)*, i32 (%struct.vop_link_args*)*, i32 (%struct.vop_link_args*)*, i32 (%struct.vop_rename_args*)*, i32 (%struct.vop_create_args*)*, i32 (%struct.vop_link_args*)*, i32 (%struct.vop_symlink_args*)*, i32 (%struct.vop_readdir_args*)*, i32 (%struct.vop_readlink_args*)*, i32 (%struct.vop_inactive_args*)*, i32 (%struct.vop_inactive_args*)*, i32 (%struct.vop_lock1_args*)*, i32 (%struct.vop_revoke_args*)*, i32 (%struct.vop_bmap_args*)*, i32 (%struct.vop_strategy_args*)*, i32 (%struct.vop_getwritemount_args*)*, i32 (%struct.vop_islocked_args*)*, i32 (%struct.vop_pathconf_args*)*, i32 (%struct.vop_advlock_args*)*, i32 (%struct.vop_advlockasync_args*)*, i32 (%struct.vop_reallocblks_args*)*, i32 (%struct.vop_getpages_args*)*, i32 (%struct.vop_putpages_args*)*, i32 (%struct.vop_aclcheck_args*)*, i32 (%struct.vop_aclcheck_args*)*, i32 (%struct.vop_aclcheck_args*)*, i32 (%struct.vop_access_args*)*, i32 (%struct.vop_getextattr_args*)*, i32 (%struct.vop_listextattr_args*)*, i32 (%struct.vop_openextattr_args*)*, i32 (%struct.vop_deleteextattr_args*)*, i32 (%struct.vop_setextattr_args*)*, i32 (%struct.vop_setlabel_args*)*, i32 (%struct.vop_vptofh_args*)*, i32 (%struct.vop_vptocnp_args*)* }> + %struct.vop_vptocnp_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.vnode**, %struct.ucred*, i8*, i32* }> + %struct.vop_vptofh_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.fid* }> + %struct.vop_whiteout_args = type <{ %struct.vop_generic_args, %struct.vnode*, %struct.componentname*, i32, i8, i8, i8, i8 }> + %struct.vpollinfo = type <{ %struct.mtx, %struct.selinfo, i16, i16, i8, i8, i8, i8 }> + %struct.witness = type opaque + %struct.workhead = type <{ %struct.worklist* }> + %struct.worklist = type opaque + %union.anon = type <{ [16 x i8] }> + %union.pager_info = type <{ [4 x i8] }> + %union.sigval = type <{ [8 x i8] }> + +define i32 @vlrureclaim(%struct.mount* %mp) nounwind { +entry: + br i1 undef, label %if.then11, label %do.end + +if.then11: ; preds = %entry + br label %do.end + +do.end: ; preds = %if.then11, %entry + br label %while.cond.outer + +while.cond.outer: ; preds = %while.cond.outer.backedge, %do.end + %count.0.ph = phi i32 [ undef, %do.end ], [ undef, %while.cond.outer.backedge ] ; <i32> [#uses=1] + br label %while.cond + +while.cond: ; preds = %next_iter, %while.cond.outer + %count.0 = phi i32 [ %dec, %next_iter ], [ %count.0.ph, %while.cond.outer ] ; <i32> [#uses=2] + %cmp21 = icmp eq i32 %count.0, 0 ; <i1> [#uses=1] + br i1 %cmp21, label %do.body288.loopexit4, label %while.body + +while.body: ; preds = %while.cond + br label %while.cond27 + +while.cond27: ; preds = %while.body36, %while.body + br i1 undef, label %do.body288.loopexit, label %land.rhs + +land.rhs: ; preds = %while.cond27 + br i1 undef, label %while.body36, label %while.end + +while.body36: ; preds = %land.rhs + br label %while.cond27 + +while.end: ; preds = %land.rhs + br i1 undef, label %do.body288.loopexit4, label %do.body46 + +do.body46: ; preds = %while.end + br i1 undef, label %if.else64, label %if.then53 + +if.then53: ; preds = %do.body46 + br label %if.end72 + +if.else64: ; preds = %do.body46 + br label %if.end72 + +if.end72: ; preds = %if.else64, %if.then53 + %dec = add i32 %count.0, -1 ; <i32> [#uses=2] + br i1 undef, label %next_iter, label %if.end111 + +if.end111: ; preds = %if.end72 + br i1 undef, label %lor.lhs.false, label %do.body145 + +lor.lhs.false: ; preds = %if.end111 + br i1 undef, label %lor.lhs.false122, label %do.body145 + +lor.lhs.false122: ; preds = %lor.lhs.false + br i1 undef, label %lor.lhs.false128, label %do.body145 + +lor.lhs.false128: ; preds = %lor.lhs.false122 + br i1 undef, label %do.body162, label %land.lhs.true + +land.lhs.true: ; preds = %lor.lhs.false128 + br i1 undef, label %do.body145, label %do.body162 + +do.body145: ; preds = %land.lhs.true, %lor.lhs.false122, %lor.lhs.false, %if.end111 + br i1 undef, label %if.then156, label %next_iter + +if.then156: ; preds = %do.body145 + br label %next_iter + +do.body162: ; preds = %land.lhs.true, %lor.lhs.false128 + br i1 undef, label %if.then173, label %do.end177 + +if.then173: ; preds = %do.body162 + br label %do.end177 + +do.end177: ; preds = %if.then173, %do.body162 + br i1 undef, label %do.body185, label %if.then182 + +if.then182: ; preds = %do.end177 + br label %next_iter_mntunlocked + +do.body185: ; preds = %do.end177 + br i1 undef, label %if.then196, label %do.end202 + +if.then196: ; preds = %do.body185 + br label %do.end202 + +do.end202: ; preds = %if.then196, %do.body185 + br i1 undef, label %lor.lhs.false207, label %if.then231 + +lor.lhs.false207: ; preds = %do.end202 + br i1 undef, label %lor.lhs.false214, label %if.then231 + +lor.lhs.false214: ; preds = %lor.lhs.false207 + br i1 undef, label %do.end236, label %land.lhs.true221 + +land.lhs.true221: ; preds = %lor.lhs.false214 + br i1 undef, label %if.then231, label %do.end236 + +if.then231: ; preds = %land.lhs.true221, %lor.lhs.false207, %do.end202 + br label %next_iter_mntunlocked + +do.end236: ; preds = %land.lhs.true221, %lor.lhs.false214 + br label %next_iter_mntunlocked + +next_iter_mntunlocked: ; preds = %do.end236, %if.then231, %if.then182 + br i1 undef, label %yield, label %do.body269 + +next_iter: ; preds = %if.then156, %do.body145, %if.end72 + %rem2482 = and i32 %dec, 255 ; <i32> [#uses=1] + %cmp249 = icmp eq i32 %rem2482, 0 ; <i1> [#uses=1] + br i1 %cmp249, label %do.body253, label %while.cond + +do.body253: ; preds = %next_iter + br i1 undef, label %if.then264, label %yield + +if.then264: ; preds = %do.body253 + br label %yield + +yield: ; preds = %if.then264, %do.body253, %next_iter_mntunlocked + br label %do.body269 + +do.body269: ; preds = %yield, %next_iter_mntunlocked + br i1 undef, label %if.then280, label %while.cond.outer.backedge + +if.then280: ; preds = %do.body269 + br label %while.cond.outer.backedge + +while.cond.outer.backedge: ; preds = %if.then280, %do.body269 + br label %while.cond.outer + +do.body288.loopexit: ; preds = %while.cond27 + br label %do.body288 + +do.body288.loopexit4: ; preds = %while.end, %while.cond + br label %do.body288 + +do.body288: ; preds = %do.body288.loopexit4, %do.body288.loopexit + br i1 undef, label %if.then299, label %do.end303 + +if.then299: ; preds = %do.body288 + br label %do.end303 + +do.end303: ; preds = %if.then299, %do.body288 + ret i32 undef +} diff --git a/test/Analysis/ScalarEvolution/avoid-smax-0.ll b/test/Analysis/ScalarEvolution/avoid-smax-0.ll new file mode 100644 index 00000000000..3d15c787fcf --- /dev/null +++ b/test/Analysis/ScalarEvolution/avoid-smax-0.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -scalar-evolution -analyze | grep "Loop %bb3: backedge-taken count is (-1 + %n)" + +; We don't want to use a max in the trip count expression in +; this testcase. + +define void @foo(i32 %n, i32* %p, i32* %q) nounwind { +entry: + icmp sgt i32 %n, 0 + br i1 %0, label %bb, label %return + +bb: + load i32* %q, align 4 + icmp eq i32 %1, 0 + br i1 %2, label %return, label %bb3.preheader + +bb3.preheader: + br label %bb3 + +bb3: + %i.0 = phi i32 [ %7, %bb3 ], [ 0, %bb3.preheader ] + getelementptr i32* %p, i32 %i.0 + load i32* %3, align 4 + add i32 %4, 1 + getelementptr i32* %p, i32 %i.0 + store i32 %5, i32* %6, align 4 + add i32 %i.0, 1 + icmp slt i32 %7, %n + br i1 %8, label %bb3, label %return.loopexit + +return.loopexit: + br label %return + +return: + ret void +} diff --git a/test/Analysis/ScalarEvolution/avoid-smax-1.ll b/test/Analysis/ScalarEvolution/avoid-smax-1.ll new file mode 100644 index 00000000000..d9b83a929aa --- /dev/null +++ b/test/Analysis/ScalarEvolution/avoid-smax-1.ll @@ -0,0 +1,234 @@ +; RUN: opt < %s -analyze -scalar-evolution -S | FileCheck %s + +; Indvars should be able to find the trip count for the bb6 loop +; without using a maximum calculation (icmp, select) because it should +; be able to prove that the comparison is guarded by an appropriate +; conditional branch. Unfortunately, indvars is not yet able to find +; the comparison for the other two loops in this testcase. +; +; CHECK: Loop %bb6: backedge-taken count is (-1 + %w) + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin9" + +define void @foo(i8* %r, i32 %s, i32 %w, i32 %x, i8* %j, i32 %d) nounwind { +entry: + %0 = mul i32 %x, %w ; <i32> [#uses=2] + %1 = mul i32 %x, %w ; <i32> [#uses=1] + %2 = sdiv i32 %1, 4 ; <i32> [#uses=1] + %.sum2 = add i32 %2, %0 ; <i32> [#uses=2] + %cond = icmp eq i32 %d, 1 ; <i1> [#uses=1] + br i1 %cond, label %bb29, label %bb10.preheader + +bb10.preheader: ; preds = %entry + %3 = icmp sgt i32 %x, 0 ; <i1> [#uses=1] + br i1 %3, label %bb.nph9, label %bb18.loopexit + +bb.nph7: ; preds = %bb7.preheader + %4 = mul i32 %y.08, %w ; <i32> [#uses=1] + %5 = mul i32 %y.08, %s ; <i32> [#uses=1] + %6 = add i32 %5, 1 ; <i32> [#uses=1] + br label %bb6 + +bb6: ; preds = %bb7, %bb.nph7 + %x.06 = phi i32 [ %13, %bb7 ], [ 0, %bb.nph7 ] ; <i32> [#uses=3] + %7 = add i32 %x.06, %4 ; <i32> [#uses=1] + %8 = shl i32 %x.06, 1 ; <i32> [#uses=1] + %9 = add i32 %6, %8 ; <i32> [#uses=1] + %10 = getelementptr i8* %r, i32 %9 ; <i8*> [#uses=1] + %11 = load i8* %10, align 1 ; <i8> [#uses=1] + %12 = getelementptr i8* %j, i32 %7 ; <i8*> [#uses=1] + store i8 %11, i8* %12, align 1 + %13 = add i32 %x.06, 1 ; <i32> [#uses=2] + br label %bb7 + +bb7: ; preds = %bb6 + %14 = icmp slt i32 %13, %w ; <i1> [#uses=1] + br i1 %14, label %bb6, label %bb7.bb9_crit_edge + +bb7.bb9_crit_edge: ; preds = %bb7 + br label %bb9 + +bb9: ; preds = %bb7.preheader, %bb7.bb9_crit_edge + %15 = add i32 %y.08, 1 ; <i32> [#uses=2] + br label %bb10 + +bb10: ; preds = %bb9 + %16 = icmp slt i32 %15, %x ; <i1> [#uses=1] + br i1 %16, label %bb7.preheader, label %bb10.bb18.loopexit_crit_edge + +bb10.bb18.loopexit_crit_edge: ; preds = %bb10 + br label %bb10.bb18.loopexit_crit_edge.split + +bb10.bb18.loopexit_crit_edge.split: ; preds = %bb.nph9, %bb10.bb18.loopexit_crit_edge + br label %bb18.loopexit + +bb.nph9: ; preds = %bb10.preheader + %17 = icmp sgt i32 %w, 0 ; <i1> [#uses=1] + br i1 %17, label %bb.nph9.split, label %bb10.bb18.loopexit_crit_edge.split + +bb.nph9.split: ; preds = %bb.nph9 + br label %bb7.preheader + +bb7.preheader: ; preds = %bb.nph9.split, %bb10 + %y.08 = phi i32 [ %15, %bb10 ], [ 0, %bb.nph9.split ] ; <i32> [#uses=3] + br i1 true, label %bb.nph7, label %bb9 + +bb.nph5: ; preds = %bb18.loopexit + %18 = sdiv i32 %w, 2 ; <i32> [#uses=1] + %19 = icmp slt i32 %w, 2 ; <i1> [#uses=1] + %20 = sdiv i32 %x, 2 ; <i32> [#uses=1] + br i1 %19, label %bb18.bb20_crit_edge.split, label %bb.nph5.split + +bb.nph5.split: ; preds = %bb.nph5 + br label %bb13 + +bb13: ; preds = %bb18, %bb.nph5.split + %y.14 = phi i32 [ %42, %bb18 ], [ 0, %bb.nph5.split ] ; <i32> [#uses=4] + %21 = mul i32 %18, %y.14 ; <i32> [#uses=2] + %22 = shl i32 %y.14, 1 ; <i32> [#uses=1] + %23 = srem i32 %y.14, 2 ; <i32> [#uses=1] + %24 = add i32 %23, %22 ; <i32> [#uses=1] + %25 = mul i32 %24, %s ; <i32> [#uses=2] + br i1 true, label %bb.nph3, label %bb17 + +bb.nph3: ; preds = %bb13 + %26 = add i32 %21, %0 ; <i32> [#uses=1] + %27 = add i32 %21, %.sum2 ; <i32> [#uses=1] + %28 = sdiv i32 %w, 2 ; <i32> [#uses=1] + br label %bb14 + +bb14: ; preds = %bb15, %bb.nph3 + %x.12 = phi i32 [ %40, %bb15 ], [ 0, %bb.nph3 ] ; <i32> [#uses=5] + %29 = shl i32 %x.12, 2 ; <i32> [#uses=1] + %30 = add i32 %29, %25 ; <i32> [#uses=1] + %31 = getelementptr i8* %r, i32 %30 ; <i8*> [#uses=1] + %32 = load i8* %31, align 1 ; <i8> [#uses=1] + %.sum = add i32 %26, %x.12 ; <i32> [#uses=1] + %33 = getelementptr i8* %j, i32 %.sum ; <i8*> [#uses=1] + store i8 %32, i8* %33, align 1 + %34 = shl i32 %x.12, 2 ; <i32> [#uses=1] + %35 = or i32 %34, 2 ; <i32> [#uses=1] + %36 = add i32 %35, %25 ; <i32> [#uses=1] + %37 = getelementptr i8* %r, i32 %36 ; <i8*> [#uses=1] + %38 = load i8* %37, align 1 ; <i8> [#uses=1] + %.sum6 = add i32 %27, %x.12 ; <i32> [#uses=1] + %39 = getelementptr i8* %j, i32 %.sum6 ; <i8*> [#uses=1] + store i8 %38, i8* %39, align 1 + %40 = add i32 %x.12, 1 ; <i32> [#uses=2] + br label %bb15 + +bb15: ; preds = %bb14 + %41 = icmp sgt i32 %28, %40 ; <i1> [#uses=1] + br i1 %41, label %bb14, label %bb15.bb17_crit_edge + +bb15.bb17_crit_edge: ; preds = %bb15 + br label %bb17 + +bb17: ; preds = %bb15.bb17_crit_edge, %bb13 + %42 = add i32 %y.14, 1 ; <i32> [#uses=2] + br label %bb18 + +bb18.loopexit: ; preds = %bb10.bb18.loopexit_crit_edge.split, %bb10.preheader + %43 = icmp slt i32 %x, 2 ; <i1> [#uses=1] + br i1 %43, label %bb20, label %bb.nph5 + +bb18: ; preds = %bb17 + %44 = icmp sgt i32 %20, %42 ; <i1> [#uses=1] + br i1 %44, label %bb13, label %bb18.bb20_crit_edge + +bb18.bb20_crit_edge: ; preds = %bb18 + br label %bb18.bb20_crit_edge.split + +bb18.bb20_crit_edge.split: ; preds = %bb18.bb20_crit_edge, %bb.nph5 + br label %bb20 + +bb20: ; preds = %bb18.bb20_crit_edge.split, %bb18.loopexit + switch i32 %d, label %return [ + i32 3, label %bb22 + i32 1, label %bb29 + ] + +bb22: ; preds = %bb20 + %45 = mul i32 %x, %w ; <i32> [#uses=1] + %46 = sdiv i32 %45, 4 ; <i32> [#uses=1] + %.sum3 = add i32 %46, %.sum2 ; <i32> [#uses=2] + %47 = add i32 %x, 15 ; <i32> [#uses=1] + %48 = and i32 %47, -16 ; <i32> [#uses=1] + %49 = add i32 %w, 15 ; <i32> [#uses=1] + %50 = and i32 %49, -16 ; <i32> [#uses=1] + %51 = mul i32 %48, %s ; <i32> [#uses=1] + %52 = icmp sgt i32 %x, 0 ; <i1> [#uses=1] + br i1 %52, label %bb.nph, label %bb26 + +bb.nph: ; preds = %bb22 + br label %bb23 + +bb23: ; preds = %bb24, %bb.nph + %y.21 = phi i32 [ %57, %bb24 ], [ 0, %bb.nph ] ; <i32> [#uses=3] + %53 = mul i32 %y.21, %50 ; <i32> [#uses=1] + %.sum1 = add i32 %53, %51 ; <i32> [#uses=1] + %54 = getelementptr i8* %r, i32 %.sum1 ; <i8*> [#uses=1] + %55 = mul i32 %y.21, %w ; <i32> [#uses=1] + %.sum5 = add i32 %55, %.sum3 ; <i32> [#uses=1] + %56 = getelementptr i8* %j, i32 %.sum5 ; <i8*> [#uses=1] + tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %56, i8* %54, i32 %w, i32 1, i1 false) + %57 = add i32 %y.21, 1 ; <i32> [#uses=2] + br label %bb24 + +bb24: ; preds = %bb23 + %58 = icmp slt i32 %57, %x ; <i1> [#uses=1] + br i1 %58, label %bb23, label %bb24.bb26_crit_edge + +bb24.bb26_crit_edge: ; preds = %bb24 + br label %bb26 + +bb26: ; preds = %bb24.bb26_crit_edge, %bb22 + %59 = mul i32 %x, %w ; <i32> [#uses=1] + %.sum4 = add i32 %.sum3, %59 ; <i32> [#uses=1] + %60 = getelementptr i8* %j, i32 %.sum4 ; <i8*> [#uses=1] + %61 = mul i32 %x, %w ; <i32> [#uses=1] + %62 = sdiv i32 %61, 2 ; <i32> [#uses=1] + tail call void @llvm.memset.p0i8.i32(i8* %60, i8 -128, i32 %62, i32 1, i1 false) + ret void + +bb29: ; preds = %bb20, %entry + %63 = add i32 %w, 15 ; <i32> [#uses=1] + %64 = and i32 %63, -16 ; <i32> [#uses=1] + %65 = icmp sgt i32 %x, 0 ; <i1> [#uses=1] + br i1 %65, label %bb.nph11, label %bb33 + +bb.nph11: ; preds = %bb29 + br label %bb30 + +bb30: ; preds = %bb31, %bb.nph11 + %y.310 = phi i32 [ %70, %bb31 ], [ 0, %bb.nph11 ] ; <i32> [#uses=3] + %66 = mul i32 %y.310, %64 ; <i32> [#uses=1] + %67 = getelementptr i8* %r, i32 %66 ; <i8*> [#uses=1] + %68 = mul i32 %y.310, %w ; <i32> [#uses=1] + %69 = getelementptr i8* %j, i32 %68 ; <i8*> [#uses=1] + tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %69, i8* %67, i32 %w, i32 1, i1 false) + %70 = add i32 %y.310, 1 ; <i32> [#uses=2] + br label %bb31 + +bb31: ; preds = %bb30 + %71 = icmp slt i32 %70, %x ; <i1> [#uses=1] + br i1 %71, label %bb30, label %bb31.bb33_crit_edge + +bb31.bb33_crit_edge: ; preds = %bb31 + br label %bb33 + +bb33: ; preds = %bb31.bb33_crit_edge, %bb29 + %72 = mul i32 %x, %w ; <i32> [#uses=1] + %73 = getelementptr i8* %j, i32 %72 ; <i8*> [#uses=1] + %74 = mul i32 %x, %w ; <i32> [#uses=1] + %75 = sdiv i32 %74, 2 ; <i32> [#uses=1] + tail call void @llvm.memset.p0i8.i32(i8* %73, i8 -128, i32 %75, i32 1, i1 false) + ret void + +return: ; preds = %bb20 + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) nounwind diff --git a/test/Analysis/ScalarEvolution/div-overflow.ll b/test/Analysis/ScalarEvolution/div-overflow.ll new file mode 100644 index 00000000000..28467975606 --- /dev/null +++ b/test/Analysis/ScalarEvolution/div-overflow.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -scalar-evolution -analyze \ +; RUN: | grep "\--> ((-128 \* %a) /u -128)" + +; Don't let ScalarEvolution fold this div away. + +define i8 @foo(i8 %a) { + %t0 = shl i8 %a, 7 + %t1 = lshr i8 %t0, 7 + ret i8 %t1 +} diff --git a/test/Analysis/ScalarEvolution/do-loop.ll b/test/Analysis/ScalarEvolution/do-loop.ll new file mode 100644 index 00000000000..6e3295a920b --- /dev/null +++ b/test/Analysis/ScalarEvolution/do-loop.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep smax +; PR1614 + +define i32 @f(i32 %x, i32 %y) { +entry: + br label %bb + +bb: ; preds = %bb, %entry + %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb ] ; <i32> [#uses=2] + %x_addr.0 = add i32 %indvar, %x ; <i32> [#uses=1] + %tmp2 = add i32 %x_addr.0, 1 ; <i32> [#uses=2] + %tmp5 = icmp slt i32 %tmp2, %y ; <i1> [#uses=1] + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br i1 %tmp5, label %bb, label %bb7 + +bb7: ; preds = %bb + ret i32 %tmp2 +} diff --git a/test/Analysis/ScalarEvolution/fold.ll b/test/Analysis/ScalarEvolution/fold.ll new file mode 100644 index 00000000000..4e2adf187e8 --- /dev/null +++ b/test/Analysis/ScalarEvolution/fold.ll @@ -0,0 +1,62 @@ +; RUN: opt -analyze -scalar-evolution %s -S | FileCheck %s + +define i16 @test1(i8 %x) { + %A = zext i8 %x to i12 + %B = sext i12 %A to i16 +; CHECK: zext i8 %x to i16 + ret i16 %B +} + +define i8 @test2(i8 %x) { + %A = zext i8 %x to i16 + %B = add i16 %A, 1025 + %C = trunc i16 %B to i8 +; CHECK: (1 + %x) + ret i8 %C +} + +define i8 @test3(i8 %x) { + %A = zext i8 %x to i16 + %B = mul i16 %A, 1027 + %C = trunc i16 %B to i8 +; CHECK: (3 * %x) + ret i8 %C +} + +define void @test4(i32 %x, i32 %y) { +entry: + %Y = and i32 %y, 3 + br label %loop +loop: + %A = phi i32 [0, %entry], [%I, %loop] + %rand1 = icmp sgt i32 %A, %Y + %Z1 = select i1 %rand1, i32 %A, i32 %Y + %rand2 = icmp ugt i32 %A, %Z1 + %Z2 = select i1 %rand2, i32 %A, i32 %Z1 +; CHECK: %Z2 = +; CHECK-NEXT: --> ([[EXPR:.*]]){{ +}}Exits: 20 + %B = trunc i32 %Z2 to i16 + %C = sext i16 %B to i30 +; CHECK: %C = +; CHECK-NEXT: (trunc i32 ([[EXPR]]) to i30) + %D = sext i16 %B to i32 +; CHECK: %D = +; CHECK-NEXT: ([[EXPR]]) + %E = sext i16 %B to i34 +; CHECK: %E = +; CHECK-NEXT: (zext i32 ([[EXPR]]) to i34) + %F = zext i16 %B to i30 +; CHECK: %F = +; CHECK-NEXT: (trunc i32 ([[EXPR]]) to i30 + %G = zext i16 %B to i32 +; CHECK: %G = +; CHECK-NEXT: ([[EXPR]]) + %H = zext i16 %B to i34 +; CHECK: %H = +; CHECK-NEXT: (zext i32 ([[EXPR]]) to i34) + %I = add i32 %A, 1 + %0 = icmp ne i32 %A, 20 + br i1 %0, label %loop, label %exit +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/how-far-to-zero.ll b/test/Analysis/ScalarEvolution/how-far-to-zero.ll new file mode 100644 index 00000000000..07af88ffbeb --- /dev/null +++ b/test/Analysis/ScalarEvolution/how-far-to-zero.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; PR13228 +define void @f() nounwind uwtable readnone { +entry: + br label %for.cond + +for.cond: ; preds = %for.cond, %entry + %c.0 = phi i8 [ 1, %entry ], [ 0, %for.cond ] + %i.0 = phi i8 [ 0, %entry ], [ %inc, %for.cond ] + %lnot = icmp eq i8 %i.0, 0 + %inc = add i8 %i.0, 1 + br i1 %lnot, label %for.cond, label %while.cond + +while.cond: ; preds = %while.body, %for.cond + %b.2 = phi i8 [ %add, %while.body ], [ 0, %for.cond ] + br i1 undef, label %while.end, label %while.body + +while.body: ; preds = %while.cond + %add = add i8 %b.2, %c.0 + %tobool7 = icmp eq i8 %add, 0 + br i1 %tobool7, label %while.end, label %while.cond + +while.end: ; preds = %while.body, %while.cond + ret void +} +;CHECK: Loop %while.cond: <multiple exits> Unpredictable backedge-taken count. diff --git a/test/Analysis/ScalarEvolution/lit.local.cfg b/test/Analysis/ScalarEvolution/lit.local.cfg new file mode 100644 index 00000000000..c6106e4746f --- /dev/null +++ b/test/Analysis/ScalarEvolution/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll'] diff --git a/test/Analysis/ScalarEvolution/load.ll b/test/Analysis/ScalarEvolution/load.ll new file mode 100644 index 00000000000..2c753f5befc --- /dev/null +++ b/test/Analysis/ScalarEvolution/load.ll @@ -0,0 +1,65 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" +target triple = "i386-pc-linux-gnu" + +@arr1 = internal unnamed_addr constant [50 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 32, i32 33, i32 34, i32 35, i32 36, i32 37, i32 38, i32 39, i32 40, i32 41, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49, i32 50], align 4 +@arr2 = internal unnamed_addr constant [50 x i32] [i32 49, i32 48, i32 47, i32 46, i32 45, i32 44, i32 43, i32 42, i32 41, i32 40, i32 39, i32 38, i32 37, i32 36, i32 35, i32 34, i32 33, i32 32, i32 31, i32 30, i32 29, i32 28, i32 27, i32 26, i32 25, i32 24, i32 23, i32 22, i32 21, i32 20, i32 19, i32 18, i32 17, i32 16, i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0], align 4 + +; PR11034 +define i32 @test1() nounwind readnone { +; CHECK: test1 +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.04 = phi i32 [ 0, %entry ], [ %add2, %for.body ] +; CHECK: --> %sum.04{{ *}}Exits: 2450 + %i.03 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds [50 x i32]* @arr1, i32 0, i32 %i.03 + %0 = load i32* %arrayidx, align 4 +; CHECK: --> %0{{ *}}Exits: 50 + %arrayidx1 = getelementptr inbounds [50 x i32]* @arr2, i32 0, i32 %i.03 + %1 = load i32* %arrayidx1, align 4 +; CHECK: --> %1{{ *}}Exits: 0 + %add = add i32 %0, %sum.04 + %add2 = add i32 %add, %1 + %inc = add nsw i32 %i.03, 1 + %cmp = icmp eq i32 %inc, 50 + br i1 %cmp, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret i32 %add2 +} + + +%struct.ListNode = type { %struct.ListNode*, i32 } + +@node5 = internal constant { %struct.ListNode*, i32, [4 x i8] } { %struct.ListNode* bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node4 to %struct.ListNode*), i32 4, [4 x i8] undef }, align 8 +@node4 = internal constant { %struct.ListNode*, i32, [4 x i8] } { %struct.ListNode* bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node3 to %struct.ListNode*), i32 3, [4 x i8] undef }, align 8 +@node3 = internal constant { %struct.ListNode*, i32, [4 x i8] } { %struct.ListNode* bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node2 to %struct.ListNode*), i32 2, [4 x i8] undef }, align 8 +@node2 = internal constant { %struct.ListNode*, i32, [4 x i8] } { %struct.ListNode* bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node1 to %struct.ListNode*), i32 1, [4 x i8] undef }, align 8 +@node1 = internal constant { %struct.ListNode*, i32, [4 x i8] } { %struct.ListNode* null, i32 0, [4 x i8] undef }, align 8 + +define i32 @test2() nounwind uwtable readonly { +; CHECK: test2 +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.02 = phi i32 [ 0, %entry ], [ %add, %for.body ] +; CHECK: --> %sum.02{{ *}}Exits: 10 + %n.01 = phi %struct.ListNode* [ bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node5 to %struct.ListNode*), %entry ], [ %1, %for.body ] +; CHECK: --> %n.01{{ *}}Exits: @node1 + %i = getelementptr inbounds %struct.ListNode* %n.01, i64 0, i32 1 + %0 = load i32* %i, align 4 + %add = add nsw i32 %0, %sum.02 + %next = getelementptr inbounds %struct.ListNode* %n.01, i64 0, i32 0 + %1 = load %struct.ListNode** %next, align 8 +; CHECK: --> %1{{ *}}Exits: 0 + %cmp = icmp eq %struct.ListNode* %1, null + br i1 %cmp, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret i32 %add +} diff --git a/test/Analysis/ScalarEvolution/max-trip-count.ll b/test/Analysis/ScalarEvolution/max-trip-count.ll new file mode 100644 index 00000000000..0cdbdf57a64 --- /dev/null +++ b/test/Analysis/ScalarEvolution/max-trip-count.ll @@ -0,0 +1,100 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; ScalarEvolution should be able to understand the loop and eliminate the casts. + +; CHECK: {%d,+,sizeof(i32)} + +define void @foo(i32* nocapture %d, i32 %n) nounwind { +entry: + %0 = icmp sgt i32 %n, 0 ; <i1> [#uses=1] + br i1 %0, label %bb.nph, label %return + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %i.02 = phi i32 [ %5, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=2] + %p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ] ; <i8> [#uses=2] + %1 = sext i8 %p.01 to i32 ; <i32> [#uses=1] + %2 = sext i32 %i.02 to i64 ; <i64> [#uses=1] + %3 = getelementptr i32* %d, i64 %2 ; <i32*> [#uses=1] + store i32 %1, i32* %3, align 4 + %4 = add i8 %p.01, 1 ; <i8> [#uses=1] + %5 = add i32 %i.02, 1 ; <i32> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %6 = icmp slt i32 %5, %n ; <i1> [#uses=1] + br i1 %6, label %bb, label %bb1.return_crit_edge + +bb1.return_crit_edge: ; preds = %bb1 + br label %return + +return: ; preds = %bb1.return_crit_edge, %entry + ret void +} + +; ScalarEvolution should be able to find the maximum tripcount +; of this multiple-exit loop, and if it doesn't know the exact +; count, it should say so. + +; PR7845 +; CHECK: Loop %for.cond: <multiple exits> Unpredictable backedge-taken count. +; CHECK: Loop %for.cond: max backedge-taken count is 5 + +@.str = private constant [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=2] + +define i32 @main() nounwind { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %g_4.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ] ; <i32> [#uses=5] + %cmp = icmp slt i32 %g_4.0, 5 ; <i1> [#uses=1] + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %conv = trunc i32 %g_4.0 to i16 ; <i16> [#uses=1] + %tobool.not = icmp eq i16 %conv, 0 ; <i1> [#uses=1] + %tobool3 = icmp ne i32 %g_4.0, 0 ; <i1> [#uses=1] + %or.cond = and i1 %tobool.not, %tobool3 ; <i1> [#uses=1] + br i1 %or.cond, label %for.end, label %for.inc + +for.inc: ; preds = %for.body + %add = add nsw i32 %g_4.0, 1 ; <i32> [#uses=1] + br label %for.cond + +for.end: ; preds = %for.body, %for.cond + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %g_4.0) nounwind ; <i32> [#uses=0] + ret i32 0 +} + +declare i32 @printf(i8*, ...) + +define void @test(i8* %a, i32 %n) nounwind { +entry: + %cmp1 = icmp sgt i32 %n, 0 + br i1 %cmp1, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + %tmp = zext i32 %n to i64 + br label %for.body + +for.body: ; preds = %for.body, %for.body.lr.ph + %indvar = phi i64 [ %indvar.next, %for.body ], [ 0, %for.body.lr.ph ] + %arrayidx = getelementptr i8* %a, i64 %indvar + store i8 0, i8* %arrayidx, align 1 + %indvar.next = add i64 %indvar, 1 + %exitcond = icmp ne i64 %indvar.next, %tmp + br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.body + br label %for.end + +for.end: ; preds = %for.cond.for.end_crit_edge, %entry + ret void +} + +; CHECK: Determining loop execution counts for: @test +; CHECK-NEXT: backedge-taken count is +; CHECK-NEXT: max backedge-taken count is -1 diff --git a/test/Analysis/ScalarEvolution/nsw-offset.ll b/test/Analysis/ScalarEvolution/nsw-offset.ll new file mode 100644 index 00000000000..8969a5ad4ce --- /dev/null +++ b/test/Analysis/ScalarEvolution/nsw-offset.ll @@ -0,0 +1,77 @@ +; RUN: opt < %s -S -analyze -scalar-evolution | FileCheck %s + +; ScalarEvolution should be able to fold away the sign-extensions +; on this loop with a primary induction variable incremented with +; a nsw add of 2. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + +define void @foo(i32 %no, double* nocapture %d, double* nocapture %q) nounwind { +entry: + %n = and i32 %no, 4294967294 + %0 = icmp sgt i32 %n, 0 ; <i1> [#uses=1] + br i1 %0, label %bb.nph, label %return + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb.nph, %bb1 + %i.01 = phi i32 [ %16, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=5] + +; CHECK: %1 = sext i32 %i.01 to i64 +; CHECK: --> {0,+,2}<nuw><nsw><%bb> + %1 = sext i32 %i.01 to i64 ; <i64> [#uses=1] + +; CHECK: %2 = getelementptr inbounds double* %d, i64 %1 +; CHECK: --> {%d,+,16}<nsw><%bb> + %2 = getelementptr inbounds double* %d, i64 %1 ; <double*> [#uses=1] + + %3 = load double* %2, align 8 ; <double> [#uses=1] + %4 = sext i32 %i.01 to i64 ; <i64> [#uses=1] + %5 = getelementptr inbounds double* %q, i64 %4 ; <double*> [#uses=1] + %6 = load double* %5, align 8 ; <double> [#uses=1] + %7 = or i32 %i.01, 1 ; <i32> [#uses=1] + +; CHECK: %8 = sext i32 %7 to i64 +; CHECK: --> {1,+,2}<nuw><nsw><%bb> + %8 = sext i32 %7 to i64 ; <i64> [#uses=1] + +; CHECK: %9 = getelementptr inbounds double* %q, i64 %8 +; CHECK: {(8 + %q),+,16}<nsw><%bb> + %9 = getelementptr inbounds double* %q, i64 %8 ; <double*> [#uses=1] + +; Artificially repeat the above three instructions, this time using +; add nsw instead of or. + %t7 = add nsw i32 %i.01, 1 ; <i32> [#uses=1] + +; CHECK: %t8 = sext i32 %t7 to i64 +; CHECK: --> {1,+,2}<nuw><nsw><%bb> + %t8 = sext i32 %t7 to i64 ; <i64> [#uses=1] + +; CHECK: %t9 = getelementptr inbounds double* %q, i64 %t8 +; CHECK: {(8 + %q),+,16}<nsw><%bb> + %t9 = getelementptr inbounds double* %q, i64 %t8 ; <double*> [#uses=1] + + %10 = load double* %9, align 8 ; <double> [#uses=1] + %11 = fadd double %6, %10 ; <double> [#uses=1] + %12 = fadd double %11, 3.200000e+00 ; <double> [#uses=1] + %13 = fmul double %3, %12 ; <double> [#uses=1] + %14 = sext i32 %i.01 to i64 ; <i64> [#uses=1] + %15 = getelementptr inbounds double* %d, i64 %14 ; <double*> [#uses=1] + store double %13, double* %15, align 8 + %16 = add nsw i32 %i.01, 2 ; <i32> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %17 = icmp slt i32 %16, %n ; <i1> [#uses=1] + br i1 %17, label %bb, label %bb1.return_crit_edge + +bb1.return_crit_edge: ; preds = %bb1 + br label %return + +return: ; preds = %bb1.return_crit_edge, %entry + ret void +} + +; CHECK: Loop %bb: backedge-taken count is ((-1 + %n) /u 2) +; CHECK: Loop %bb: max backedge-taken count is 1073741822 diff --git a/test/Analysis/ScalarEvolution/nsw.ll b/test/Analysis/ScalarEvolution/nsw.ll new file mode 100644 index 00000000000..659cf4f8da9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/nsw.ll @@ -0,0 +1,124 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; The addrecs in this loop are analyzable only by using nsw information. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + +; CHECK: Classifying expressions for: @test1 +define void @test1(double* %p) nounwind { +entry: + %tmp = load double* %p, align 8 ; <double> [#uses=1] + %tmp1 = fcmp ogt double %tmp, 2.000000e+00 ; <i1> [#uses=1] + br i1 %tmp1, label %bb.nph, label %return + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %i.01 = phi i32 [ %tmp8, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=3] +; CHECK: %i.01 +; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%bb> + %tmp2 = sext i32 %i.01 to i64 ; <i64> [#uses=1] + %tmp3 = getelementptr double* %p, i64 %tmp2 ; <double*> [#uses=1] + %tmp4 = load double* %tmp3, align 8 ; <double> [#uses=1] + %tmp5 = fmul double %tmp4, 9.200000e+00 ; <double> [#uses=1] + %tmp6 = sext i32 %i.01 to i64 ; <i64> [#uses=1] + %tmp7 = getelementptr double* %p, i64 %tmp6 ; <double*> [#uses=1] +; CHECK: %tmp7 +; CHECK-NEXT: --> {%p,+,8}<%bb> + store double %tmp5, double* %tmp7, align 8 + %tmp8 = add nsw i32 %i.01, 1 ; <i32> [#uses=2] +; CHECK: %tmp8 +; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%bb> + br label %bb1 + +bb1: ; preds = %bb + %phitmp = sext i32 %tmp8 to i64 ; <i64> [#uses=1] +; CHECK: %phitmp +; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%bb> + %tmp9 = getelementptr double* %p, i64 %phitmp ; <double*> [#uses=1] +; CHECK: %tmp9 +; CHECK-NEXT: --> {(8 + %p),+,8}<%bb> + %tmp10 = load double* %tmp9, align 8 ; <double> [#uses=1] + %tmp11 = fcmp ogt double %tmp10, 2.000000e+00 ; <i1> [#uses=1] + br i1 %tmp11, label %bb, label %bb1.return_crit_edge + +bb1.return_crit_edge: ; preds = %bb1 + br label %return + +return: ; preds = %bb1.return_crit_edge, %entry + ret void +} + +; CHECK: Classifying expressions for: @test2 +define void @test2(i32* %begin, i32* %end) ssp { +entry: + %cmp1.i.i = icmp eq i32* %begin, %end + br i1 %cmp1.i.i, label %_ZSt4fillIPiiEvT_S1_RKT0_.exit, label %for.body.lr.ph.i.i + +for.body.lr.ph.i.i: ; preds = %entry + br label %for.body.i.i + +for.body.i.i: ; preds = %for.body.i.i, %for.body.lr.ph.i.i + %__first.addr.02.i.i = phi i32* [ %begin, %for.body.lr.ph.i.i ], [ %ptrincdec.i.i, %for.body.i.i ] +; CHECK: %__first.addr.02.i.i +; CHECK-NEXT: --> {%begin,+,4}<nw><%for.body.i.i> + store i32 0, i32* %__first.addr.02.i.i, align 4 + %ptrincdec.i.i = getelementptr inbounds i32* %__first.addr.02.i.i, i64 1 +; CHECK: %ptrincdec.i.i +; CHECK-NEXT: --> {(4 + %begin),+,4}<nw><%for.body.i.i> + %cmp.i.i = icmp eq i32* %ptrincdec.i.i, %end + br i1 %cmp.i.i, label %for.cond.for.end_crit_edge.i.i, label %for.body.i.i + +for.cond.for.end_crit_edge.i.i: ; preds = %for.body.i.i + br label %_ZSt4fillIPiiEvT_S1_RKT0_.exit + +_ZSt4fillIPiiEvT_S1_RKT0_.exit: ; preds = %entry, %for.cond.for.end_crit_edge.i.i + ret void +} + +; Various checks for inbounds geps. +define void @test3(i32* %begin, i32* %end) nounwind ssp { +entry: + %cmp7.i.i = icmp eq i32* %begin, %end + br i1 %cmp7.i.i, label %_ZSt4fillIPiiEvT_S1_RKT0_.exit, label %for.body.i.i + +for.body.i.i: ; preds = %entry, %for.body.i.i + %indvar.i.i = phi i64 [ %tmp, %for.body.i.i ], [ 0, %entry ] +; CHECK: %indvar.i.i +; CHECK: {0,+,1}<nuw><nsw><%for.body.i.i> + %tmp = add nsw i64 %indvar.i.i, 1 +; CHECK: %tmp = +; CHECK: {1,+,1}<nuw><nsw><%for.body.i.i> + %ptrincdec.i.i = getelementptr inbounds i32* %begin, i64 %tmp +; CHECK: %ptrincdec.i.i = +; CHECK: {(4 + %begin),+,4}<nsw><%for.body.i.i> + %__first.addr.08.i.i = getelementptr inbounds i32* %begin, i64 %indvar.i.i +; CHECK: %__first.addr.08.i.i +; CHECK: {%begin,+,4}<nsw><%for.body.i.i> + store i32 0, i32* %__first.addr.08.i.i, align 4 + %cmp.i.i = icmp eq i32* %ptrincdec.i.i, %end + br i1 %cmp.i.i, label %_ZSt4fillIPiiEvT_S1_RKT0_.exit, label %for.body.i.i +; CHECK: Loop %for.body.i.i: backedge-taken count is ((-4 + (-1 * %begin) + %end) /u 4) +; CHECK: Loop %for.body.i.i: max backedge-taken count is ((-4 + (-1 * %begin) + %end) /u 4) +_ZSt4fillIPiiEvT_S1_RKT0_.exit: ; preds = %for.body.i.i, %entry + ret void +} + +; A single AddExpr exists for (%a + %b), which is not always <nsw>. +; CHECK: @addnsw +; CHECK-NOT: --> (%a + %b)<nsw> +define i32 @addnsw(i32 %a, i32 %b) nounwind ssp { +entry: + %tmp = add i32 %a, %b + %cmp = icmp sgt i32 %tmp, 0 + br i1 %cmp, label %greater, label %exit + +greater: + %tmp2 = add nsw i32 %a, %b + br label %exit + +exit: + %result = phi i32 [ %a, %entry ], [ %tmp2, %greater ] + ret i32 %result +} diff --git a/test/Analysis/ScalarEvolution/pointer-sign-bits.ll b/test/Analysis/ScalarEvolution/pointer-sign-bits.ll new file mode 100644 index 00000000000..b2cec2d9fc8 --- /dev/null +++ b/test/Analysis/ScalarEvolution/pointer-sign-bits.ll @@ -0,0 +1,220 @@ +; RUN: opt < %s -analyze -scalar-evolution + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" + %JavaObject = type { [0 x i32 (...)*]*, i8* } + +define void @JnJVM_antlr_CSharpCodeGenerator_genBitSet__Lantlr_collections_impl_BitSet_2I(%JavaObject*, %JavaObject*, i32) { +start: + br i1 undef, label %"stack overflow", label %"no stack overflow" + +"GOTO or IF*2": ; preds = %"true verifyAndComputePtr89", %verifyNullCont84 + unreachable + +"GOTO or IF*5": ; preds = %"true verifyAndComputePtr127", %"GOTO or IF*6" + unreachable + +"GOTO or IF*6": ; preds = %"true verifyAndComputePtr131.GOTO or IF*6_crit_edge", %"true verifyAndComputePtr89" + %indvar = phi i32 [ %indvar.next, %"true verifyAndComputePtr131.GOTO or IF*6_crit_edge" ], [ 0, %"true verifyAndComputePtr89" ] ; <i32> [#uses=2] + %.0.in = add i32 %indvar, 0 ; <i32> [#uses=1] + %.0 = add i32 %.0.in, 1 ; <i32> [#uses=1] + %3 = icmp slt i32 %.0, %4 ; <i1> [#uses=1] + br i1 %3, label %verifyNullCont126, label %"GOTO or IF*5" + +end: ; preds = %"no exception block35" + ret void + +"stack overflow": ; preds = %start + ret void + +"no stack overflow": ; preds = %start + br i1 undef, label %verifyNullCont, label %"no stack overflow.end_crit_edge" + +"no stack overflow.end_crit_edge": ; preds = %"no stack overflow" + ret void + +verifyNullCont: ; preds = %"no stack overflow" + br i1 undef, label %verifyNullCont9, label %verifyNullCont.end_crit_edge + +verifyNullCont.end_crit_edge: ; preds = %verifyNullCont + ret void + +verifyNullCont9: ; preds = %verifyNullCont + br i1 undef, label %verifyNullCont12, label %verifyNullCont9.end_crit_edge + +verifyNullCont9.end_crit_edge: ; preds = %verifyNullCont9 + ret void + +verifyNullCont12: ; preds = %verifyNullCont9 + br i1 undef, label %"no exception block13", label %verifyNullCont12.end_crit_edge + +verifyNullCont12.end_crit_edge: ; preds = %verifyNullCont12 + ret void + +"no exception block13": ; preds = %verifyNullCont12 + br i1 undef, label %verifyNullExit14, label %verifyNullCont15 + +verifyNullExit14: ; preds = %"no exception block13" + ret void + +verifyNullCont15: ; preds = %"no exception block13" + br i1 undef, label %"no exception block16", label %verifyNullCont15.end_crit_edge + +verifyNullCont15.end_crit_edge: ; preds = %verifyNullCont15 + ret void + +"no exception block16": ; preds = %verifyNullCont15 + br i1 undef, label %verifyNullExit17, label %verifyNullCont18 + +verifyNullExit17: ; preds = %"no exception block16" + ret void + +verifyNullCont18: ; preds = %"no exception block16" + br i1 undef, label %"no exception block19", label %verifyNullCont18.end_crit_edge + +verifyNullCont18.end_crit_edge: ; preds = %verifyNullCont18 + ret void + +"no exception block19": ; preds = %verifyNullCont18 + br i1 undef, label %verifyNullExit20, label %verifyNullCont21 + +verifyNullExit20: ; preds = %"no exception block19" + ret void + +verifyNullCont21: ; preds = %"no exception block19" + br i1 undef, label %verifyNullCont24, label %verifyNullCont21.end_crit_edge + +verifyNullCont21.end_crit_edge: ; preds = %verifyNullCont21 + ret void + +verifyNullCont24: ; preds = %verifyNullCont21 + br i1 undef, label %verifyNullCont27, label %verifyNullCont24.end_crit_edge + +verifyNullCont24.end_crit_edge: ; preds = %verifyNullCont24 + ret void + +verifyNullCont27: ; preds = %verifyNullCont24 + br i1 undef, label %verifyNullCont32, label %verifyNullCont27.end_crit_edge + +verifyNullCont27.end_crit_edge: ; preds = %verifyNullCont27 + ret void + +verifyNullCont32: ; preds = %verifyNullCont27 + br i1 undef, label %verifyNullExit33, label %verifyNullCont34 + +verifyNullExit33: ; preds = %verifyNullCont32 + ret void + +verifyNullCont34: ; preds = %verifyNullCont32 + br i1 undef, label %"no exception block35", label %verifyNullCont34.end_crit_edge + +verifyNullCont34.end_crit_edge: ; preds = %verifyNullCont34 + ret void + +"no exception block35": ; preds = %verifyNullCont34 + br i1 undef, label %end, label %verifyNullCont60 + +verifyNullCont60: ; preds = %"no exception block35" + br i1 undef, label %verifyNullCont63, label %verifyNullCont60.end_crit_edge + +verifyNullCont60.end_crit_edge: ; preds = %verifyNullCont60 + ret void + +verifyNullCont63: ; preds = %verifyNullCont60 + br i1 undef, label %"no exception block64", label %verifyNullCont63.end_crit_edge + +verifyNullCont63.end_crit_edge: ; preds = %verifyNullCont63 + ret void + +"no exception block64": ; preds = %verifyNullCont63 + br i1 undef, label %verifyNullExit65, label %verifyNullCont66 + +verifyNullExit65: ; preds = %"no exception block64" + ret void + +verifyNullCont66: ; preds = %"no exception block64" + br i1 undef, label %"no exception block67", label %verifyNullCont66.end_crit_edge + +verifyNullCont66.end_crit_edge: ; preds = %verifyNullCont66 + ret void + +"no exception block67": ; preds = %verifyNullCont66 + br i1 undef, label %verifyNullExit68, label %verifyNullCont69 + +verifyNullExit68: ; preds = %"no exception block67" + ret void + +verifyNullCont69: ; preds = %"no exception block67" + br i1 undef, label %"no exception block70", label %verifyNullCont69.end_crit_edge + +verifyNullCont69.end_crit_edge: ; preds = %verifyNullCont69 + ret void + +"no exception block70": ; preds = %verifyNullCont69 + br i1 undef, label %verifyNullExit71, label %verifyNullCont72 + +verifyNullExit71: ; preds = %"no exception block70" + ret void + +verifyNullCont72: ; preds = %"no exception block70" + br i1 undef, label %verifyNullCont75, label %verifyNullCont72.end_crit_edge + +verifyNullCont72.end_crit_edge: ; preds = %verifyNullCont72 + ret void + +verifyNullCont75: ; preds = %verifyNullCont72 + br i1 undef, label %verifyNullCont78, label %verifyNullCont75.end_crit_edge + +verifyNullCont75.end_crit_edge: ; preds = %verifyNullCont75 + ret void + +verifyNullCont78: ; preds = %verifyNullCont75 + br i1 undef, label %"verifyNullCont78.GOTO or IF*4_crit_edge", label %verifyNullCont78.end_crit_edge + +"verifyNullCont78.GOTO or IF*4_crit_edge": ; preds = %verifyNullCont78 + br i1 undef, label %verifyNullExit80, label %verifyNullCont81 + +verifyNullCont78.end_crit_edge: ; preds = %verifyNullCont78 + ret void + +verifyNullExit80: ; preds = %"verifyNullCont78.GOTO or IF*4_crit_edge" + ret void + +verifyNullCont81: ; preds = %"verifyNullCont78.GOTO or IF*4_crit_edge" + %4 = ptrtoint i8* undef to i32 ; <i32> [#uses=2] + %5 = icmp slt i32 0, %4 ; <i1> [#uses=1] + br i1 %5, label %verifyNullCont84, label %verifyNullCont172 + +verifyNullCont84: ; preds = %verifyNullCont81 + br i1 undef, label %"GOTO or IF*2", label %verifyNullCont86 + +verifyNullCont86: ; preds = %verifyNullCont84 + br i1 undef, label %"true verifyAndComputePtr", label %"false verifyAndComputePtr" + +"true verifyAndComputePtr": ; preds = %verifyNullCont86 + br i1 undef, label %"true verifyAndComputePtr89", label %"false verifyAndComputePtr90" + +"false verifyAndComputePtr": ; preds = %verifyNullCont86 + ret void + +"true verifyAndComputePtr89": ; preds = %"true verifyAndComputePtr" + br i1 undef, label %"GOTO or IF*6", label %"GOTO or IF*2" + +"false verifyAndComputePtr90": ; preds = %"true verifyAndComputePtr" + ret void + +verifyNullCont126: ; preds = %"GOTO or IF*6" + br i1 undef, label %"true verifyAndComputePtr127", label %"false verifyAndComputePtr128" + +"true verifyAndComputePtr127": ; preds = %verifyNullCont126 + br i1 undef, label %"true verifyAndComputePtr131.GOTO or IF*6_crit_edge", label %"GOTO or IF*5" + +"false verifyAndComputePtr128": ; preds = %verifyNullCont126 + ret void + +"true verifyAndComputePtr131.GOTO or IF*6_crit_edge": ; preds = %"true verifyAndComputePtr127" + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] + br label %"GOTO or IF*6" + +verifyNullCont172: ; preds = %verifyNullCont81 + unreachable +} diff --git a/test/Analysis/ScalarEvolution/pr3909.ll b/test/Analysis/ScalarEvolution/pr3909.ll new file mode 100644 index 00000000000..cf7531d4322 --- /dev/null +++ b/test/Analysis/ScalarEvolution/pr3909.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -indvars -disable-output +; PR 3909 + + + %0 = type { i32, %1* } ; type %0 + %1 = type { i32, i8* } ; type %1 + +define x86_stdcallcc i32 @_Dmain(%0 %unnamed) { +entry: + br label %whilebody + +whilebody: ; preds = %endwhile5, %entry + %i.0 = phi i64 [ 0, %entry ], [ %tmp11, %endwhile5 ] ; <i64> [#uses=1] + %m.0 = phi i64 [ 0, %entry ], [ %tmp11, %endwhile5 ] ; <i64> [#uses=2] + %tmp2 = mul i64 %m.0, %m.0 ; <i64> [#uses=1] + br label %whilecond3 + +whilecond3: ; preds = %whilebody4, %whilebody + %j.0 = phi i64 [ %tmp2, %whilebody ], [ %tmp9, %whilebody4 ] ; <i64> [#uses=2] + %tmp7 = icmp ne i64 %j.0, 0 ; <i1> [#uses=1] + br i1 %tmp7, label %whilebody4, label %endwhile5 + +whilebody4: ; preds = %whilecond3 + %tmp9 = add i64 %j.0, 1 ; <i64> [#uses=1] + br label %whilecond3 + +endwhile5: ; preds = %whilecond3 + %tmp11 = add i64 %i.0, 1 ; <i64> [#uses=2] + br label %whilebody +} diff --git a/test/Analysis/ScalarEvolution/scev-aa.ll b/test/Analysis/ScalarEvolution/scev-aa.ll new file mode 100644 index 00000000000..a0abbb787b0 --- /dev/null +++ b/test/Analysis/ScalarEvolution/scev-aa.ll @@ -0,0 +1,215 @@ +; RUN: opt < %s -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 +; A[i+(j+1)] != A[i+j], which can arise from multi-dimensional array references, +; and the example of the form A[0] != A[i+1], where i+1 is known to be positive. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + +; p[i] and p[i+1] don't alias. + +; CHECK: Function: loop: 3 pointers, 0 call sites +; CHECK: NoAlias: double* %pi, double* %pi.next + +define void @loop(double* nocapture %p, i64 %n) nounwind { +entry: + %j = icmp sgt i64 %n, 0 + br i1 %j, label %bb, label %return + +bb: + %i = phi i64 [ 0, %entry ], [ %i.next, %bb ] + %pi = getelementptr double* %p, i64 %i + %i.next = add i64 %i, 1 + %pi.next = getelementptr double* %p, i64 %i.next + %x = load double* %pi + %y = load double* %pi.next + %z = fmul double %x, %y + store double %z, double* %pi + %exitcond = icmp eq i64 %i.next, %n + br i1 %exitcond, label %return, label %bb + +return: + ret void +} + +; Slightly more involved: p[j][i], p[j][i+1], and p[j+1][i] don't alias. + +; CHECK: Function: nestedloop: 4 pointers, 0 call sites +; CHECK: NoAlias: double* %pi.j, double* %pi.next.j +; CHECK: NoAlias: double* %pi.j, double* %pi.j.next +; CHECK: NoAlias: double* %pi.j.next, double* %pi.next.j + +define void @nestedloop(double* nocapture %p, i64 %m) nounwind { +entry: + %k = icmp sgt i64 %m, 0 + br i1 %k, label %guard, label %return + +guard: + %l = icmp sgt i64 91, 0 + br i1 %l, label %outer.loop, label %return + +outer.loop: + %j = phi i64 [ 0, %guard ], [ %j.next, %outer.latch ] + br label %bb + +bb: + %i = phi i64 [ 0, %outer.loop ], [ %i.next, %bb ] + %i.next = add i64 %i, 1 + + %e = add i64 %i, %j + %pi.j = getelementptr double* %p, i64 %e + %f = add i64 %i.next, %j + %pi.next.j = getelementptr double* %p, i64 %f + %x = load double* %pi.j + %y = load double* %pi.next.j + %z = fmul double %x, %y + store double %z, double* %pi.j + + %o = add i64 %j, 91 + %g = add i64 %i, %o + %pi.j.next = getelementptr double* %p, i64 %g + %a = load double* %pi.j.next + %b = fmul double %x, %a + store double %b, double* %pi.j.next + + %exitcond = icmp eq i64 %i.next, 91 + br i1 %exitcond, label %outer.latch, label %bb + +outer.latch: + %j.next = add i64 %j, 91 + %h = icmp eq i64 %j.next, %m + br i1 %h, label %return, label %outer.loop + +return: + ret void +} + +; Even more involved: same as nestedloop, but with a variable extent. +; When n is 1, p[j+1][i] does alias p[j][i+1], and there's no way to +; prove whether n will be greater than 1, so that relation will always +; by MayAlias. The loop is guarded by a n > 0 test though, so +; p[j+1][i] and p[j][i] can theoretically be determined to be NoAlias, +; however the analysis currently doesn't do that. +; TODO: Make the analysis smarter and turn that MayAlias into a NoAlias. + +; CHECK: Function: nestedloop_more: 4 pointers, 0 call sites +; CHECK: NoAlias: double* %pi.j, double* %pi.next.j +; CHECK: MayAlias: double* %pi.j, double* %pi.j.next + +define void @nestedloop_more(double* nocapture %p, i64 %n, i64 %m) nounwind { +entry: + %k = icmp sgt i64 %m, 0 + br i1 %k, label %guard, label %return + +guard: + %l = icmp sgt i64 %n, 0 + br i1 %l, label %outer.loop, label %return + +outer.loop: + %j = phi i64 [ 0, %guard ], [ %j.next, %outer.latch ] + br label %bb + +bb: + %i = phi i64 [ 0, %outer.loop ], [ %i.next, %bb ] + %i.next = add i64 %i, 1 + + %e = add i64 %i, %j + %pi.j = getelementptr double* %p, i64 %e + %f = add i64 %i.next, %j + %pi.next.j = getelementptr double* %p, i64 %f + %x = load double* %pi.j + %y = load double* %pi.next.j + %z = fmul double %x, %y + store double %z, double* %pi.j + + %o = add i64 %j, %n + %g = add i64 %i, %o + %pi.j.next = getelementptr double* %p, i64 %g + %a = load double* %pi.j.next + %b = fmul double %x, %a + store double %b, double* %pi.j.next + + %exitcond = icmp eq i64 %i.next, %n + br i1 %exitcond, label %outer.latch, label %bb + +outer.latch: + %j.next = add i64 %j, %n + %h = icmp eq i64 %j.next, %m + br i1 %h, label %return, label %outer.loop + +return: + ret void +} + +; ScalarEvolution expands field offsets into constants, which allows it to +; do aggressive analysis. Contrast this with BasicAA, which works by +; recognizing GEP idioms. + +%struct.A = type { %struct.B, i32, i32 } +%struct.B = type { double } + +; CHECK: Function: foo: 7 pointers, 0 call sites +; CHECK: NoAlias: %struct.B* %B, i32* %Z +; CHECK: NoAlias: %struct.B* %B, %struct.B* %C +; CHECK: MustAlias: %struct.B* %C, i32* %Z +; CHECK: NoAlias: %struct.B* %B, i32* %X +; CHECK: MustAlias: i32* %X, i32* %Z +; CHECK: MustAlias: %struct.B* %C, i32* %Y +; CHECK: MustAlias: i32* %X, i32* %Y + +define void @foo() { +entry: + %A = alloca %struct.A + %B = getelementptr %struct.A* %A, i32 0, i32 0 + %Q = bitcast %struct.B* %B to %struct.A* + %Z = getelementptr %struct.A* %Q, i32 0, i32 1 + %C = getelementptr %struct.B* %B, i32 1 + %X = bitcast %struct.B* %C to i32* + %Y = getelementptr %struct.A* %A, i32 0, i32 1 + ret void +} + +; CHECK: Function: bar: 7 pointers, 0 call sites +; CHECK: NoAlias: %struct.B* %N, i32* %P +; CHECK: NoAlias: %struct.B* %N, %struct.B* %R +; CHECK: MustAlias: %struct.B* %R, i32* %P +; CHECK: NoAlias: %struct.B* %N, i32* %W +; CHECK: MustAlias: i32* %P, i32* %W +; CHECK: MustAlias: %struct.B* %R, i32* %V +; CHECK: MustAlias: i32* %V, i32* %W + +define void @bar() { + %M = alloca %struct.A + %N = getelementptr %struct.A* %M, i32 0, i32 0 + %O = bitcast %struct.B* %N to %struct.A* + %P = getelementptr %struct.A* %O, i32 0, i32 1 + %R = getelementptr %struct.B* %N, i32 1 + %W = bitcast %struct.B* %R to i32* + %V = getelementptr %struct.A* %M, i32 0, i32 1 + ret void +} + +; CHECK: Function: nonnegative: 2 pointers, 0 call sites +; CHECK: NoAlias: i64* %arrayidx, i64* %p + +define void @nonnegative(i64* %p) nounwind { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %i = phi i64 [ %inc, %for.body ], [ 0, %entry ] ; <i64> [#uses=2] + %inc = add nsw i64 %i, 1 ; <i64> [#uses=2] + %arrayidx = getelementptr inbounds i64* %p, i64 %inc + store i64 0, i64* %arrayidx + %tmp6 = load i64* %p ; <i64> [#uses=1] + %cmp = icmp slt i64 %inc, %tmp6 ; <i1> [#uses=1] + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + ret void +} + +; CHECK: 14 no alias responses +; CHECK: 26 may alias responses +; CHECK: 18 must alias responses diff --git a/test/Analysis/ScalarEvolution/sext-inreg.ll b/test/Analysis/ScalarEvolution/sext-inreg.ll new file mode 100644 index 00000000000..8b3d641943d --- /dev/null +++ b/test/Analysis/ScalarEvolution/sext-inreg.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -analyze -scalar-evolution > %t +; RUN: grep "sext i57 {0,+,199}<%bb> to i64" %t | count 1 +; RUN: grep "sext i59 {0,+,199}<%bb> to i64" %t | count 1 + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin9.6" + +define i64 @foo(i64* nocapture %x, i64 %n) nounwind { +entry: + %t0 = icmp sgt i64 %n, 0 ; <i1> [#uses=1] + br i1 %t0, label %bb, label %return + +bb: ; preds = %bb, %entry + %i.01 = phi i64 [ 0, %entry ], [ %indvar.next, %bb ] ; <i32> [#uses=2] + %t1 = shl i64 %i.01, 7 ; <i32> [#uses=1] + %t2 = ashr i64 %t1, 7 ; <i32> [#uses=1] + %s1 = shl i64 %i.01, 5 ; <i32> [#uses=1] + %s2 = ashr i64 %s1, 5 ; <i32> [#uses=1] + %t3 = getelementptr i64* %x, i64 %i.01 ; <i64*> [#uses=1] + store i64 0, i64* %t3, align 1 + %indvar.next = add i64 %i.01, 199 ; <i32> [#uses=2] + %exitcond = icmp eq i64 %indvar.next, %n ; <i1> [#uses=1] + br i1 %exitcond, label %return, label %bb + +return: ; preds = %bb, %entry + %p = phi i64 [ 0, %entry ], [ %t2, %bb ] + %q = phi i64 [ 0, %entry ], [ %s2, %bb ] + %v = xor i64 %p, %q + ret i64 %v +} diff --git a/test/Analysis/ScalarEvolution/sext-iv-0.ll b/test/Analysis/ScalarEvolution/sext-iv-0.ll new file mode 100644 index 00000000000..d5d32689e17 --- /dev/null +++ b/test/Analysis/ScalarEvolution/sext-iv-0.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s + +; Convert (sext {-128,+,1}) to {sext(-128),+,sext(1)}, since the +; trip count is within range where this is safe. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo(double* nocapture %x) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i64 [ -128, %bb1.thread ], [ %8, %bb1 ] ; <i64> [#uses=3] +; CHECK: %i.0.reg2mem.0 +; CHECK-NEXT: --> {-128,+,1}<%bb1> Exits: 127 + %0 = trunc i64 %i.0.reg2mem.0 to i8 ; <i8> [#uses=1] +; CHECK: %0 +; CHECK-NEXT: --> {-128,+,1}<%bb1> Exits: 127 + %1 = trunc i64 %i.0.reg2mem.0 to i9 ; <i8> [#uses=1] +; CHECK: %1 +; CHECK-NEXT: --> {-128,+,1}<%bb1> Exits: 127 + %2 = sext i9 %1 to i64 ; <i64> [#uses=1] +; CHECK: %2 +; CHECK-NEXT: --> {-128,+,1}<nsw><%bb1> Exits: 127 + %3 = getelementptr double* %x, i64 %2 ; <double*> [#uses=1] + %4 = load double* %3, align 8 ; <double> [#uses=1] + %5 = fmul double %4, 3.900000e+00 ; <double> [#uses=1] + %6 = sext i8 %0 to i64 ; <i64> [#uses=1] + %7 = getelementptr double* %x, i64 %6 ; <double*> [#uses=1] + store double %5, double* %7, align 8 + %8 = add i64 %i.0.reg2mem.0, 1 ; <i64> [#uses=2] + %9 = icmp sgt i64 %8, 127 ; <i1> [#uses=1] + br i1 %9, label %return, label %bb1 + +return: ; preds = %bb1 + ret void +} diff --git a/test/Analysis/ScalarEvolution/sext-iv-1.ll b/test/Analysis/ScalarEvolution/sext-iv-1.ll new file mode 100644 index 00000000000..c34596d35af --- /dev/null +++ b/test/Analysis/ScalarEvolution/sext-iv-1.ll @@ -0,0 +1,100 @@ +; RUN: opt < %s -scalar-evolution -analyze \ +; RUN: | grep " --> (sext i. {.*,+,.*}<%bb1> to i64)" | count 5 + +; Don't convert (sext {...,+,...}) to {sext(...),+,sext(...)} in cases +; where the trip count is not within range. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo0(double* nocapture %x) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i64 [ -128, %bb1.thread ], [ %8, %bb1 ] ; <i64> [#uses=3] + %0 = trunc i64 %i.0.reg2mem.0 to i7 ; <i8> [#uses=1] + %1 = trunc i64 %i.0.reg2mem.0 to i9 ; <i8> [#uses=1] + %2 = sext i9 %1 to i64 ; <i64> [#uses=1] + %3 = getelementptr double* %x, i64 %2 ; <double*> [#uses=1] + %4 = load double* %3, align 8 ; <double> [#uses=1] + %5 = fmul double %4, 3.900000e+00 ; <double> [#uses=1] + %6 = sext i7 %0 to i64 ; <i64> [#uses=1] + %7 = getelementptr double* %x, i64 %6 ; <double*> [#uses=1] + store double %5, double* %7, align 8 + %8 = add i64 %i.0.reg2mem.0, 1 ; <i64> [#uses=2] + %9 = icmp sgt i64 %8, 127 ; <i1> [#uses=1] + br i1 %9, label %return, label %bb1 + +return: ; preds = %bb1 + ret void +} + +define void @foo1(double* nocapture %x) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i64 [ -128, %bb1.thread ], [ %8, %bb1 ] ; <i64> [#uses=3] + %0 = trunc i64 %i.0.reg2mem.0 to i8 ; <i8> [#uses=1] + %1 = trunc i64 %i.0.reg2mem.0 to i9 ; <i8> [#uses=1] + %2 = sext i9 %1 to i64 ; <i64> [#uses=1] + %3 = getelementptr double* %x, i64 %2 ; <double*> [#uses=1] + %4 = load double* %3, align 8 ; <double> [#uses=1] + %5 = fmul double %4, 3.900000e+00 ; <double> [#uses=1] + %6 = sext i8 %0 to i64 ; <i64> [#uses=1] + %7 = getelementptr double* %x, i64 %6 ; <double*> [#uses=1] + store double %5, double* %7, align 8 + %8 = add i64 %i.0.reg2mem.0, 1 ; <i64> [#uses=2] + %9 = icmp sgt i64 %8, 128 ; <i1> [#uses=1] + br i1 %9, label %return, label %bb1 + +return: ; preds = %bb1 + ret void +} + +define void @foo2(double* nocapture %x) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i64 [ -129, %bb1.thread ], [ %8, %bb1 ] ; <i64> [#uses=3] + %0 = trunc i64 %i.0.reg2mem.0 to i8 ; <i8> [#uses=1] + %1 = trunc i64 %i.0.reg2mem.0 to i9 ; <i8> [#uses=1] + %2 = sext i9 %1 to i64 ; <i64> [#uses=1] + %3 = getelementptr double* %x, i64 %2 ; <double*> [#uses=1] + %4 = load double* %3, align 8 ; <double> [#uses=1] + %5 = fmul double %4, 3.900000e+00 ; <double> [#uses=1] + %6 = sext i8 %0 to i64 ; <i64> [#uses=1] + %7 = getelementptr double* %x, i64 %6 ; <double*> [#uses=1] + store double %5, double* %7, align 8 + %8 = add i64 %i.0.reg2mem.0, 1 ; <i64> [#uses=2] + %9 = icmp sgt i64 %8, 127 ; <i1> [#uses=1] + br i1 %9, label %return, label %bb1 + +return: ; preds = %bb1 + ret void +} + +define void @foo3(double* nocapture %x) nounwind { +bb1.thread: + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i64 [ -128, %bb1.thread ], [ %8, %bb1 ] ; <i64> [#uses=3] + %0 = trunc i64 %i.0.reg2mem.0 to i8 ; <i8> [#uses=1] + %1 = trunc i64 %i.0.reg2mem.0 to i9 ; <i8> [#uses=1] + %2 = sext i9 %1 to i64 ; <i64> [#uses=1] + %3 = getelementptr double* %x, i64 %2 ; <double*> [#uses=1] + %4 = load double* %3, align 8 ; <double> [#uses=1] + %5 = fmul double %4, 3.900000e+00 ; <double> [#uses=1] + %6 = sext i8 %0 to i64 ; <i64> [#uses=1] + %7 = getelementptr double* %x, i64 %6 ; <double*> [#uses=1] + store double %5, double* %7, align 8 + %8 = add i64 %i.0.reg2mem.0, -1 ; <i64> [#uses=2] + %9 = icmp sgt i64 %8, 127 ; <i1> [#uses=1] + br i1 %9, label %return, label %bb1 + +return: ; preds = %bb1 + ret void +} diff --git a/test/Analysis/ScalarEvolution/sext-iv-2.ll b/test/Analysis/ScalarEvolution/sext-iv-2.ll new file mode 100644 index 00000000000..97e252c1fb3 --- /dev/null +++ b/test/Analysis/ScalarEvolution/sext-iv-2.ll @@ -0,0 +1,74 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; CHECK: %tmp3 = sext i8 %tmp2 to i32 +; CHECK: --> (sext i8 {0,+,1}<%bb1> to i32) Exits: -1 +; CHECK: %tmp4 = mul i32 %tmp3, %i.02 +; CHECK: --> ((sext i8 {0,+,1}<%bb1> to i32) * {0,+,1}<%bb>) Exits: {0,+,-1}<%bb> + +; These sexts are not foldable. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + +@table = common global [32 x [256 x i32]] zeroinitializer, align 32 ; <[32 x [256 x i32]]*> [#uses=2] + +define i32 @main() nounwind { +entry: + br i1 false, label %bb5, label %bb.nph3 + +bb.nph3: ; preds = %entry + br label %bb + +bb: ; preds = %bb4, %bb.nph3 + %i.02 = phi i32 [ %tmp10, %bb4 ], [ 0, %bb.nph3 ] ; <i32> [#uses=3] + br i1 false, label %bb3, label %bb.nph + +bb.nph: ; preds = %bb + br label %bb1 + +bb1: ; preds = %bb2, %bb.nph + %j.01 = phi i32 [ %tmp8, %bb2 ], [ 0, %bb.nph ] ; <i32> [#uses=3] + %tmp2 = trunc i32 %j.01 to i8 ; <i8> [#uses=1] + %tmp3 = sext i8 %tmp2 to i32 ; <i32> [#uses=1] + %tmp4 = mul i32 %tmp3, %i.02 ; <i32> [#uses=1] + %tmp5 = sext i32 %i.02 to i64 ; <i64> [#uses=1] + %tmp6 = sext i32 %j.01 to i64 ; <i64> [#uses=1] + %tmp7 = getelementptr [32 x [256 x i32]]* @table, i64 0, i64 %tmp5, i64 %tmp6 ; <i32*> [#uses=1] + store i32 %tmp4, i32* %tmp7, align 4 + %tmp8 = add i32 %j.01, 1 ; <i32> [#uses=2] + br label %bb2 + +bb2: ; preds = %bb1 + %phitmp1 = icmp sgt i32 %tmp8, 255 ; <i1> [#uses=1] + br i1 %phitmp1, label %bb2.bb3_crit_edge, label %bb1 + +bb2.bb3_crit_edge: ; preds = %bb2 + br label %bb3 + +bb3: ; preds = %bb2.bb3_crit_edge, %bb + %tmp10 = add i32 %i.02, 1 ; <i32> [#uses=2] + br label %bb4 + +bb4: ; preds = %bb3 + %phitmp = icmp sgt i32 %tmp10, 31 ; <i1> [#uses=1] + br i1 %phitmp, label %bb4.bb5_crit_edge, label %bb + +bb4.bb5_crit_edge: ; preds = %bb4 + br label %bb5 + +bb5: ; preds = %bb4.bb5_crit_edge, %entry + %tmp12 = load i32* getelementptr ([32 x [256 x i32]]* @table, i64 0, i64 9, i64 132), align 16 ; <i32> [#uses=1] + %tmp13 = icmp eq i32 %tmp12, -1116 ; <i1> [#uses=1] + br i1 %tmp13, label %bb7, label %bb6 + +bb6: ; preds = %bb5 + call void @abort() noreturn nounwind + unreachable + +bb7: ; preds = %bb5 + br label %return + +return: ; preds = %bb7 + ret i32 0 +} + +declare void @abort() noreturn nounwind diff --git a/test/Analysis/ScalarEvolution/sle.ll b/test/Analysis/ScalarEvolution/sle.ll new file mode 100644 index 00000000000..f38f6b63dce --- /dev/null +++ b/test/Analysis/ScalarEvolution/sle.ll @@ -0,0 +1,27 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +; ScalarEvolution should be able to use nsw information to prove that +; this loop has a finite trip count. + +; CHECK: @le +; CHECK: Loop %for.body: backedge-taken count is %n +; CHECK: Loop %for.body: max backedge-taken count is 9223372036854775807 + +define void @le(i64 %n, double* nocapture %p) nounwind { +entry: + %cmp6 = icmp slt i64 %n, 0 ; <i1> [#uses=1] + br i1 %cmp6, label %for.end, label %for.body + +for.body: ; preds = %for.body, %entry + %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] ; <i64> [#uses=2] + %arrayidx = getelementptr double* %p, i64 %i ; <double*> [#uses=2] + %t4 = load double* %arrayidx ; <double> [#uses=1] + %mul = fmul double %t4, 2.200000e+00 ; <double> [#uses=1] + store double %mul, double* %arrayidx + %i.next = add nsw i64 %i, 1 ; <i64> [#uses=2] + %cmp = icmp sgt i64 %i.next, %n ; <i1> [#uses=1] + br i1 %cmp, label %for.end, label %for.body + +for.end: ; preds = %for.body, %entry + ret void +} diff --git a/test/Analysis/ScalarEvolution/smax.ll b/test/Analysis/ScalarEvolution/smax.ll new file mode 100644 index 00000000000..eceb4298fd5 --- /dev/null +++ b/test/Analysis/ScalarEvolution/smax.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -analyze -scalar-evolution | grep smax | count 2 +; RUN: opt < %s -analyze -scalar-evolution | grep \ +; RUN: "%. smax %. smax %." +; PR1614 + +define i32 @x(i32 %a, i32 %b, i32 %c) { + %A = icmp sgt i32 %a, %b + %B = select i1 %A, i32 %a, i32 %b + %C = icmp sle i32 %c, %B + %D = select i1 %C, i32 %B, i32 %c + ret i32 %D +} diff --git a/test/Analysis/ScalarEvolution/trip-count.ll b/test/Analysis/ScalarEvolution/trip-count.ll new file mode 100644 index 00000000000..94f6882c0c9 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: -scalar-evolution-max-iterations=0 | grep "backedge-taken count is 10000" +; PR1101 + +@A = weak global [1000 x i32] zeroinitializer, align 32 + + +define void @test(i32 %N) { +entry: + br label %bb3 + +bb: ; preds = %bb3 + %tmp = getelementptr [1000 x i32]* @A, i32 0, i32 %i.0 ; <i32*> [#uses=1] + store i32 123, i32* %tmp + %tmp2 = add i32 %i.0, 1 ; <i32> [#uses=1] + br label %bb3 + +bb3: ; preds = %bb, %entry + %i.0 = phi i32 [ 0, %entry ], [ %tmp2, %bb ] ; <i32> [#uses=3] + %tmp3 = icmp sle i32 %i.0, 9999 ; <i1> [#uses=1] + br i1 %tmp3, label %bb, label %bb5 + +bb5: ; preds = %bb3 + br label %return + +return: ; preds = %bb5 + ret void +} diff --git a/test/Analysis/ScalarEvolution/trip-count10.ll b/test/Analysis/ScalarEvolution/trip-count10.ll new file mode 100644 index 00000000000..546e1dc7d8f --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count10.ll @@ -0,0 +1,126 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; Trip counts with trivial exit conditions. + +; CHECK: Determining loop execution counts for: @a +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +; CHECK: Determining loop execution counts for: @b +; CHECK: Loop %loop: backedge-taken count is false +; CHECK: Loop %loop: max backedge-taken count is false + +; CHECK: Determining loop execution counts for: @c +; CHECK: Loop %loop: backedge-taken count is false +; CHECK: Loop %loop: max backedge-taken count is false + +; CHECK: Determining loop execution counts for: @d +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. + +define void @a(i64 %n) nounwind { +entry: + %t0 = icmp sgt i64 %n, 0 + br i1 %t0, label %loop, label %return + +loop: + %i = phi i64 [ %i.next, %loop ], [ 0, %entry ] + %i.next = add nsw i64 %i, 1 + %exitcond = icmp eq i64 %i.next, %n + br i1 false, label %return, label %loop + +return: + ret void +} +define void @b(i64 %n) nounwind { +entry: + %t0 = icmp sgt i64 %n, 0 + br i1 %t0, label %loop, label %return + +loop: + %i = phi i64 [ %i.next, %loop ], [ 0, %entry ] + %i.next = add nsw i64 %i, 1 + %exitcond = icmp eq i64 %i.next, %n + br i1 true, label %return, label %loop + +return: + ret void +} +define void @c(i64 %n) nounwind { +entry: + %t0 = icmp sgt i64 %n, 0 + br i1 %t0, label %loop, label %return + +loop: + %i = phi i64 [ %i.next, %loop ], [ 0, %entry ] + %i.next = add nsw i64 %i, 1 + %exitcond = icmp eq i64 %i.next, %n + br i1 false, label %loop, label %return + +return: + ret void +} +define void @d(i64 %n) nounwind { +entry: + %t0 = icmp sgt i64 %n, 0 + br i1 %t0, label %loop, label %return + +loop: + %i = phi i64 [ %i.next, %loop ], [ 0, %entry ] + %i.next = add nsw i64 %i, 1 + %exitcond = icmp eq i64 %i.next, %n + br i1 true, label %loop, label %return + +return: + ret void +} + +; Trip counts for non-polynomial iterations. It's theoretically possible +; to compute a maximum count for these, but short of that, ScalarEvolution +; should return unknown. + +; PR7416 +; CHECK: Determining loop execution counts for: @nonpolynomial +; CHECK-NEXT: Loop %loophead: Unpredictable backedge-taken count +; CHECK-NEXT: Loop %loophead: Unpredictable max backedge-taken count + +declare i1 @g() nounwind + +define void @nonpolynomial() { +entry: + br label %loophead +loophead: + %x = phi i32 [0, %entry], [%x.1, %bb1], [%x.2, %bb2] + %y = icmp slt i32 %x, 100 + br i1 %y, label %loopbody, label %retbb +loopbody: + %z = call i1 @g() + br i1 %z, label %bb1, label %bb2 +bb1: + %x.1 = add i32 %x, 2 + br label %loophead +bb2: + %x.2 = add i32 %x, 3 + br label %loophead +retbb: + ret void +} + +; PHI nodes with all constant operands. + +; CHECK: Determining loop execution counts for: @constant_phi_operands +; CHECK: Loop %loop: backedge-taken count is 1 +; CHECK: Loop %loop: max backedge-taken count is 1 + +define void @constant_phi_operands() nounwind { +entry: + br label %loop + +loop: + %i = phi i64 [ 1, %loop ], [ 0, %entry ] + %exitcond = icmp eq i64 %i, 1 + br i1 %exitcond, label %return, label %loop + +return: + ret void +} diff --git a/test/Analysis/ScalarEvolution/trip-count11.ll b/test/Analysis/ScalarEvolution/trip-count11.ll new file mode 100644 index 00000000000..71915037ec8 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count11.ll @@ -0,0 +1,29 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo.a = internal constant [8 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7], align 16 + +define i32 @foo() nounwind uwtable noinline { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %sum.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ] +; CHECK: --> %sum.0 Exits: 28 + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %cmp = icmp ult i32 %i.0, 8 + br i1 %cmp, label %for.inc, label %for.end + +for.inc: ; preds = %for.cond + %idxprom = sext i32 %i.0 to i64 + %arrayidx = getelementptr inbounds [8 x i32]* @foo.a, i64 0, i64 %idxprom + %0 = load i32* %arrayidx, align 4 + %add = add nsw i32 %sum.0, %0 + %inc = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret i32 %sum.0 +} diff --git a/test/Analysis/ScalarEvolution/trip-count12.ll b/test/Analysis/ScalarEvolution/trip-count12.ll new file mode 100644 index 00000000000..8f960e1c1c7 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count12.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; CHECK: Determining loop execution counts for: @test +; CHECK: Loop %for.body: backedge-taken count is ((-2 + %len) /u 2) +; CHECK: Loop %for.body: max backedge-taken count is 1073741823 + +define zeroext i16 @test(i16* nocapture %p, i32 %len) nounwind readonly { +entry: + %cmp2 = icmp sgt i32 %len, 1 + br i1 %cmp2, label %for.body.preheader, label %for.end + +for.body.preheader: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body, %for.body.preheader + %p.addr.05 = phi i16* [ %incdec.ptr, %for.body ], [ %p, %for.body.preheader ] + %len.addr.04 = phi i32 [ %sub, %for.body ], [ %len, %for.body.preheader ] + %res.03 = phi i32 [ %add, %for.body ], [ 0, %for.body.preheader ] + %incdec.ptr = getelementptr inbounds i16* %p.addr.05, i32 1 + %0 = load i16* %p.addr.05, align 2 + %conv = zext i16 %0 to i32 + %add = add i32 %conv, %res.03 + %sub = add nsw i32 %len.addr.04, -2 + %cmp = icmp sgt i32 %sub, 1 + br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.body + %extract.t = trunc i32 %add to i16 + br label %for.end + +for.end: ; preds = %for.cond.for.end_crit_edge, %entry + %res.0.lcssa.off0 = phi i16 [ %extract.t, %for.cond.for.end_crit_edge ], [ 0, %entry ] + ret i16 %res.0.lcssa.off0 +} + diff --git a/test/Analysis/ScalarEvolution/trip-count2.ll b/test/Analysis/ScalarEvolution/trip-count2.ll new file mode 100644 index 00000000000..d84e99f6e7c --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count2.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -analyze -scalar-evolution | \ +; RUN: grep "backedge-taken count is 4" +; PR1101 + +@A = weak global [1000 x i32] zeroinitializer, align 32 + + +define void @test(i32 %N) { +entry: + br label %bb3 + +bb: ; preds = %bb3 + %tmp = getelementptr [1000 x i32]* @A, i32 0, i32 %i.0 ; <i32*> [#uses=1] + store i32 123, i32* %tmp + %tmp4 = mul i32 %i.0, 4 ; <i32> [#uses=1] + %tmp5 = or i32 %tmp4, 1 + %tmp61 = xor i32 %tmp5, -2147483648 + %tmp6 = trunc i32 %tmp61 to i16 + %tmp71 = shl i16 %tmp6, 2 + %tmp7 = zext i16 %tmp71 to i32 + %tmp2 = add i32 %tmp7, %i.0 + br label %bb3 + +bb3: ; preds = %bb, %entry + %i.0 = phi i32 [ 0, %entry ], [ %tmp2, %bb ] ; <i32> [#uses=3] + %tmp3 = icmp sle i32 %i.0, 9999 ; <i1> [#uses=1] + br i1 %tmp3, label %bb, label %bb5 + +bb5: ; preds = %bb3 + br label %return + +return: ; preds = %bb5 + ret void +} diff --git a/test/Analysis/ScalarEvolution/trip-count3.ll b/test/Analysis/ScalarEvolution/trip-count3.ll new file mode 100644 index 00000000000..0cb6c952b89 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count3.ll @@ -0,0 +1,78 @@ +; RUN: opt < %s -scalar-evolution -analyze \ +; RUN: | grep "Loop %bb3\.i: Unpredictable backedge-taken count\." + +; ScalarEvolution can't compute a trip count because it doesn't know if +; dividing by the stride will have a remainder. This could theoretically +; be teaching it how to use a more elaborate trip count computation. + +%struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] } +%struct.SHA_INFO = type { [5 x i32], i32, i32, [16 x i32] } +%struct._IO_marker = type { %struct._IO_marker*, %struct.FILE*, i32 } + +@_2E_str = external constant [26 x i8] +@stdin = external global %struct.FILE* +@_2E_str1 = external constant [3 x i8] +@_2E_str12 = external constant [30 x i8] + +declare void @sha_init(%struct.SHA_INFO* nocapture) nounwind + +declare fastcc void @sha_transform(%struct.SHA_INFO* nocapture) nounwind + +declare void @sha_print(%struct.SHA_INFO* nocapture) nounwind + +declare i32 @printf(i8* nocapture, ...) nounwind + +declare void @sha_final(%struct.SHA_INFO* nocapture) nounwind + +declare void @sha_update(%struct.SHA_INFO* nocapture, i8* nocapture, i32) nounwind + +declare i64 @fread(i8* noalias nocapture, i64, i64, %struct.FILE* noalias nocapture) nounwind + +declare i32 @main(i32, i8** nocapture) nounwind + +declare noalias %struct.FILE* @fopen(i8* noalias nocapture, i8* noalias nocapture) nounwind + +declare i32 @fclose(%struct.FILE* nocapture) nounwind + +declare void @sha_stream(%struct.SHA_INFO* nocapture, %struct.FILE* nocapture) nounwind + +define void @sha_stream_bb3_2E_i(%struct.SHA_INFO* %sha_info, i8* %data1, i32, i8** %buffer_addr.0.i.out, i32* %count_addr.0.i.out) nounwind { +newFuncRoot: + br label %bb3.i + +sha_update.exit.exitStub: ; preds = %bb3.i + store i8* %buffer_addr.0.i, i8** %buffer_addr.0.i.out + store i32 %count_addr.0.i, i32* %count_addr.0.i.out + ret void + +bb2.i: ; preds = %bb3.i + %1 = getelementptr %struct.SHA_INFO* %sha_info, i64 0, i32 3 + %2 = bitcast [16 x i32]* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %buffer_addr.0.i, i64 64, i32 1, i1 false) + %3 = getelementptr %struct.SHA_INFO* %sha_info, i64 0, i32 3, i64 0 + %4 = bitcast i32* %3 to i8* + br label %codeRepl + +codeRepl: ; preds = %bb2.i + call void @sha_stream_bb3_2E_i_bb1_2E_i_2E_i(i8* %4) + br label %byte_reverse.exit.i + +byte_reverse.exit.i: ; preds = %codeRepl + call fastcc void @sha_transform(%struct.SHA_INFO* %sha_info) nounwind + %5 = getelementptr i8* %buffer_addr.0.i, i64 64 + %6 = add i32 %count_addr.0.i, -64 + br label %bb3.i + +bb3.i: ; preds = %byte_reverse.exit.i, %newFuncRoot + %buffer_addr.0.i = phi i8* [ %data1, %newFuncRoot ], [ %5, %byte_reverse.exit.i ] + %count_addr.0.i = phi i32 [ %0, %newFuncRoot ], [ %6, %byte_reverse.exit.i ] + %7 = icmp sgt i32 %count_addr.0.i, 63 + br i1 %7, label %bb2.i, label %sha_update.exit.exitStub +} + +declare void @sha_stream_bb3_2E_i_bb1_2E_i_2E_i(i8*) nounwind + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + diff --git a/test/Analysis/ScalarEvolution/trip-count4.ll b/test/Analysis/ScalarEvolution/trip-count4.ll new file mode 100644 index 00000000000..c02ae145268 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count4.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | grep "sext.*trunc.*Exits: 11" + +; ScalarEvolution should be able to compute a loop exit value for %indvar.i8. + +define void @another_count_down_signed(double* %d, i64 %n) nounwind { +entry: + br label %loop + +loop: ; preds = %loop, %entry + %indvar = phi i64 [ %n, %entry ], [ %indvar.next, %loop ] ; <i64> [#uses=4] + %s0 = shl i64 %indvar, 8 ; <i64> [#uses=1] + %indvar.i8 = ashr i64 %s0, 8 ; <i64> [#uses=1] + %t0 = getelementptr double* %d, i64 %indvar.i8 ; <double*> [#uses=2] + %t1 = load double* %t0 ; <double> [#uses=1] + %t2 = fmul double %t1, 1.000000e-01 ; <double> [#uses=1] + store double %t2, double* %t0 + %indvar.next = sub i64 %indvar, 1 ; <i64> [#uses=2] + %exitcond = icmp eq i64 %indvar.next, 10 ; <i1> [#uses=1] + br i1 %exitcond, label %return, label %loop + +return: ; preds = %loop + ret void +} diff --git a/test/Analysis/ScalarEvolution/trip-count5.ll b/test/Analysis/ScalarEvolution/trip-count5.ll new file mode 100644 index 00000000000..68a1ae14a7a --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count5.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -analyze -scalar-evolution > %t +; RUN: grep sext %t | count 2 +; RUN: not grep "(sext" %t + +; ScalarEvolution should be able to compute a maximum trip count +; value sufficient to fold away both sext casts. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + +define float @t(float* %pTmp1, float* %peakWeight, float* %nrgReducePeakrate, i32 %bim) nounwind { +entry: + %tmp3 = load float* %peakWeight, align 4 ; <float> [#uses=2] + %tmp2538 = icmp sgt i32 %bim, 0 ; <i1> [#uses=1] + br i1 %tmp2538, label %bb.nph, label %bb4 + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %distERBhi.036 = phi float [ %tmp10, %bb1 ], [ 0.000000e+00, %bb.nph ] ; <float> [#uses=1] + %hiPart.035 = phi i32 [ %tmp12, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=2] + %peakCount.034 = phi float [ %tmp19, %bb1 ], [ %tmp3, %bb.nph ] ; <float> [#uses=1] + %tmp6 = sext i32 %hiPart.035 to i64 ; <i64> [#uses=1] + %tmp7 = getelementptr float* %pTmp1, i64 %tmp6 ; <float*> [#uses=1] + %tmp8 = load float* %tmp7, align 4 ; <float> [#uses=1] + %tmp10 = fadd float %tmp8, %distERBhi.036 ; <float> [#uses=3] + %tmp12 = add i32 %hiPart.035, 1 ; <i32> [#uses=3] + %tmp15 = sext i32 %tmp12 to i64 ; <i64> [#uses=1] + %tmp16 = getelementptr float* %peakWeight, i64 %tmp15 ; <float*> [#uses=1] + %tmp17 = load float* %tmp16, align 4 ; <float> [#uses=1] + %tmp19 = fadd float %tmp17, %peakCount.034 ; <float> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %tmp21 = fcmp olt float %tmp10, 2.500000e+00 ; <i1> [#uses=1] + %tmp25 = icmp slt i32 %tmp12, %bim ; <i1> [#uses=1] + %tmp27 = and i1 %tmp21, %tmp25 ; <i1> [#uses=1] + br i1 %tmp27, label %bb, label %bb1.bb4_crit_edge + +bb1.bb4_crit_edge: ; preds = %bb1 + br label %bb4 + +bb4: ; preds = %bb1.bb4_crit_edge, %entry + %distERBhi.0.lcssa = phi float [ %tmp10, %bb1.bb4_crit_edge ], [ 0.000000e+00, %entry ] ; <float> [#uses=1] + %peakCount.0.lcssa = phi float [ %tmp19, %bb1.bb4_crit_edge ], [ %tmp3, %entry ] ; <float> [#uses=1] + %tmp31 = fdiv float %peakCount.0.lcssa, %distERBhi.0.lcssa ; <float> [#uses=1] + ret float %tmp31 +} diff --git a/test/Analysis/ScalarEvolution/trip-count6.ll b/test/Analysis/ScalarEvolution/trip-count6.ll new file mode 100644 index 00000000000..882f5526da4 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count6.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | grep "max backedge-taken count is 1$" + +@mode_table = global [4 x i32] zeroinitializer ; <[4 x i32]*> [#uses=1] + +define i8 @f() { +entry: + tail call i32 @fegetround( ) ; <i32>:0 [#uses=1] + br label %bb + +bb: ; preds = %bb4, %entry + %mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb4 ] ; <i8> [#uses=4] + zext i8 %mode.0 to i32 ; <i32>:1 [#uses=1] + getelementptr [4 x i32]* @mode_table, i32 0, i32 %1 ; <i32*>:2 [#uses=1] + load i32* %2, align 4 ; <i32>:3 [#uses=1] + icmp eq i32 %3, %0 ; <i1>:4 [#uses=1] + br i1 %4, label %bb1, label %bb2 + +bb1: ; preds = %bb + ret i8 %mode.0 + +bb2: ; preds = %bb + icmp eq i8 %mode.0, 1 ; <i1>:5 [#uses=1] + br i1 %5, label %bb5, label %bb4 + +bb4: ; preds = %bb2 + %indvar.next = add i8 %mode.0, 1 ; <i8> [#uses=1] + br label %bb + +bb5: ; preds = %bb2 + tail call void @raise_exception( ) noreturn + unreachable +} + +declare i32 @fegetround() + +declare void @raise_exception() noreturn diff --git a/test/Analysis/ScalarEvolution/trip-count7.ll b/test/Analysis/ScalarEvolution/trip-count7.ll new file mode 100644 index 00000000000..2bcb9e92abc --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count7.ll @@ -0,0 +1,150 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | grep "Loop %bb7.i: Unpredictable backedge-taken count\." + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + + %struct.complex = type { float, float } + %struct.element = type { i32, i32 } + %struct.node = type { %struct.node*, %struct.node*, i32 } +@seed = external global i64 ; <i64*> [#uses=0] +@_2E_str = external constant [18 x i8], align 1 ; <[18 x i8]*> [#uses=0] +@_2E_str1 = external constant [4 x i8], align 1 ; <[4 x i8]*> [#uses=0] +@value = external global float ; <float*> [#uses=0] +@fixed = external global float ; <float*> [#uses=0] +@floated = external global float ; <float*> [#uses=0] +@permarray = external global [11 x i32], align 32 ; <[11 x i32]*> [#uses=0] +@pctr = external global i32 ; <i32*> [#uses=0] +@tree = external global %struct.node* ; <%struct.node**> [#uses=0] +@stack = external global [4 x i32], align 16 ; <[4 x i32]*> [#uses=0] +@cellspace = external global [19 x %struct.element], align 32 ; <[19 x %struct.element]*> [#uses=0] +@freelist = external global i32 ; <i32*> [#uses=0] +@movesdone = external global i32 ; <i32*> [#uses=0] +@ima = external global [41 x [41 x i32]], align 32 ; <[41 x [41 x i32]]*> [#uses=0] +@imb = external global [41 x [41 x i32]], align 32 ; <[41 x [41 x i32]]*> [#uses=0] +@imr = external global [41 x [41 x i32]], align 32 ; <[41 x [41 x i32]]*> [#uses=0] +@rma = external global [41 x [41 x float]], align 32 ; <[41 x [41 x float]]*> [#uses=0] +@rmb = external global [41 x [41 x float]], align 32 ; <[41 x [41 x float]]*> [#uses=0] +@rmr = external global [41 x [41 x float]], align 32 ; <[41 x [41 x float]]*> [#uses=0] +@piececount = external global [4 x i32], align 16 ; <[4 x i32]*> [#uses=0] +@class = external global [13 x i32], align 32 ; <[13 x i32]*> [#uses=0] +@piecemax = external global [13 x i32], align 32 ; <[13 x i32]*> [#uses=0] +@puzzl = external global [512 x i32], align 32 ; <[512 x i32]*> [#uses=0] +@p = external global [13 x [512 x i32]], align 32 ; <[13 x [512 x i32]]*> [#uses=0] +@n = external global i32 ; <i32*> [#uses=0] +@kount = external global i32 ; <i32*> [#uses=0] +@sortlist = external global [5001 x i32], align 32 ; <[5001 x i32]*> [#uses=0] +@biggest = external global i32 ; <i32*> [#uses=0] +@littlest = external global i32 ; <i32*> [#uses=0] +@top = external global i32 ; <i32*> [#uses=0] +@z = external global [257 x %struct.complex], align 32 ; <[257 x %struct.complex]*> [#uses=0] +@w = external global [257 x %struct.complex], align 32 ; <[257 x %struct.complex]*> [#uses=0] +@e = external global [130 x %struct.complex], align 32 ; <[130 x %struct.complex]*> [#uses=0] +@zr = external global float ; <float*> [#uses=0] +@zi = external global float ; <float*> [#uses=0] + +declare void @Initrand() nounwind + +declare i32 @Rand() nounwind + +declare void @Try(i32, i32*, i32*, i32*, i32*, i32*) nounwind + +declare i32 @puts(i8* nocapture) nounwind + +declare void @Queens(i32) nounwind + +declare i32 @printf(i8* nocapture, ...) nounwind + +declare i32 @main() nounwind + +declare void @Doit() nounwind + +declare void @Doit_bb7([15 x i32]*, [17 x i32]*, [9 x i32]*) nounwind + +define void @Doit_bb7_2E_i([9 x i32]* %x1, [15 x i32]* %c, [17 x i32]* %b, [9 x i32]* %a, i32* %q, i32* %x1.sub, i32* %b9, i32* %a10, i32* %c11) nounwind { +newFuncRoot: + br label %bb7.i + +Try.exit.exitStub: ; preds = %bb7.i + ret void + +bb.i: ; preds = %bb7.i + %tmp = add i32 %j.0.i, 1 ; <i32> [#uses=5] + store i32 0, i32* %q, align 4 + %tmp1 = sext i32 %tmp to i64 ; <i64> [#uses=1] + %tmp2 = getelementptr [9 x i32]* %a, i64 0, i64 %tmp1 ; <i32*> [#uses=1] + %tmp3 = load i32* %tmp2, align 4 ; <i32> [#uses=1] + %tmp4 = icmp eq i32 %tmp3, 0 ; <i1> [#uses=1] + br i1 %tmp4, label %bb.i.bb7.i.backedge_crit_edge, label %bb1.i + +bb1.i: ; preds = %bb.i + %tmp5 = add i32 %j.0.i, 2 ; <i32> [#uses=1] + %tmp6 = sext i32 %tmp5 to i64 ; <i64> [#uses=1] + %tmp7 = getelementptr [17 x i32]* %b, i64 0, i64 %tmp6 ; <i32*> [#uses=1] + %tmp8 = load i32* %tmp7, align 4 ; <i32> [#uses=1] + %tmp9 = icmp eq i32 %tmp8, 0 ; <i1> [#uses=1] + br i1 %tmp9, label %bb1.i.bb7.i.backedge_crit_edge, label %bb2.i + +bb2.i: ; preds = %bb1.i + %tmp10 = sub i32 7, %j.0.i ; <i32> [#uses=1] + %tmp11 = sext i32 %tmp10 to i64 ; <i64> [#uses=1] + %tmp12 = getelementptr [15 x i32]* %c, i64 0, i64 %tmp11 ; <i32*> [#uses=1] + %tmp13 = load i32* %tmp12, align 4 ; <i32> [#uses=1] + %tmp14 = icmp eq i32 %tmp13, 0 ; <i1> [#uses=1] + br i1 %tmp14, label %bb2.i.bb7.i.backedge_crit_edge, label %bb3.i + +bb3.i: ; preds = %bb2.i + %tmp15 = getelementptr [9 x i32]* %x1, i64 0, i64 1 ; <i32*> [#uses=1] + store i32 %tmp, i32* %tmp15, align 4 + %tmp16 = sext i32 %tmp to i64 ; <i64> [#uses=1] + %tmp17 = getelementptr [9 x i32]* %a, i64 0, i64 %tmp16 ; <i32*> [#uses=1] + store i32 0, i32* %tmp17, align 4 + %tmp18 = add i32 %j.0.i, 2 ; <i32> [#uses=1] + %tmp19 = sext i32 %tmp18 to i64 ; <i64> [#uses=1] + %tmp20 = getelementptr [17 x i32]* %b, i64 0, i64 %tmp19 ; <i32*> [#uses=1] + store i32 0, i32* %tmp20, align 4 + %tmp21 = sub i32 7, %j.0.i ; <i32> [#uses=1] + %tmp22 = sext i32 %tmp21 to i64 ; <i64> [#uses=1] + %tmp23 = getelementptr [15 x i32]* %c, i64 0, i64 %tmp22 ; <i32*> [#uses=1] + store i32 0, i32* %tmp23, align 4 + call void @Try(i32 2, i32* %q, i32* %b9, i32* %a10, i32* %c11, i32* %x1.sub) nounwind + %tmp24 = load i32* %q, align 4 ; <i32> [#uses=1] + %tmp25 = icmp eq i32 %tmp24, 0 ; <i1> [#uses=1] + br i1 %tmp25, label %bb5.i, label %bb3.i.bb7.i.backedge_crit_edge + +bb5.i: ; preds = %bb3.i + %tmp26 = sext i32 %tmp to i64 ; <i64> [#uses=1] + %tmp27 = getelementptr [9 x i32]* %a, i64 0, i64 %tmp26 ; <i32*> [#uses=1] + store i32 1, i32* %tmp27, align 4 + %tmp28 = add i32 %j.0.i, 2 ; <i32> [#uses=1] + %tmp29 = sext i32 %tmp28 to i64 ; <i64> [#uses=1] + %tmp30 = getelementptr [17 x i32]* %b, i64 0, i64 %tmp29 ; <i32*> [#uses=1] + store i32 1, i32* %tmp30, align 4 + %tmp31 = sub i32 7, %j.0.i ; <i32> [#uses=1] + %tmp32 = sext i32 %tmp31 to i64 ; <i64> [#uses=1] + %tmp33 = getelementptr [15 x i32]* %c, i64 0, i64 %tmp32 ; <i32*> [#uses=1] + store i32 1, i32* %tmp33, align 4 + br label %bb7.i.backedge + +bb7.i.backedge: ; preds = %bb3.i.bb7.i.backedge_crit_edge, %bb2.i.bb7.i.backedge_crit_edge, %bb1.i.bb7.i.backedge_crit_edge, %bb.i.bb7.i.backedge_crit_edge, %bb5.i + br label %bb7.i + +bb7.i: ; preds = %bb7.i.backedge, %newFuncRoot + %j.0.i = phi i32 [ 0, %newFuncRoot ], [ %tmp, %bb7.i.backedge ] ; <i32> [#uses=8] + %tmp34 = load i32* %q, align 4 ; <i32> [#uses=1] + %tmp35 = icmp eq i32 %tmp34, 0 ; <i1> [#uses=1] + %tmp36 = icmp ne i32 %j.0.i, 8 ; <i1> [#uses=1] + %tmp37 = and i1 %tmp35, %tmp36 ; <i1> [#uses=1] + br i1 %tmp37, label %bb.i, label %Try.exit.exitStub + +bb.i.bb7.i.backedge_crit_edge: ; preds = %bb.i + br label %bb7.i.backedge + +bb1.i.bb7.i.backedge_crit_edge: ; preds = %bb1.i + br label %bb7.i.backedge + +bb2.i.bb7.i.backedge_crit_edge: ; preds = %bb2.i + br label %bb7.i.backedge + +bb3.i.bb7.i.backedge_crit_edge: ; preds = %bb3.i + br label %bb7.i.backedge +} diff --git a/test/Analysis/ScalarEvolution/trip-count8.ll b/test/Analysis/ScalarEvolution/trip-count8.ll new file mode 100644 index 00000000000..005162b7921 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count8.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | grep "Loop %for\.body: backedge-taken count is (-1 + [%]ecx)" +; PR4599 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + +define i32 @foo(i32 %ecx) nounwind { +entry: + %cmp2 = icmp eq i32 %ecx, 0 ; <i1> [#uses=1] + br i1 %cmp2, label %for.end, label %bb.nph + +for.cond: ; preds = %for.inc + %cmp = icmp ult i32 %inc, %ecx ; <i1> [#uses=1] + br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.cond + %phitmp = add i32 %i.01, 2 ; <i32> [#uses=1] + br label %for.end + +bb.nph: ; preds = %entry + br label %for.body + +for.body: ; preds = %bb.nph, %for.cond + %i.01 = phi i32 [ %inc, %for.cond ], [ 0, %bb.nph ] ; <i32> [#uses=3] + %call = call i32 @bar(i32 %i.01) nounwind ; <i32> [#uses=0] + br label %for.inc + +for.inc: ; preds = %for.body + %inc = add i32 %i.01, 1 ; <i32> [#uses=2] + br label %for.cond + +for.end: ; preds = %for.cond.for.end_crit_edge, %entry + %i.0.lcssa = phi i32 [ %phitmp, %for.cond.for.end_crit_edge ], [ 1, %entry ] ; <i32> [#uses=1] + ret i32 %i.0.lcssa +} + +declare i32 @bar(i32) diff --git a/test/Analysis/ScalarEvolution/trip-count9.ll b/test/Analysis/ScalarEvolution/trip-count9.ll new file mode 100644 index 00000000000..9180f2b8dd7 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count9.ll @@ -0,0 +1,408 @@ +; RUN: opt -analyze -scalar-evolution -S < %s | FileCheck %s + +; Every combination of +; - starting at 0, 1, or %x +; - steping by 1 or 2 +; - stopping at %n or %n*2 +; - using nsw, or not + +; Some of these represent missed opportunities. + +; CHECK: Determining loop execution counts for: @foo +; CHECK: Loop %loop: backedge-taken count is (-1 + %n) +; CHECK: Loop %loop: max backedge-taken count is 6 +define void @foo(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @step2(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @start1 +; CHECK: Loop %loop: backedge-taken count is (-2 + (2 smax %n)) +; CHECK: Loop %loop: max backedge-taken count is 5 +define void @start1(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @start1_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @start1_step2(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @startx +; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax %n)) +; CHECK: Loop %loop: max backedge-taken count is -1 +define void @startx(i4 %n, i4 %x) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @startx_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @startx_step2(i4 %n, i4 %x) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @nsw +; CHECK: Loop %loop: backedge-taken count is (-1 + %n) +; CHECK: Loop %loop: max backedge-taken count is 6 +define void @nsw(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; Be careful with this one. If %n is INT4_MAX, %i.next will wrap. The nsw bit +; says that the result is undefined, but ScalarEvolution must respect that +; subsequent passes may result the undefined behavior in predictable ways. +; CHECK: Determining loop execution counts for: @nsw_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @nsw_step2(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @nsw_start1 +; CHECK: Loop %loop: backedge-taken count is (-2 + (2 smax %n)) +; CHECK: Loop %loop: max backedge-taken count is 5 +define void @nsw_start1(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @nsw_start1_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @nsw_start1_step2(i4 %n) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @nsw_startx +; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax %n)) +; CHECK: Loop %loop: max backedge-taken count is -1 +define void @nsw_startx(i4 %n, i4 %x) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @nsw_startx_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +define void @nsw_startx_step2(i4 %n, i4 %x) { +entry: + %s = icmp sgt i4 %n, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %n + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even +; CHECK: Loop %loop: backedge-taken count is (-1 + (2 * %n)) +; CHECK: Loop %loop: max backedge-taken count is 5 +define void @even(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: max backedge-taken count is 2 +define void @even_step2(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_start1 +; CHECK: Loop %loop: backedge-taken count is (-2 + (2 smax (2 * %n))) +; CHECK: Loop %loop: max backedge-taken count is 4 +define void @even_start1(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_start1_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: max backedge-taken count is 2 +define void @even_start1_step2(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_startx +; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax (2 * %n))) +; CHECK: Loop %loop: max backedge-taken count is -1 +define void @even_startx(i4 %n, i4 %x) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_startx_step2 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: max backedge-taken count is 7 +define void @even_startx_step2(i4 %n, i4 %x) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw +; CHECK: Loop %loop: backedge-taken count is (-1 + (2 * %n)) +; CHECK: Loop %loop: max backedge-taken count is 5 +define void @even_nsw(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw_step2 +; CHECK: Loop %loop: backedge-taken count is ((-1 + (2 * %n)) /u 2) +; CHECK: Loop %loop: max backedge-taken count is 2 +define void @even_nsw_step2(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw_start1 +; CHECK: Loop %loop: backedge-taken count is (-2 + (2 smax (2 * %n))) +; CHECK: Loop %loop: max backedge-taken count is 4 +define void @even_nsw_start1(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw_start1_step2 +; CHECK: Loop %loop: backedge-taken count is ((-2 + (3 smax (2 * %n))) /u 2) +; CHECK: Loop %loop: max backedge-taken count is 2 +define void @even_nsw_start1_step2(i4 %n) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ 1, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw_startx +; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax (2 * %n))) +; CHECK: Loop %loop: max backedge-taken count is -1 +define void @even_nsw_startx(i4 %n, i4 %x) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 1 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} + +; CHECK: Determining loop execution counts for: @even_nsw_startx_step2 +; CHECK: Loop %loop: backedge-taken count is ((-1 + (-1 * %x) + ((2 + %x) smax (2 * %n))) /u 2) +; CHECK: Loop %loop: max backedge-taken count is 7 +define void @even_nsw_startx_step2(i4 %n, i4 %x) { +entry: + %m = shl i4 %n, 1 + %s = icmp sgt i4 %m, 0 + br i1 %s, label %loop, label %exit +loop: + %i = phi i4 [ %x, %entry ], [ %i.next, %loop ] + %i.next = add nsw i4 %i, 2 + %t = icmp slt i4 %i.next, %m + br i1 %t, label %loop, label %exit +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/undefined.ll b/test/Analysis/ScalarEvolution/undefined.ll new file mode 100644 index 00000000000..b1f44460af6 --- /dev/null +++ b/test/Analysis/ScalarEvolution/undefined.ll @@ -0,0 +1,39 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +; ScalarEvolution shouldn't attempt to interpret expressions which have +; undefined results. + +define void @foo(i64 %x) { + + %a = udiv i64 %x, 0 +; CHECK: --> (%x /u 0) + + %B = shl i64 %x, 64 +; CHECK: --> %B + + %b = ashr i64 %B, 64 +; CHECK: --> %b + + %c = lshr i64 %x, 64 +; CHECK: --> %c + + %d = shl i64 %x, 64 +; CHECK: --> %d + + %E = shl i64 %x, -1 +; CHECK: --> %E + + %e = ashr i64 %E, -1 +; CHECK: --> %e + + %f = lshr i64 %x, -1 +; CHECK: --> %f + + %g = shl i64 %x, -1 +; CHECK: --> %g + + %h = bitcast i64 undef to i64 +; CHECK: --> undef + + ret void +} diff --git a/test/Analysis/ScalarEvolution/unreachable-code.ll b/test/Analysis/ScalarEvolution/unreachable-code.ll new file mode 100644 index 00000000000..51d93981800 --- /dev/null +++ b/test/Analysis/ScalarEvolution/unreachable-code.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +; CHECK: %t = add i64 %t, 1 +; CHECK: --> %t + +define void @foo() { +entry: + ret void + +dead: + %t = add i64 %t, 1 + ret void +} diff --git a/test/Analysis/ScalarEvolution/unsimplified-loop.ll b/test/Analysis/ScalarEvolution/unsimplified-loop.ll new file mode 100644 index 00000000000..a3175077b68 --- /dev/null +++ b/test/Analysis/ScalarEvolution/unsimplified-loop.ll @@ -0,0 +1,29 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +; This loop has no preheader, multiple backedges, etc., but ScalarEvolution +; should still be able to analyze it. + +; CHECK: %i = phi i64 [ 5, %entry ], [ 5, %alt ], [ %i.next, %loop.a ], [ %i.next, %loop.b ] +; CHECK-NEXT: --> {5,+,1}<%loop> + +define void @foo(i1 %p, i1 %q, i1 %s, i1 %u) { +entry: + br i1 %p, label %loop, label %alt + +alt: + br i1 %s, label %loop, label %exit + +loop: + %i = phi i64 [ 5, %entry ], [ 5, %alt ], [ %i.next, %loop.a ], [ %i.next, %loop.b ] + %i.next = add i64 %i, 1 + br i1 %q, label %loop.a, label %loop.b + +loop.a: + br label %loop + +loop.b: + br i1 %u, label %loop, label %exit + +exit: + ret void +} diff --git a/test/Analysis/ScalarEvolution/xor-and.ll b/test/Analysis/ScalarEvolution/xor-and.ll new file mode 100644 index 00000000000..4ab2f39a281 --- /dev/null +++ b/test/Analysis/ScalarEvolution/xor-and.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -scalar-evolution -analyze \ +; RUN: | grep "\--> (zext i4 (-8 + (trunc i64 (8 \* %x) to i4)) to i64)" + +; ScalarEvolution shouldn't try to analyze %z into something like +; --> (zext i4 (-1 + (-1 * (trunc i64 (8 * %x) to i4))) to i64) + +define i64 @foo(i64 %x) { + %a = shl i64 %x, 3 + %t = and i64 %a, 8 + %z = xor i64 %t, 8 + ret i64 %z +} diff --git a/test/Analysis/ScalarEvolution/zext-wrap.ll b/test/Analysis/ScalarEvolution/zext-wrap.ll new file mode 100644 index 00000000000..38d15ffbd88 --- /dev/null +++ b/test/Analysis/ScalarEvolution/zext-wrap.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -analyze -scalar-evolution \ +; RUN: | FileCheck %s +; PR4569 + +define i16 @main() nounwind { +entry: + br label %bb.i + +bb.i: ; preds = %bb1.i, %bb.nph + %l_95.0.i1 = phi i8 [ %tmp1, %bb.i ], [ 0, %entry ] + +; 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) Exits: 2 + + %tmp = zext i8 %l_95.0.i1 to i16 + + %tmp1 = add i8 %l_95.0.i1, -1 + %phitmp = icmp eq i8 %tmp1, 1 + br i1 %phitmp, label %bb1.i.func_36.exit_crit_edge, label %bb.i + +bb1.i.func_36.exit_crit_edge: + ret i16 %tmp +} diff --git a/test/Analysis/TypeBasedAliasAnalysis/aliastest.ll b/test/Analysis/TypeBasedAliasAnalysis/aliastest.ll new file mode 100644 index 00000000000..d59e3924acd --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/aliastest.ll @@ -0,0 +1,62 @@ +; RUN: opt < %s -tbaa -basicaa -gvn -S | FileCheck %s + +; Test that basic alias queries work. + +; CHECK: @test0_yes +; CHECK: add i8 %x, %x +define i8 @test0_yes(i8* %a, i8* %b) nounwind { + %x = load i8* %a, !tbaa !1 + store i8 0, i8* %b, !tbaa !2 + %y = load i8* %a, !tbaa !1 + %z = add i8 %x, %y + ret i8 %z +} + +; CHECK: @test0_no +; CHECK: add i8 %x, %y +define i8 @test0_no(i8* %a, i8* %b) nounwind { + %x = load i8* %a, !tbaa !3 + store i8 0, i8* %b, !tbaa !4 + %y = load i8* %a, !tbaa !3 + %z = add i8 %x, %y + ret i8 %z +} + +; Test that basic invariant-memory queries work. + +; CHECK: @test1_yes +; CHECK: add i8 %x, %x +define i8 @test1_yes(i8* %a, i8* %b) nounwind { + %x = load i8* %a, !tbaa !5 + store i8 0, i8* %b + %y = load i8* %a, !tbaa !5 + %z = add i8 %x, %y + ret i8 %z +} + +; CHECK: @test1_no +; CHECK: add i8 %x, %y +define i8 @test1_no(i8* %a, i8* %b) nounwind { + %x = load i8* %a, !tbaa !6 + store i8 0, i8* %b + %y = load i8* %a, !tbaa !6 + %z = add i8 %x, %y + ret i8 %z +} + +; Root note. +!0 = metadata !{ } +; Some type. +!1 = metadata !{ metadata !"foo", metadata !0 } +; Some other non-aliasing type. +!2 = metadata !{ metadata !"bar", metadata !0 } + +; Some type. +!3 = metadata !{ metadata !"foo", metadata !0 } +; Some type in a different type system. +!4 = metadata !{ metadata !"bar", metadata !"different" } + +; Invariant memory. +!5 = metadata !{ metadata !"qux", metadata !0, i1 1 } +; Not invariant memory. +!6 = metadata !{ metadata !"qux", metadata !0, i1 0 } diff --git a/test/Analysis/TypeBasedAliasAnalysis/argument-promotion.ll b/test/Analysis/TypeBasedAliasAnalysis/argument-promotion.ll new file mode 100644 index 00000000000..3b5211e5999 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/argument-promotion.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -tbaa -basicaa -argpromotion -mem2reg -S | not grep alloca + +target datalayout = "E-p:64:64:64" + +define internal i32 @test(i32* %X, i32* %Y, i32* %Q) { + store i32 77, i32* %Q, !tbaa !2 + %A = load i32* %X, !tbaa !1 + %B = load i32* %Y, !tbaa !1 + %C = add i32 %A, %B + ret i32 %C +} + +define internal i32 @caller(i32* %B, i32* %Q) { + %A = alloca i32 + store i32 78, i32* %Q, !tbaa !2 + store i32 1, i32* %A, !tbaa !1 + %C = call i32 @test(i32* %A, i32* %B, i32* %Q) + ret i32 %C +} + +define i32 @callercaller(i32* %Q) { + %B = alloca i32 + store i32 2, i32* %B, !tbaa !1 + store i32 79, i32* %Q, !tbaa !2 + %X = call i32 @caller(i32* %B, i32* %Q) + ret i32 %X +} + +!0 = metadata !{metadata !"test"} +!1 = metadata !{metadata !"green", metadata !0} +!2 = metadata !{metadata !"blue", metadata !0} diff --git a/test/Analysis/TypeBasedAliasAnalysis/dse.ll b/test/Analysis/TypeBasedAliasAnalysis/dse.ll new file mode 100644 index 00000000000..6b44eb63842 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/dse.ll @@ -0,0 +1,66 @@ +; RUN: opt < %s -tbaa -basicaa -dse -S | FileCheck %s + +; DSE should make use of TBAA. + +; CHECK: @test0_yes +; CHECK-NEXT: load i8* %b +; CHECK-NEXT: store i8 1, i8* %a +; CHECK-NEXT: ret i8 %y +define i8 @test0_yes(i8* %a, i8* %b) nounwind { + store i8 0, i8* %a, !tbaa !1 + %y = load i8* %b, !tbaa !2 + store i8 1, i8* %a, !tbaa !1 + ret i8 %y +} + +; CHECK: @test0_no +; CHECK-NEXT: store i8 0, i8* %a +; CHECK-NEXT: load i8* %b +; CHECK-NEXT: store i8 1, i8* %a +; CHECK-NEXT: ret i8 %y +define i8 @test0_no(i8* %a, i8* %b) nounwind { + store i8 0, i8* %a, !tbaa !3 + %y = load i8* %b, !tbaa !4 + store i8 1, i8* %a, !tbaa !3 + ret i8 %y +} + +; CHECK: @test1_yes +; CHECK-NEXT: load i8* %b +; CHECK-NEXT: store i8 1, i8* %a +; CHECK-NEXT: ret i8 %y +define i8 @test1_yes(i8* %a, i8* %b) nounwind { + store i8 0, i8* %a + %y = load i8* %b, !tbaa !5 + store i8 1, i8* %a + ret i8 %y +} + +; CHECK: @test1_no +; CHECK-NEXT: store i8 0, i8* %a +; CHECK-NEXT: load i8* %b +; CHECK-NEXT: store i8 1, i8* %a +; CHECK-NEXT: ret i8 %y +define i8 @test1_no(i8* %a, i8* %b) nounwind { + store i8 0, i8* %a + %y = load i8* %b, !tbaa !6 + store i8 1, i8* %a + ret i8 %y +} + +; Root note. +!0 = metadata !{ } +; Some type. +!1 = metadata !{ metadata !"foo", metadata !0 } +; Some other non-aliasing type. +!2 = metadata !{ metadata !"bar", metadata !0 } + +; Some type. +!3 = metadata !{ metadata !"foo", metadata !0 } +; Some type in a different type system. +!4 = metadata !{ metadata !"bar", metadata !"different" } + +; Invariant memory. +!5 = metadata !{ metadata !"qux", metadata !0, i1 1 } +; Not invariant memory. +!6 = metadata !{ metadata !"qux", metadata !0, i1 0 } diff --git a/test/Analysis/TypeBasedAliasAnalysis/dynamic-indices.ll b/test/Analysis/TypeBasedAliasAnalysis/dynamic-indices.ll new file mode 100644 index 00000000000..52e394b2d09 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/dynamic-indices.ll @@ -0,0 +1,131 @@ +; RUN: opt -tbaa -basicaa -gvn -S < %s | FileCheck %s +; PR9971 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + +%struct.X = type { i32, float } +%union.vector_t = type { [2 x i64] } + +; Don't delete the load after the loop, because it loads values stored +; inside the loop. + +; CHECK: define void @vrlh( + +; CHECK: for.end: +; CHECK: %arrayidx31 = getelementptr inbounds %union.vector_t* %t, i64 0, i32 0, i64 1 +; CHECK: %tmp32 = load i64* %arrayidx31, align 8, !tbaa !3 + +define void @vrlh(%union.vector_t* %va, %union.vector_t* %vb, %union.vector_t* %vd) nounwind { +entry: + %t = alloca %union.vector_t, align 8 + br label %for.body + +for.body: ; preds = %entry, %for.body + %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %sub = sub nsw i32 7, %i.01 + %idxprom = sext i32 %sub to i64 + %half = bitcast %union.vector_t* %vb to [8 x i16]* + %arrayidx = getelementptr inbounds [8 x i16]* %half, i64 0, i64 %idxprom + %tmp4 = load i16* %arrayidx, align 2, !tbaa !0 + %conv = zext i16 %tmp4 to i32 + %and = and i32 %conv, 15 + %sub6 = sub nsw i32 7, %i.01 + %idxprom7 = sext i32 %sub6 to i64 + %half9 = bitcast %union.vector_t* %va to [8 x i16]* + %arrayidx10 = getelementptr inbounds [8 x i16]* %half9, i64 0, i64 %idxprom7 + %tmp11 = load i16* %arrayidx10, align 2, !tbaa !0 + %conv12 = zext i16 %tmp11 to i32 + %shl = shl i32 %conv12, %and + %sub15 = sub nsw i32 7, %i.01 + %idxprom16 = sext i32 %sub15 to i64 + %half18 = bitcast %union.vector_t* %va to [8 x i16]* + %arrayidx19 = getelementptr inbounds [8 x i16]* %half18, i64 0, i64 %idxprom16 + %tmp20 = load i16* %arrayidx19, align 2, !tbaa !0 + %conv21 = zext i16 %tmp20 to i32 + %sub23 = sub nsw i32 16, %and + %shr = lshr i32 %conv21, %sub23 + %or = or i32 %shl, %shr + %conv24 = trunc i32 %or to i16 + %sub26 = sub nsw i32 7, %i.01 + %idxprom27 = sext i32 %sub26 to i64 + %half28 = bitcast %union.vector_t* %t to [8 x i16]* + %arrayidx29 = getelementptr inbounds [8 x i16]* %half28, i64 0, i64 %idxprom27 + store i16 %conv24, i16* %arrayidx29, align 2, !tbaa !0 + %inc = add nsw i32 %i.01, 1 + %cmp = icmp slt i32 %inc, 8 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + %arrayidx31 = getelementptr inbounds %union.vector_t* %t, i64 0, i32 0, i64 1 + %tmp32 = load i64* %arrayidx31, align 8, !tbaa !3 + %arrayidx35 = getelementptr inbounds %union.vector_t* %vd, i64 0, i32 0, i64 1 + store i64 %tmp32, i64* %arrayidx35, align 8, !tbaa !3 + %arrayidx37 = getelementptr inbounds %union.vector_t* %t, i64 0, i32 0, i64 0 + %tmp38 = load i64* %arrayidx37, align 8, !tbaa !3 + %arrayidx41 = getelementptr inbounds %union.vector_t* %vd, i64 0, i32 0, i64 0 + store i64 %tmp38, i64* %arrayidx41, align 8, !tbaa !3 + ret void +} + +; Do delete the load after the loop. + +; CHECK: define i32 @test0( + +; CHECK: ret i32 0 + +define i32 @test0(%struct.X* %a) nounwind { +entry: + %i = getelementptr inbounds %struct.X* %a, i64 0, i32 0 + store i32 0, i32* %i, align 4, !tbaa !4 + br label %for.body + +for.body: ; preds = %entry, %for.body + %i2.01 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %f = getelementptr inbounds %struct.X* %a, i64 %i2.01, i32 1 + %tmp6 = load float* %f, align 4, !tbaa !5 + %mul = fmul float %tmp6, 0x40019999A0000000 + store float %mul, float* %f, align 4, !tbaa !5 + %inc = add nsw i64 %i2.01, 1 + %cmp = icmp slt i64 %inc, 10000 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + %i9 = getelementptr inbounds %struct.X* %a, i64 0, i32 0 + %tmp10 = load i32* %i9, align 4, !tbaa !4 + ret i32 %tmp10 +} + +; Do delete the load after the loop. + +; CHECK: define float @test1( + +; CHECK: ret float 0x3FD3333340000000 + +define float @test1(%struct.X* %a) nounwind { +entry: + %f = getelementptr inbounds %struct.X* %a, i64 0, i32 1 + store float 0x3FD3333340000000, float* %f, align 4, !tbaa !5 + br label %for.body + +for.body: ; preds = %entry, %for.body + %i.01 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %i5 = getelementptr inbounds %struct.X* %a, i64 %i.01, i32 0 + %tmp6 = load i32* %i5, align 4, !tbaa !4 + %mul = mul nsw i32 %tmp6, 3 + store i32 %mul, i32* %i5, align 4, !tbaa !4 + %inc = add nsw i64 %i.01, 1 + %cmp = icmp slt i64 %inc, 10000 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + %f9 = getelementptr inbounds %struct.X* %a, i64 0, i32 1 + %tmp10 = load float* %f9, align 4, !tbaa !5 + ret float %tmp10 +} + +!0 = metadata !{metadata !"short", metadata !1} +!1 = metadata !{metadata !"omnipotent char", metadata !2} +!2 = metadata !{metadata !"Simple C/C++ TBAA", null} +!3 = metadata !{metadata !"long long", metadata !1} +!4 = metadata !{metadata !"int", metadata !1} +!5 = metadata !{metadata !"float", metadata !1} diff --git a/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll new file mode 100644 index 00000000000..1ac59278e7e --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -0,0 +1,81 @@ +; RUN: opt < %s -tbaa -basicaa -functionattrs -S | FileCheck %s + +; FunctionAttrs should make use of TBAA. + +; Add the readnone attribute, since the only access is a store which TBAA +; says is to constant memory. +; +; It's unusual to see a store to constant memory, but it isn't necessarily +; invalid, as it's possible that this only happens after optimization on a +; code path which isn't ever executed. + +; CHECK: define void @test0_yes(i32* nocapture %p) nounwind readnone { +define void @test0_yes(i32* %p) nounwind { + store i32 0, i32* %p, !tbaa !1 + ret void +} + +; CHECK: define void @test0_no(i32* nocapture %p) nounwind { +define void @test0_no(i32* %p) nounwind { + store i32 0, i32* %p, !tbaa !2 + ret void +} + +; Add the readonly attribute, since there's just a call to a function which +; TBAA says doesn't modify any memory. + +; CHECK: define void @test1_yes(i32* nocapture %p) nounwind readonly { +define void @test1_yes(i32* %p) nounwind { + call void @callee(i32* %p), !tbaa !1 + ret void +} + +; CHECK: define void @test1_no(i32* %p) nounwind { +define void @test1_no(i32* %p) nounwind { + call void @callee(i32* %p), !tbaa !2 + ret void +} + +; Add the readonly attribute, as above, but this time BasicAA will say +; that the function accesses memory through its arguments, which TBAA +; still says that the function doesn't write to memory. +; +; This is unusual, since the function is memcpy, but as above, this +; isn't necessarily invalid. + +; CHECK: define void @test2_yes(i8* nocapture %p, i8* nocapture %q, i64 %n) nounwind readnone { +define void @test2_yes(i8* %p, i8* %q, i64 %n) nounwind { + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 %n, i32 1, i1 false), !tbaa !1 + ret void +} + +; CHECK: define void @test2_no(i8* nocapture %p, i8* nocapture %q, i64 %n) nounwind { +define void @test2_no(i8* %p, i8* %q, i64 %n) nounwind { + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 %n, i32 1, i1 false), !tbaa !2 + ret void +} + +; Similar to the others, va_arg only accesses memory through its operand. + +; CHECK: define i32 @test3_yes(i8* nocapture %p) nounwind readnone { +define i32 @test3_yes(i8* %p) nounwind { + %t = va_arg i8* %p, i32, !tbaa !1 + ret i32 %t +} + +; CHECK: define i32 @test3_no(i8* nocapture %p) nounwind { +define i32 @test3_no(i8* %p) nounwind { + %t = va_arg i8* %p, i32, !tbaa !2 + ret i32 %t +} + +declare void @callee(i32* %p) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) nounwind + +; Root note. +!0 = metadata !{ } + +; Invariant memory. +!1 = metadata !{ metadata !"foo", metadata !0, i1 1 } +; Not invariant memory. +!2 = metadata !{ metadata !"foo", metadata !0, i1 0 } diff --git a/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll b/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll new file mode 100644 index 00000000000..eceaa2cf02d --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll @@ -0,0 +1,91 @@ +; RUN: opt -tbaa -basicaa -gvn -S < %s | FileCheck %s + +target datalayout = "e-p:64:64:64" + +; GVN should ignore the store to p1 to see that the load from p is +; fully redundant. + +; CHECK: @yes +; CHECK: if.then: +; CHECK-NEXT: store i32 0, i32* %q +; CHECK-NEXT: ret void + +define void @yes(i1 %c, i32* %p, i32* %p1, i32* %q) nounwind { +entry: + store i32 0, i32* %p, !tbaa !1 + store i32 1, i32* %p1, !tbaa !2 + br i1 %c, label %if.else, label %if.then + +if.then: + %t = load i32* %p, !tbaa !1 + store i32 %t, i32* %q + ret void + +if.else: + ret void +} + +; GVN should ignore the store to p1 to see that the first load from p is +; fully redundant. However, the second load uses a different type. Theoretically +; the other type could be unified with the first type, however for now, GVN +; should just be conservative. + +; CHECK: @watch_out_for_type_change +; CHECK: if.then: +; CHECK: %t = load i32* %p +; CHECK: store i32 %t, i32* %q +; CHECK: ret void +; CHECK: if.else: +; CHECK: %u = load i32* %p +; CHECK: store i32 %u, i32* %q + +define void @watch_out_for_type_change(i1 %c, i32* %p, i32* %p1, i32* %q) nounwind { +entry: + store i32 0, i32* %p, !tbaa !1 + store i32 1, i32* %p1, !tbaa !2 + br i1 %c, label %if.else, label %if.then + +if.then: + %t = load i32* %p, !tbaa !4 + store i32 %t, i32* %q + ret void + +if.else: + %u = load i32* %p, !tbaa !3 + store i32 %u, i32* %q + ret void +} + +; As before, but the types are swapped. This time GVN does managed to +; eliminate one of the loads before noticing the type mismatch. + +; CHECK: @watch_out_for_another_type_change +; CHECK: if.then: +; CHECK: %t = load i32* %p +; CHECK: store i32 %t, i32* %q +; CHECK: ret void +; CHECK: if.else: +; CHECK: store i32 0, i32* %q + +define void @watch_out_for_another_type_change(i1 %c, i32* %p, i32* %p1, i32* %q) nounwind { +entry: + store i32 0, i32* %p, !tbaa !1 + store i32 1, i32* %p1, !tbaa !2 + br i1 %c, label %if.else, label %if.then + +if.then: + %t = load i32* %p, !tbaa !3 + store i32 %t, i32* %q + ret void + +if.else: + %u = load i32* %p, !tbaa !4 + store i32 %u, i32* %q + ret void +} + +!0 = metadata !{} +!1 = metadata !{metadata !"red", metadata !0} +!2 = metadata !{metadata !"blu", metadata !0} +!3 = metadata !{metadata !"outer space"} +!4 = metadata !{metadata !"brick red", metadata !1} diff --git a/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll b/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll new file mode 100644 index 00000000000..8f080e2108b --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll @@ -0,0 +1,27 @@ +; RUN: opt -tbaa -basicaa -gvn -S < %s | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" + +; TBAA should prove that these calls don't interfere, since they are +; IntrArgReadMem and have TBAA metadata. + +; CHECK: define <8 x i16> @test0(i8* %p, i8* %q, <8 x i16> %y) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind +; CHECK-NEXT: call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK-NEXT: %c = add <8 x i16> %a, %a +define <8 x i16> @test0(i8* %p, i8* %q, <8 x i16> %y) { +entry: + %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind, !tbaa !2 + call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16), !tbaa !1 + %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind, !tbaa !2 + %c = add <8 x i16> %a, %b + ret <8 x i16> %c +} + +declare <8 x i16> @llvm.arm.neon.vld1.v8i16(i8*, i32) nounwind readonly +declare void @llvm.arm.neon.vst1.v8i16(i8*, <8 x i16>, i32) nounwind + +!0 = metadata !{metadata !"tbaa root", null} +!1 = metadata !{metadata !"A", metadata !0} +!2 = metadata !{metadata !"B", metadata !0} diff --git a/test/Analysis/TypeBasedAliasAnalysis/licm.ll b/test/Analysis/TypeBasedAliasAnalysis/licm.ll new file mode 100644 index 00000000000..12a9c1dc564 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/licm.ll @@ -0,0 +1,61 @@ +; RUN: opt -tbaa -licm -S < %s | FileCheck %s + +; LICM should be able to hoist the address load out of the loop +; by using TBAA information. + +; CHECK: @foo +; CHECK: entry: +; CHECK-NEXT: %tmp3 = load double** @P, !tbaa !0 +; CHECK-NEXT: br label %for.body + +@P = common global double* null + +define void @foo(i64 %n) nounwind { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %i.07 = phi i64 [ %inc, %for.body ], [ 0, %entry ] + %tmp3 = load double** @P, !tbaa !1 + %scevgep = getelementptr double* %tmp3, i64 %i.07 + %tmp4 = load double* %scevgep, !tbaa !2 + %mul = fmul double %tmp4, 2.300000e+00 + store double %mul, double* %scevgep, !tbaa !2 + %inc = add i64 %i.07, 1 + %exitcond = icmp eq i64 %inc, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body, %entry + ret void +} + +!0 = metadata !{metadata !"root", null} +!1 = metadata !{metadata !"pointer", metadata !0} +!2 = metadata !{metadata !"double", metadata !0} + +; LICM shouldn't hoist anything here. + +; CHECK: @bar +; CHECK: loop: +; CHECK: load +; CHECK: store +; CHECK: load +; CHECK: store +; CHECK: br label %loop + +define void @bar(i8** %p) nounwind { +entry: + %q = bitcast i8** %p to i8* + br label %loop + +loop: + %tmp51 = load i8** %p, !tbaa !4 + store i8* %tmp51, i8** %p + %tmp40 = load i8* %q, !tbaa !5 + store i8 %tmp40, i8* %q + br label %loop +} + +!3 = metadata !{metadata !"pointer", metadata !4} +!4 = metadata !{metadata !"char", metadata !5} +!5 = metadata !{metadata !"root", null} diff --git a/test/Analysis/TypeBasedAliasAnalysis/lit.local.cfg b/test/Analysis/TypeBasedAliasAnalysis/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll b/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll new file mode 100644 index 00000000000..c2407dfd4c8 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll @@ -0,0 +1,23 @@ +; RUN: opt -S -tbaa -basicaa -memcpyopt -instcombine < %s | FileCheck %s + +target datalayout = "e-p:64:64:64" + +; The second memcpy is redundant and can be deleted. There's an intervening store, but +; it has a TBAA tag which declares that it is unrelated. + +; CHECK: @foo +; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 16, i32 1, i1 false), !tbaa !0 +; CHECK-NEXT: store i8 2, i8* %s, align 1, !tbaa !2 +; CHECK-NEXT: ret void +define void @foo(i8* nocapture %p, i8* nocapture %q, i8* nocapture %s) nounwind { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 16, i32 1, i1 false), !tbaa !2 + store i8 2, i8* %s, align 1, !tbaa !1 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %q, i8* %p, i64 16, i32 1, i1 false), !tbaa !2 + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + +!0 = metadata !{metadata !"tbaa root", null} +!1 = metadata !{metadata !"A", metadata !0} +!2 = metadata !{metadata !"B", metadata !0} diff --git a/test/Analysis/TypeBasedAliasAnalysis/precedence.ll b/test/Analysis/TypeBasedAliasAnalysis/precedence.ll new file mode 100644 index 00000000000..47cb5f2256d --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/precedence.ll @@ -0,0 +1,46 @@ +; RUN: opt -basicaa -tbaa -gvn -instcombine -S < %s | FileCheck %s --check-prefix=TBAA +; RUN: opt -tbaa -basicaa -gvn -instcombine -S < %s | FileCheck %s --check-prefix=BASICAA + +; According to the TBAA metadata the load and store don't alias. However, +; according to the actual code, they do. The order of the alias analysis +; passes should determine which of these takes precedence. + +target datalayout = "e-p:64:64:64" + +; Test for simple MustAlias aliasing. + +; TBAA: @trouble +; TBAA: ret i32 0 +; BASICAA: @trouble +; BASICAA: ret i32 1075000115 +define i32 @trouble(i32* %x) nounwind { +entry: + store i32 0, i32* %x, !tbaa !0 + %0 = bitcast i32* %x to float* + store float 0x4002666660000000, float* %0, !tbaa !3 + %tmp3 = load i32* %x, !tbaa !0 + ret i32 %tmp3 +} + +; Test for PartialAlias aliasing. GVN doesn't yet eliminate the load +; in the BasicAA case. + +; TBAA: @offset +; TBAA: ret i64 0 +; BASICAA: @offset +; BASICAA: ret i64 %tmp3 +define i64 @offset(i64* %x) nounwind { +entry: + store i64 0, i64* %x, !tbaa !4 + %0 = bitcast i64* %x to i8* + %1 = getelementptr i8* %0, i64 1 + store i8 1, i8* %1, !tbaa !5 + %tmp3 = load i64* %x, !tbaa !4 + ret i64 %tmp3 +} + +!0 = metadata !{metadata !"int", metadata !1} +!1 = metadata !{metadata !"simple"} +!3 = metadata !{metadata !"float", metadata !1} +!4 = metadata !{metadata !"long", metadata !1} +!5 = metadata !{metadata !"small", metadata !1} diff --git a/test/Analysis/TypeBasedAliasAnalysis/sink.ll b/test/Analysis/TypeBasedAliasAnalysis/sink.ll new file mode 100644 index 00000000000..fd32d6a7a58 --- /dev/null +++ b/test/Analysis/TypeBasedAliasAnalysis/sink.ll @@ -0,0 +1,20 @@ +; RUN: opt -tbaa -sink -S < %s | FileCheck %s + +; CHECK: a: +; CHECK: %f = load float* %p, !tbaa !2 +; CHECK: store float %f, float* %q + +define void @foo(float* %p, i1 %c, float* %q, float* %r) { + %f = load float* %p, !tbaa !0 + store float 0.0, float* %r, !tbaa !1 + br i1 %c, label %a, label %b +a: + store float %f, float* %q + br label %b +b: + ret void +} + +!0 = metadata !{metadata !"A", metadata !2} +!1 = metadata !{metadata !"B", metadata !2} +!2 = metadata !{metadata !"test"} |