• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; Tests that check our handling of volatile instructions encountered
2; when scanning for dependencies
3; RUN: opt -basicaa -gvn -S < %s | FileCheck %s
4
5; Check that we can bypass a volatile load when searching
6; for dependencies of a non-volatile load
7define i32 @test1(i32* nocapture %p, i32* nocapture %q) {
8; CHECK-LABEL: test1
9; CHECK:      %0 = load volatile i32, i32* %q
10; CHECK-NEXT: ret i32 0
11entry:
12  %x = load i32, i32* %p
13  load volatile i32, i32* %q
14  %y = load i32, i32* %p
15  %add = sub i32 %y, %x
16  ret i32 %add
17}
18
19; We can not value forward if the query instruction is
20; volatile, this would be (in effect) removing the volatile load
21define i32 @test2(i32* nocapture %p, i32* nocapture %q) {
22; CHECK-LABEL: test2
23; CHECK:      %x = load i32, i32* %p
24; CHECK-NEXT: %y = load volatile i32, i32* %p
25; CHECK-NEXT: %add = sub i32 %y, %x
26entry:
27  %x = load i32, i32* %p
28  %y = load volatile i32, i32* %p
29  %add = sub i32 %y, %x
30  ret i32 %add
31}
32
33; If the query instruction is itself volatile, we *cannot*
34; reorder it even if p and q are noalias
35define i32 @test3(i32* noalias nocapture %p, i32* noalias nocapture %q) {
36; CHECK-LABEL: test3
37; CHECK:      %x = load i32, i32* %p
38; CHECK-NEXT: %0 = load volatile i32, i32* %q
39; CHECK-NEXT: %y = load volatile i32, i32* %p
40entry:
41  %x = load i32, i32* %p
42  load volatile i32, i32* %q
43  %y = load volatile i32, i32* %p
44  %add = sub i32 %y, %x
45  ret i32 %add
46}
47
48; If an encountered instruction is both volatile and ordered,
49; we need to use the strictest ordering of either.  In this
50; case, the ordering prevents forwarding.
51define i32 @test4(i32* noalias nocapture %p, i32* noalias nocapture %q) {
52; CHECK-LABEL: test4
53; CHECK:      %x = load i32, i32* %p
54; CHECK-NEXT: %0 = load atomic volatile i32, i32* %q seq_cst
55; CHECK-NEXT: %y = load atomic i32, i32* %p seq_cst
56entry:
57  %x = load i32, i32* %p
58  load atomic volatile i32, i32* %q seq_cst, align 4
59  %y = load atomic i32, i32* %p seq_cst, align 4
60  %add = sub i32 %y, %x
61  ret i32 %add
62}
63
64; Value forwarding from a volatile load is perfectly legal
65define i32 @test5(i32* nocapture %p, i32* nocapture %q) {
66; CHECK-LABEL: test5
67; CHECK:      %x = load volatile i32, i32* %p
68; CHECK-NEXT: ret i32 0
69entry:
70  %x = load volatile i32, i32* %p
71  %y = load i32, i32* %p
72  %add = sub i32 %y, %x
73  ret i32 %add
74}
75
76; Does cross block redundancy elimination work with volatiles?
77define i32 @test6(i32* noalias nocapture %p, i32* noalias nocapture %q) {
78; CHECK-LABEL: test6
79; CHECK:      %y1 = load i32, i32* %p
80; CHECK-LABEL: header
81; CHECK:      %x = load volatile i32, i32* %q
82; CHECK-NEXT: %add = sub i32 %y1, %x
83entry:
84  %y1 = load i32, i32* %p
85  call void @use(i32 %y1)
86  br label %header
87header:
88  %x = load volatile i32, i32* %q
89  %y = load i32, i32* %p
90  %add = sub i32 %y, %x
91  %cnd = icmp eq i32 %add, 0
92  br i1 %cnd, label %exit, label %header
93exit:
94  ret i32 %add
95}
96
97; Does cross block PRE work with volatiles?
98define i32 @test7(i1 %c, i32* noalias nocapture %p, i32* noalias nocapture %q) {
99; CHECK-LABEL: test7
100; CHECK-LABEL: entry.header_crit_edge:
101; CHECK:       %y.pre = load i32, i32* %p
102; CHECK-LABEL: skip:
103; CHECK:       %y1 = load i32, i32* %p
104; CHECK-LABEL: header:
105; CHECK:      %y = phi i32
106; CHECK-NEXT: %x = load volatile i32, i32* %q
107; CHECK-NEXT: %add = sub i32 %y, %x
108entry:
109  br i1 %c, label %header, label %skip
110skip:
111  %y1 = load i32, i32* %p
112  call void @use(i32 %y1)
113  br label %header
114header:
115  %x = load volatile i32, i32* %q
116  %y = load i32, i32* %p
117  %add = sub i32 %y, %x
118  %cnd = icmp eq i32 %add, 0
119  br i1 %cnd, label %exit, label %header
120exit:
121  ret i32 %add
122}
123
124; Another volatile PRE case - two paths through a loop
125; load in preheader, one path read only, one not
126define i32 @test8(i1 %b, i1 %c, i32* noalias %p, i32* noalias %q) {
127; CHECK-LABEL: test8
128; CHECK-LABEL: entry
129; CHECK:       %y1 = load i32, i32* %p
130; CHECK-LABEL: header:
131; CHECK:      %y = phi i32
132; CHECK-NEXT: %x = load volatile i32, i32* %q
133; CHECK-NOT:  load
134; CHECK-LABEL: skip.header_crit_edge:
135; CHECK:       %y.pre = load i32, i32* %p
136entry:
137  %y1 = load i32, i32* %p
138  call void @use(i32 %y1)
139  br label %header
140header:
141  %x = load volatile i32, i32* %q
142  %y = load i32, i32* %p
143  call void @use(i32 %y)
144  br i1 %b, label %skip, label %header
145skip:
146  ; escaping the arguments is explicitly required since we marked
147  ; them noalias
148  call void @clobber(i32* %p, i32* %q)
149  br i1 %c, label %header, label %exit
150exit:
151  %add = sub i32 %y, %x
152  ret i32 %add
153}
154
155define i32 @test9(i32* %V) {
156entry:
157  %load = load volatile i32, i32* %V, !range !0
158  ret i32 %load
159}
160; CHECK-LABEL: test9
161; CHECK: load volatile
162; CHECK: ret i32 0
163
164declare void @use(i32) readonly
165declare void @clobber(i32* %p, i32* %q)
166
167!0 = !{ i32 0, i32 1 }
168