Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / LICM / promote-single-thread.ll
blob89935b5f1ae01f0187442c73a71d407a76c5cf7b
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,MT
3 ; RUN: opt -S -passes=licm -licm-force-thread-model-single < %s | FileCheck %s --check-prefixes=CHECK,ST
5 @g = external global i32
6 @c = external constant i32
8 declare void @capture(ptr)
10 ; Even in single-thread mode, can only perform load-only promotion for globals,
11 ; because we might not have provenance to write to the global. See
12 ; promote_global_noalias for an example of the issue.
13 define void @promote_global(i1 %c, i1 %c2) {
14 ; CHECK-LABEL: @promote_global(
15 ; CHECK-NEXT:  entry:
16 ; CHECK-NEXT:    [[G_PROMOTED:%.*]] = load i32, ptr @g, align 4
17 ; CHECK-NEXT:    br label [[LOOP:%.*]]
18 ; CHECK:       loop:
19 ; CHECK-NEXT:    [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[G_PROMOTED]], [[ENTRY:%.*]] ]
20 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
21 ; CHECK:       if:
22 ; CHECK-NEXT:    [[V_INC:%.*]] = add i32 [[V_INC2]], 1
23 ; CHECK-NEXT:    store i32 [[V_INC]], ptr @g, align 4
24 ; CHECK-NEXT:    br label [[LATCH]]
25 ; CHECK:       latch:
26 ; CHECK-NEXT:    [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
27 ; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
28 ; CHECK:       exit:
29 ; CHECK-NEXT:    ret void
31 entry:
32   br label %loop
34 loop:
35   br i1 %c, label %if, label %latch
37 if:
38   %v = load i32, ptr @g
39   %v.inc = add i32 %v, 1
40   store i32 %v.inc, ptr @g
41   br label %latch
43 latch:
44   br i1 %c2, label %exit, label %loop
46 exit:
47   ret void
50 ; The store can never be promoted here, because the global is constant, and
51 ; the store could trap.
52 define void @promote_constant_global(i1 %c, i1 %c2) {
53 ; CHECK-LABEL: @promote_constant_global(
54 ; CHECK-NEXT:  entry:
55 ; CHECK-NEXT:    [[V:%.*]] = load i32, ptr @c, align 4
56 ; CHECK-NEXT:    [[V_INC:%.*]] = add i32 [[V]], 1
57 ; CHECK-NEXT:    br label [[LOOP:%.*]]
58 ; CHECK:       loop:
59 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH:%.*]]
60 ; CHECK:       if:
61 ; CHECK-NEXT:    store i32 [[V_INC]], ptr @c, align 4
62 ; CHECK-NEXT:    br label [[LATCH]]
63 ; CHECK:       latch:
64 ; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
65 ; CHECK:       exit:
66 ; CHECK-NEXT:    ret void
68 entry:
69   br label %loop
71 loop:
72   br i1 %c, label %if, label %latch
74 if:
75   %v = load i32, ptr @c
76   %v.inc = add i32 %v, 1
77   store i32 %v.inc, ptr @c
78   br label %latch
80 latch:
81   br i1 %c2, label %exit, label %loop
83 exit:
84   ret void
87 ; if %c is false and %ptr == @g, then this should store 42 to the pointer.
88 ; However, if we perform load+store promotion, then we would instead store the
89 ; original value of the global.
90 define void @promote_global_noalias(i1 %c, i1 %c2, ptr noalias %ptr) {
91 ; CHECK-LABEL: @promote_global_noalias(
92 ; CHECK-NEXT:  entry:
93 ; CHECK-NEXT:    [[G_PROMOTED:%.*]] = load i32, ptr @g, align 4
94 ; CHECK-NEXT:    br label [[LOOP:%.*]]
95 ; CHECK:       loop:
96 ; CHECK-NEXT:    [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[G_PROMOTED]], [[ENTRY:%.*]] ]
97 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
98 ; CHECK:       if:
99 ; CHECK-NEXT:    [[V_INC:%.*]] = add i32 [[V_INC2]], 1
100 ; CHECK-NEXT:    store i32 [[V_INC]], ptr @g, align 4
101 ; CHECK-NEXT:    br label [[LATCH]]
102 ; CHECK:       else:
103 ; CHECK-NEXT:    store i32 42, ptr [[PTR:%.*]], align 4
104 ; CHECK-NEXT:    br label [[LATCH]]
105 ; CHECK:       latch:
106 ; CHECK-NEXT:    [[V_INC1]] = phi i32 [ [[V_INC2]], [[ELSE]] ], [ [[V_INC]], [[IF]] ]
107 ; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
108 ; CHECK:       exit:
109 ; CHECK-NEXT:    ret void
111 entry:
112   br label %loop
114 loop:
115   br i1 %c, label %if, label %else
118   %v = load i32, ptr @g
119   %v.inc = add i32 %v, 1
120   store i32 %v.inc, ptr @g
121   br label %latch
123 else:
124   store i32 42, ptr %ptr
125   br label %latch
127 latch:
128   br i1 %c2, label %exit, label %loop
130 exit:
131   ret void
134 ; In single-thread mode both loads and stores can be promoted. In multi-thread
135 ; mode only loads can be promoted, as a different thread might write to the
136 ; captured alloca.
137 define void @promote_captured_alloca(i1 %c, i1 %c2) {
138 ; MT-LABEL: @promote_captured_alloca(
139 ; MT-NEXT:  entry:
140 ; MT-NEXT:    [[A:%.*]] = alloca i32, align 4
141 ; MT-NEXT:    call void @capture(ptr [[A]])
142 ; MT-NEXT:    [[A_PROMOTED:%.*]] = load i32, ptr [[A]], align 4
143 ; MT-NEXT:    br label [[LOOP:%.*]]
144 ; MT:       loop:
145 ; MT-NEXT:    [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[A_PROMOTED]], [[ENTRY:%.*]] ]
146 ; MT-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
147 ; MT:       if:
148 ; MT-NEXT:    [[V_INC:%.*]] = add i32 [[V_INC2]], 1
149 ; MT-NEXT:    store i32 [[V_INC]], ptr [[A]], align 4
150 ; MT-NEXT:    br label [[LATCH]]
151 ; MT:       latch:
152 ; MT-NEXT:    [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
153 ; MT-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
154 ; MT:       exit:
155 ; MT-NEXT:    ret void
157 ; ST-LABEL: @promote_captured_alloca(
158 ; ST-NEXT:  entry:
159 ; ST-NEXT:    [[A:%.*]] = alloca i32, align 4
160 ; ST-NEXT:    call void @capture(ptr [[A]])
161 ; ST-NEXT:    [[A_PROMOTED:%.*]] = load i32, ptr [[A]], align 4
162 ; ST-NEXT:    br label [[LOOP:%.*]]
163 ; ST:       loop:
164 ; ST-NEXT:    [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[A_PROMOTED]], [[ENTRY:%.*]] ]
165 ; ST-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
166 ; ST:       if:
167 ; ST-NEXT:    [[V_INC:%.*]] = add i32 [[V_INC2]], 1
168 ; ST-NEXT:    br label [[LATCH]]
169 ; ST:       latch:
170 ; ST-NEXT:    [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
171 ; ST-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
172 ; ST:       exit:
173 ; ST-NEXT:    [[V_INC1_LCSSA:%.*]] = phi i32 [ [[V_INC1]], [[LATCH]] ]
174 ; ST-NEXT:    store i32 [[V_INC1_LCSSA]], ptr [[A]], align 4
175 ; ST-NEXT:    ret void
177 entry:
178   %a = alloca i32
179   call void @capture(ptr %a)
180   br label %loop
182 loop:
183   br i1 %c, label %if, label %latch
186   %v = load i32, ptr %a
187   %v.inc = add i32 %v, 1
188   store i32 %v.inc, ptr %a
189   br label %latch
191 latch:
192   br i1 %c2, label %exit, label %loop
194 exit:
195   ret void
198 ; The store cannot be promoted here, because we do not know whether the
199 ; argument memory is writable.
200 define void @promote_arg(ptr noalias dereferenceable(4) align 4 %arg, i1 %c, i1 %c2) {
201 ; CHECK-LABEL: @promote_arg(
202 ; CHECK-NEXT:  entry:
203 ; CHECK-NEXT:    [[ARG_PROMOTED:%.*]] = load i32, ptr [[ARG:%.*]], align 4
204 ; CHECK-NEXT:    br label [[LOOP:%.*]]
205 ; CHECK:       loop:
206 ; CHECK-NEXT:    [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[ARG_PROMOTED]], [[ENTRY:%.*]] ]
207 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
208 ; CHECK:       if:
209 ; CHECK-NEXT:    [[V_INC:%.*]] = add i32 [[V_INC2]], 1
210 ; CHECK-NEXT:    store i32 [[V_INC]], ptr [[ARG]], align 4
211 ; CHECK-NEXT:    br label [[LATCH]]
212 ; CHECK:       latch:
213 ; CHECK-NEXT:    [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
214 ; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
215 ; CHECK:       exit:
216 ; CHECK-NEXT:    ret void
218 entry:
219   br label %loop
221 loop:
222   br i1 %c, label %if, label %latch
225   %v = load i32, ptr %arg
226   %v.inc = add i32 %v, 1
227   store i32 %v.inc, ptr %arg
228   br label %latch
230 latch:
231   br i1 %c2, label %exit, label %loop
233 exit:
234   ret void