• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -S -early-cse < %s | FileCheck %s
2; RUN: opt -S -basicaa -early-cse-memssa < %s | FileCheck %s
3
4declare void @clobber_and_use(i32)
5
6define void @f_0(i32* %ptr) {
7; CHECK-LABEL: @f_0(
8; CHECK:   %val0 = load i32, i32* %ptr, !invariant.load !0
9; CHECK:   call void @clobber_and_use(i32 %val0)
10; CHECK:   call void @clobber_and_use(i32 %val0)
11; CHECK:   call void @clobber_and_use(i32 %val0)
12; CHECK:   ret void
13
14  %val0 = load i32, i32* %ptr, !invariant.load !{}
15  call void @clobber_and_use(i32 %val0)
16  %val1 = load i32, i32* %ptr, !invariant.load !{}
17  call void @clobber_and_use(i32 %val1)
18  %val2 = load i32, i32* %ptr, !invariant.load !{}
19  call void @clobber_and_use(i32 %val2)
20  ret void
21}
22
23define void @f_1(i32* %ptr) {
24; We can forward invariant loads to non-invariant loads.
25
26; CHECK-LABEL: @f_1(
27; CHECK:   %val0 = load i32, i32* %ptr, !invariant.load !0
28; CHECK:   call void @clobber_and_use(i32 %val0)
29; CHECK:   call void @clobber_and_use(i32 %val0)
30
31  %val0 = load i32, i32* %ptr, !invariant.load !{}
32  call void @clobber_and_use(i32 %val0)
33  %val1 = load i32, i32* %ptr
34  call void @clobber_and_use(i32 %val1)
35  ret void
36}
37
38define void @f_2(i32* %ptr) {
39; We can forward a non-invariant load into an invariant load.
40
41; CHECK-LABEL: @f_2(
42; CHECK:   %val0 = load i32, i32* %ptr
43; CHECK:   call void @clobber_and_use(i32 %val0)
44; CHECK:   call void @clobber_and_use(i32 %val0)
45
46  %val0 = load i32, i32* %ptr
47  call void @clobber_and_use(i32 %val0)
48  %val1 = load i32, i32* %ptr, !invariant.load !{}
49  call void @clobber_and_use(i32 %val1)
50  ret void
51}
52
53define void @f_3(i1 %cond, i32* %ptr) {
54; CHECK-LABEL: @f_3(
55  %val0 = load i32, i32* %ptr, !invariant.load !{}
56  call void @clobber_and_use(i32 %val0)
57  br i1 %cond, label %left, label %right
58
59; CHECK:  %val0 = load i32, i32* %ptr, !invariant.load !0
60; CHECK: left:
61; CHECK-NEXT:  call void @clobber_and_use(i32 %val0)
62
63left:
64  %val1 = load i32, i32* %ptr
65  call void @clobber_and_use(i32 %val1)
66  ret void
67
68right:
69  ret void
70}
71
72define void @f_4(i1 %cond, i32* %ptr) {
73; Negative test -- can't forward %val0 to %va1 because that'll break
74; def-dominates-use.
75
76; CHECK-LABEL: @f_4(
77  br i1 %cond, label %left, label %merge
78
79left:
80; CHECK: left:
81; CHECK-NEXT:  %val0 = load i32, i32* %ptr, !invariant.load !
82; CHECK-NEXT:  call void @clobber_and_use(i32 %val0)
83
84  %val0 = load i32, i32* %ptr, !invariant.load !{}
85  call void @clobber_and_use(i32 %val0)
86  br label %merge
87
88merge:
89; CHECK: merge:
90; CHECK-NEXT:   %val1 = load i32, i32* %ptr
91; CHECK-NEXT:   call void @clobber_and_use(i32 %val1)
92
93  %val1 = load i32, i32* %ptr
94  call void @clobber_and_use(i32 %val1)
95  ret void
96}
97
98; By assumption, the call can't change contents of p
99; LangRef is a bit unclear about whether the store is reachable, so
100; for the moment we chose to be conservative and just assume it's valid
101; to restore the same unchanging value.
102define void @test_dse1(i32* %p) {
103; CHECK-LABEL: @test_dse1
104; CHECK-NOT: store
105  %v1 = load i32, i32* %p, !invariant.load !{}
106  call void @clobber_and_use(i32 %v1)
107  store i32 %v1, i32* %p
108  ret void
109}
110
111; By assumption, v1 must equal v2 (TODO)
112define void @test_false_negative_dse2(i32* %p, i32 %v2) {
113; CHECK-LABEL: @test_false_negative_dse2
114; CHECK: store
115  %v1 = load i32, i32* %p, !invariant.load !{}
116  call void @clobber_and_use(i32 %v1)
117  store i32 %v2, i32* %p
118  ret void
119}
120
121; If we remove the load, we still start an invariant scope since
122; it lets us remove later loads not explicitly marked invariant
123define void @test_scope_start_without_load(i32* %p) {
124; CHECK-LABEL: @test_scope_start_without_load
125; CHECK:   %v1 = load i32, i32* %p
126; CHECK:   %add = add i32 %v1, %v1
127; CHECK:   call void @clobber_and_use(i32 %add)
128; CHECK:   call void @clobber_and_use(i32 %v1)
129; CHECK:   ret void
130  %v1 = load i32, i32* %p
131  %v2 = load i32, i32* %p, !invariant.load !{}
132  %add = add i32 %v1, %v2
133  call void @clobber_and_use(i32 %add)
134  %v3 = load i32, i32* %p
135  call void @clobber_and_use(i32 %v3)
136  ret void
137}
138
139; If we already have an invariant scope, don't want to start a new one
140; with a potentially greater generation.  This hides the earlier invariant
141; load
142define void @test_scope_restart(i32* %p) {
143; CHECK-LABEL: @test_scope_restart
144; CHECK:   %v1 = load i32, i32* %p
145; CHECK:   call void @clobber_and_use(i32 %v1)
146; CHECK:   %add = add i32 %v1, %v1
147; CHECK:   call void @clobber_and_use(i32 %add)
148; CHECK:   call void @clobber_and_use(i32 %v1)
149; CHECK:   ret void
150  %v1 = load i32, i32* %p, !invariant.load !{}
151  call void @clobber_and_use(i32 %v1)
152  %v2 = load i32, i32* %p, !invariant.load !{}
153  %add = add i32 %v1, %v2
154  call void @clobber_and_use(i32 %add)
155  %v3 = load i32, i32* %p
156  call void @clobber_and_use(i32 %v3)
157  ret void
158}
159