1; RUN: opt -S -indvars < %s | FileCheck %s
2
3; Check that SCEV is able to recognize and use guards to prove
4; conditions gaurding loop entries and backedges.  This isn't intended
5; to be a comprehensive test of SCEV's simplification capabilities,
6; tests directly testing e.g. if SCEV can elide a sext should go
7; elsewhere.
8
9target datalayout = "n8:16:32:64"
10
11declare void @llvm.experimental.guard(i1, ...)
12
13declare void @use(i64 %x)
14
15define void @test_1(i1* %cond_buf, i32* %len_buf) {
16; CHECK-LABEL: @test_1(
17entry:
18  %len = load i32, i32* %len_buf, !range !{i32 1, i32 2147483648}
19  br label %loop
20
21loop:
22; CHECK: loop:
23; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
24; CHECK:  %iv.inc.cmp = icmp ult i32 %iv.inc, %len
25; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
26; CHECK: leave:
27
28  %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
29  %iv.inc = add i32 %iv, 1
30
31  %iv.cmp = icmp slt i32 %iv, %len
32  call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
33
34  %iv.inc.cmp = icmp slt i32 %iv.inc, %len
35  call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
36
37  %becond = load volatile i1, i1* %cond_buf
38  br i1 %becond, label %loop, label %leave
39
40leave:
41  ret void
42}
43
44define void @test_2(i32 %n, i32* %len_buf) {
45; CHECK-LABEL: @test_2(
46; CHECK:  [[LEN_ZEXT:%[^ ]+]] = zext i32 %len to i64
47; CHECK:  br label %loop
48
49entry:
50  %len = load i32, i32* %len_buf, !range !{i32 0, i32 2147483648}
51  br label %loop
52
53loop:
54; CHECK: loop:
55; CHECK:  %indvars.iv = phi i64 [ %indvars.iv.next, %loop ], [ 0, %entry ]
56; CHECK:  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
57; CHECK:  %iv.inc.cmp = icmp ult i64 %indvars.iv.next, [[LEN_ZEXT]]
58; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
59; CHECK: leave:
60
61  %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
62  %iv.inc = add i32 %iv, 1
63
64  %iv.sext = sext i32 %iv to i64
65  call void @use(i64 %iv.sext)
66
67  %iv.inc.cmp = icmp slt i32 %iv.inc, %len
68  call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
69
70  %becond = icmp ne i32 %iv, %n
71  br i1 %becond, label %loop, label %leave
72
73leave:
74  ret void
75}
76
77define void @test_3(i1* %cond_buf, i32* %len_buf) {
78; CHECK-LABEL: @test_3(
79
80entry:
81  %len = load i32, i32* %len_buf
82  %entry.cond = icmp sgt i32 %len, 0
83  call void(i1, ...) @llvm.experimental.guard(i1 %entry.cond) [ "deopt"() ]
84  br label %loop
85
86loop:
87; CHECK: loop:
88; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
89; CHECK:  %iv.inc.cmp = icmp slt i32 %iv.inc, %len
90; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
91; CHECK: leave:
92  %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
93  %iv.inc = add i32 %iv, 1
94
95  %iv.cmp = icmp slt i32 %iv, %len
96  call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
97
98  %iv.inc.cmp = icmp slt i32 %iv.inc, %len
99  call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
100
101  %becond = load volatile i1, i1* %cond_buf
102  br i1 %becond, label %loop, label %leave
103
104leave:
105  ret void
106}
107
108define void @test_4(i1* %cond_buf, i32* %len_buf) {
109; CHECK-LABEL: @test_4(
110
111entry:
112  %len = load i32, i32* %len_buf
113  %entry.cond = icmp sgt i32 %len, 0
114  call void(i1, ...) @llvm.experimental.guard(i1 %entry.cond) [ "deopt"() ]
115  br label %loop
116
117loop:
118  %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
119  %iv.inc = add i32 %iv, 1
120
121  %cond = load volatile i1, i1* %cond_buf
122  br i1 %cond, label %left, label %be
123
124left:
125  ; Does not dominate the backedge, so cannot be used in the inductive proof
126  %iv.inc.cmp = icmp slt i32 %iv.inc, %len
127  call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
128  br label %be
129
130be:
131; CHECK: be:
132; CHECK-NEXT:  %iv.cmp = icmp slt i32 %iv, %len
133; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
134; CHECK: leave:
135
136  %iv.cmp = icmp slt i32 %iv, %len
137  call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
138
139  %becond = load volatile i1, i1* %cond_buf
140  br i1 %becond, label %loop, label %leave
141
142leave:
143  ret void
144}
145