xref: /llvm-project/llvm/test/Transforms/GVN/PRE/volatile.ll (revision 84bcfa0e1b34938d1d11a44e9e17c6e222dd2f42)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Tests that check our handling of volatile instructions encountered
3; when scanning for dependencies
4; RUN: opt -passes=gvn -enable-split-backedge-in-load-pre -S < %s | FileCheck %s
5
6; Check that we can bypass a volatile load when searching
7; for dependencies of a non-volatile load
8define i32 @test1(ptr nocapture %p, ptr nocapture %q) {
9; CHECK-LABEL: @test1(
10; CHECK-NEXT:  entry:
11; CHECK-NEXT:    [[TMP0:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4
12; CHECK-NEXT:    ret i32 0
13;
14entry:
15  %x = load i32, ptr %p
16  load volatile i32, ptr %q
17  %y = load i32, ptr %p
18  %add = sub i32 %y, %x
19  ret i32 %add
20}
21
22; We can not value forward if the query instruction is
23; volatile, this would be (in effect) removing the volatile load
24define i32 @test2(ptr nocapture %p, ptr nocapture %q) {
25; CHECK-LABEL: @test2(
26; CHECK-NEXT:  entry:
27; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
28; CHECK-NEXT:    [[Y:%.*]] = load volatile i32, ptr [[P]], align 4
29; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y]], [[X]]
30; CHECK-NEXT:    ret i32 [[ADD]]
31;
32entry:
33  %x = load i32, ptr %p
34  %y = load volatile i32, ptr %p
35  %add = sub i32 %y, %x
36  ret i32 %add
37}
38
39; If the query instruction is itself volatile, we *cannot*
40; reorder it even if p and q are noalias
41define i32 @test3(ptr noalias nocapture %p, ptr noalias nocapture %q) {
42; CHECK-LABEL: @test3(
43; CHECK-NEXT:  entry:
44; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
45; CHECK-NEXT:    [[TMP0:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4
46; CHECK-NEXT:    [[Y:%.*]] = load volatile i32, ptr [[P]], align 4
47; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y]], [[X]]
48; CHECK-NEXT:    ret i32 [[ADD]]
49;
50entry:
51  %x = load i32, ptr %p
52  load volatile i32, ptr %q
53  %y = load volatile i32, ptr %p
54  %add = sub i32 %y, %x
55  ret i32 %add
56}
57
58; If an encountered instruction is both volatile and ordered,
59; we need to use the strictest ordering of either.  In this
60; case, the ordering prevents forwarding.
61define i32 @test4(ptr noalias nocapture %p, ptr noalias nocapture %q) {
62; CHECK-LABEL: @test4(
63; CHECK-NEXT:  entry:
64; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
65; CHECK-NEXT:    [[TMP0:%.*]] = load atomic volatile i32, ptr [[Q:%.*]] seq_cst, align 4
66; CHECK-NEXT:    [[Y:%.*]] = load atomic i32, ptr [[P]] seq_cst, align 4
67; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y]], [[X]]
68; CHECK-NEXT:    ret i32 [[ADD]]
69;
70entry:
71  %x = load i32, ptr %p
72  load atomic volatile i32, ptr %q seq_cst, align 4
73  %y = load atomic i32, ptr %p seq_cst, align 4
74  %add = sub i32 %y, %x
75  ret i32 %add
76}
77
78; Value forwarding from a volatile load is perfectly legal
79define i32 @test5(ptr nocapture %p, ptr nocapture %q) {
80; CHECK-LABEL: @test5(
81; CHECK-NEXT:  entry:
82; CHECK-NEXT:    [[X:%.*]] = load volatile i32, ptr [[P:%.*]], align 4
83; CHECK-NEXT:    ret i32 0
84;
85entry:
86  %x = load volatile i32, ptr %p
87  %y = load i32, ptr %p
88  %add = sub i32 %y, %x
89  ret i32 %add
90}
91
92; Does cross block redundancy elimination work with volatiles?
93define i32 @test6(ptr noalias nocapture %p, ptr noalias nocapture %q) {
94; CHECK-LABEL: @test6(
95; CHECK-NEXT:  entry:
96; CHECK-NEXT:    [[Y1:%.*]] = load i32, ptr [[P:%.*]], align 4
97; CHECK-NEXT:    call void @use(i32 [[Y1]])
98; CHECK-NEXT:    br label [[HEADER:%.*]]
99; CHECK:       header:
100; CHECK-NEXT:    [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4
101; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y1]], [[X]]
102; CHECK-NEXT:    [[CND:%.*]] = icmp eq i32 [[ADD]], 0
103; CHECK-NEXT:    br i1 [[CND]], label [[EXIT:%.*]], label [[HEADER]]
104; CHECK:       exit:
105; CHECK-NEXT:    ret i32 0
106;
107entry:
108  %y1 = load i32, ptr %p
109  call void @use(i32 %y1)
110  br label %header
111header:
112  %x = load volatile i32, ptr %q
113  %y = load i32, ptr %p
114  %add = sub i32 %y, %x
115  %cnd = icmp eq i32 %add, 0
116  br i1 %cnd, label %exit, label %header
117exit:
118  ret i32 %add
119}
120
121; Does cross block PRE work with volatiles?
122define i32 @test7(i1 %c, ptr noalias nocapture %p, ptr noalias nocapture %q) {
123; CHECK-LABEL: @test7(
124; CHECK-NEXT:  entry:
125; CHECK-NEXT:    [[Y_PRE:%.*]] = load i32, ptr [[P:%.*]], align 4
126; CHECK-NEXT:    br i1 [[C:%.*]], label [[HEADER:%.*]], label [[SKIP:%.*]]
127; CHECK:       skip:
128; CHECK-NEXT:    call void @use(i32 [[Y_PRE]])
129; CHECK-NEXT:    br label [[HEADER]]
130; CHECK:       header:
131; CHECK-NEXT:    [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4
132; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y_PRE]], [[X]]
133; CHECK-NEXT:    [[CND:%.*]] = icmp eq i32 [[ADD]], 0
134; CHECK-NEXT:    br i1 [[CND]], label [[EXIT:%.*]], label [[HEADER]]
135; CHECK:       exit:
136; CHECK-NEXT:    ret i32 0
137;
138entry:
139  br i1 %c, label %header, label %skip
140skip:
141  %y1 = load i32, ptr %p
142  call void @use(i32 %y1)
143  br label %header
144header:
145  %x = load volatile i32, ptr %q
146  %y = load i32, ptr %p
147  %add = sub i32 %y, %x
148  %cnd = icmp eq i32 %add, 0
149  br i1 %cnd, label %exit, label %header
150exit:
151  ret i32 %add
152}
153
154; Another volatile PRE case - two paths through a loop
155; load in preheader, one path read only, one not
156define i32 @test8(i1 %b, i1 %c, ptr noalias %p, ptr noalias %q) {
157; CHECK-LABEL: @test8(
158; CHECK-NEXT:  entry:
159; CHECK-NEXT:    [[Y1:%.*]] = load i32, ptr [[P:%.*]], align 4
160; CHECK-NEXT:    call void @use(i32 [[Y1]])
161; CHECK-NEXT:    br label [[HEADER:%.*]]
162; CHECK:       header:
163; CHECK-NEXT:    [[Y:%.*]] = phi i32 [ [[Y_PRE:%.*]], [[SKIP_HEADER_CRIT_EDGE:%.*]] ], [ [[Y]], [[HEADER]] ], [ [[Y1]], [[ENTRY:%.*]] ]
164; CHECK-NEXT:    [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4
165; CHECK-NEXT:    call void @use(i32 [[Y]])
166; CHECK-NEXT:    br i1 [[B:%.*]], label [[SKIP:%.*]], label [[HEADER]]
167; CHECK:       skip:
168; CHECK-NEXT:    call void @clobber(ptr [[P]], ptr [[Q]])
169; CHECK-NEXT:    br i1 [[C:%.*]], label [[SKIP_HEADER_CRIT_EDGE]], label [[EXIT:%.*]]
170; CHECK:       skip.header_crit_edge:
171; CHECK-NEXT:    [[Y_PRE]] = load i32, ptr [[P]], align 4
172; CHECK-NEXT:    br label [[HEADER]]
173; CHECK:       exit:
174; CHECK-NEXT:    [[ADD:%.*]] = sub i32 [[Y]], [[X]]
175; CHECK-NEXT:    ret i32 [[ADD]]
176;
177entry:
178  %y1 = load i32, ptr %p
179  call void @use(i32 %y1)
180  br label %header
181header:
182  %x = load volatile i32, ptr %q
183  %y = load i32, ptr %p
184  call void @use(i32 %y)
185  br i1 %b, label %skip, label %header
186skip:
187  ; escaping the arguments is explicitly required since we marked
188  ; them noalias
189  call void @clobber(ptr %p, ptr %q)
190  br i1 %c, label %header, label %exit
191exit:
192  %add = sub i32 %y, %x
193  ret i32 %add
194}
195
196; This test checks that we don't optimize away instructions that are
197; simplified by SimplifyInstruction(), but are not trivially dead.
198
199define i32 @test9(ptr %V) {
200; CHECK-LABEL: @test9(
201; CHECK-NEXT:  entry:
202; CHECK-NEXT:    [[LOAD:%.*]] = call i32 undef()
203; CHECK-NEXT:    ret i32 poison
204;
205entry:
206  %load = call i32 undef()
207  ret i32 %load
208}
209
210declare void @use(i32) readonly
211declare void @clobber(ptr %p, ptr %q)
212
213!0 = !{ i32 0, i32 1 }
214