xref: /llvm-project/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll (revision a3bbab18527b57c19ef0d55c68727af01ed55b1e)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
4
5define i8 @test1(i32 %a, i32 %length) {
6; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
7; CHECK-LABEL: define {{[^@]+}}@test1
8; CHECK-SAME: (i32 [[A:%.*]], i32 [[LENGTH:%.*]]) #[[ATTR0:[0-9]+]] {
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    br label [[LOOP:%.*]]
11; CHECK:       loop:
12; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
13; CHECK-NEXT:    br label [[BACKEDGE]]
14; CHECK:       backedge:
15; CHECK-NEXT:    [[IV_NEXT]] = add nsw i32 [[IV]], 1
16; CHECK-NEXT:    [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400
17; CHECK-NEXT:    br i1 [[CONT]], label [[LOOP]], label [[EXIT:%.*]]
18; CHECK:       exit:
19; CHECK-NEXT:    ret i8 0
20;
21entry:
22  br label %loop
23
24loop:
25  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
26  %cnd = icmp sge i32 %iv, 0
27  br i1 %cnd, label %backedge, label %exit
28
29backedge:
30  %iv.next = add nsw i32 %iv, 1
31  %cont = icmp slt i32 %iv.next, 400
32  br i1 %cont, label %loop, label %exit
33
34exit:
35  ret i8 0
36}
37
38define i8 @test2(i32 %n) {
39; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
40; CHECK-LABEL: define {{[^@]+}}@test2
41; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0]] {
42; CHECK-NEXT:  entry:
43; CHECK-NEXT:    br label [[LOOP:%.*]]
44; CHECK:       loop:
45; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
46; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[IV2_NEXT:%.*]], [[BACKEDGE]] ]
47; CHECK-NEXT:    [[CND2:%.*]] = icmp sgt i32 [[IV2]], 0
48; CHECK-NEXT:    br i1 [[CND2]], label [[BACKEDGE]], label [[EXIT:%.*]]
49; CHECK:       backedge:
50; CHECK-NEXT:    [[IV_NEXT]] = add nsw i32 [[IV]], 1
51; CHECK-NEXT:    [[IV2_NEXT]] = sub nsw i32 [[IV2]], 1
52; CHECK-NEXT:    [[CONT1:%.*]] = icmp slt i32 [[IV_NEXT]], 400
53; CHECK-NEXT:    [[CONT2:%.*]] = icmp sgt i32 [[IV2_NEXT]], 0
54; CHECK-NEXT:    [[CONT:%.*]] = and i1 [[CONT1]], [[CONT2]]
55; CHECK-NEXT:    br i1 [[CONT]], label [[LOOP]], label [[EXIT]]
56; CHECK:       exit:
57; CHECK-NEXT:    ret i8 0
58;
59entry:
60  br label %loop
61
62loop:
63  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
64  %iv2 = phi i32 [%n, %entry], [%iv2.next, %backedge]
65
66  %cnd1 = icmp sge i32 %iv, 0
67  %cnd2 = icmp sgt i32 %iv2, 0
68  %cnd = and i1 %cnd1, %cnd2
69  br i1 %cnd, label %backedge, label %exit
70
71backedge:
72  %iv.next = add nsw i32 %iv, 1
73  %iv2.next = sub nsw i32 %iv2, 1
74  %cont1 = icmp slt i32 %iv.next, 400
75  %cont2 = icmp sgt i32 %iv2.next, 0
76  %cont = and i1 %cont1, %cont2
77  br i1 %cont, label %loop, label %exit
78
79exit:
80  ret i8 0
81}
82
83; Merging cont block into do block.
84define i32 @test3(i32 %i, i1 %f, i32 %n) {
85; CHECK-LABEL: define {{[^@]+}}@test3
86; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) {
87; CHECK-NEXT:  entry:
88; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[I]], -2134
89; CHECK-NEXT:    br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
90; CHECK:       exit:
91; CHECK-NEXT:    [[C1:%.*]] = icmp ne i32 [[I]], -42
92; CHECK-NEXT:    br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
93; CHECK:       cont:
94; CHECK-NEXT:    [[COND_3:%.*]] = icmp sgt i32 [[I]], [[N]]
95; CHECK-NEXT:    br i1 [[COND_3]], label [[EXIT2]], label [[EXIT]]
96; CHECK:       do:
97; CHECK-NEXT:    [[COND_0:%.*]] = icmp sgt i32 [[I]], 0
98; CHECK-NEXT:    [[CONSUME:%.*]] = call i32 @consume(i1 [[COND_0]])
99; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I]], 0
100; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ]
101; CHECK-NEXT:    [[COND_2:%.*]] = icmp sgt i32 [[I]], 0
102; CHECK-NEXT:    br i1 [[COND_2]], label [[EXIT]], label [[CONT:%.*]]
103; CHECK:       exit2:
104; CHECK-NEXT:    ret i32 30
105;
106entry:
107  %c = icmp ne i32 %i, -2134
108  br i1 %c, label %do, label %exit
109
110exit:
111  %c1 = icmp ne i32 %i, -42
112  br i1 %c1, label %exit2, label %exit
113
114; Here cont is merged to do and i is any value except -2134.
115; i is not the single value: zero.
116cont:
117  %cond.3 = icmp sgt i32 %i, %n
118  br i1 %cond.3, label %exit2, label %exit
119
120do:
121  %cond.0 = icmp sgt i32 %i, 0
122  %consume = call i32 @consume(i1 %cond.0)
123  %cond = icmp eq i32 %i, 0
124  call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
125  %cond.2 = icmp sgt i32 %i, 0
126  br i1 %cond.2, label %exit, label %cont
127
128exit2:
129; LatticeVal for: 'i32 %i' is: constantrange<-2134, 1>
130  ret i32 30
131}
132
133; FIXME: We should be able to merge cont into do.
134; FIXME: COND should be replaced with false. This will be fixed by improving LVI.
135define i32 @test4(i32 %i, i1 %f, i32 %n) {
136; CHECK-LABEL: define {{[^@]+}}@test4
137; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) {
138; CHECK-NEXT:  entry:
139; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[I]], -2134
140; CHECK-NEXT:    br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
141; CHECK:       exit:
142; CHECK-NEXT:    [[C1:%.*]] = icmp ne i32 [[I]], -42
143; CHECK-NEXT:    br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
144; CHECK:       cont:
145; CHECK-NEXT:    call void @dummy(i1 [[F]]) #[[ATTR2:[0-9]+]]
146; CHECK-NEXT:    br label [[EXIT2]]
147; CHECK:       do:
148; CHECK-NEXT:    call void @dummy(i1 [[F]]) #[[ATTR2]]
149; CHECK-NEXT:    [[CONSUME:%.*]] = call i32 @exit()
150; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[F]])
151; CHECK-NEXT:    [[COND:%.*]] = icmp eq i1 [[F]], false
152; CHECK-NEXT:    br i1 [[COND]], label [[EXIT]], label [[CONT:%.*]]
153; CHECK:       exit2:
154; CHECK-NEXT:    ret i32 30
155;
156entry:
157  %c = icmp ne i32 %i, -2134
158  br i1 %c, label %do, label %exit
159
160exit:                                             ; preds = %do, %cont, %exit, %entry
161  %c1 = icmp ne i32 %i, -42
162  br i1 %c1, label %exit2, label %exit
163
164cont:                                             ; preds = %do
165  call void @dummy(i1 %f)
166  br label %exit2
167
168do:                                               ; preds = %entry
169  call void @dummy(i1 %f)
170  %consume = call i32 @exit()
171  call void @llvm.assume(i1 %f)
172  %cond = icmp eq i1 %f, false
173  br i1 %cond, label %exit, label %cont
174
175exit2:                                            ; preds = %cont, %exit
176  ret i32 30
177}
178
179declare i32 @exit()
180declare i32 @consume(i1)
181declare void @llvm.assume(i1) nounwind
182declare void @dummy(i1) nounwind
183declare void @llvm.experimental.guard(i1, ...)
184;.
185; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
186; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
187; CHECK: attributes #[[ATTR2]] = { nounwind }
188;.
189;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
190; CGSCC: {{.*}}
191; TUNIT: {{.*}}
192