1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2 ; Test if the !invariant.load metadata is maintained by GVN.
3 ; RUN: opt -passes=gvn -S < %s | FileCheck %s
5 define i32 @test1(ptr nocapture %p, ptr nocapture %q) {
6 ; CHECK-LABEL: define i32 @test1
7 ; CHECK-SAME: (ptr nocapture [[P:%.*]], ptr nocapture [[Q:%.*]]) {
9 ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !0
10 ; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[X]] to i8
11 ; CHECK-NEXT: store i8 [[CONV]], ptr [[Q]], align 1
12 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], 1
13 ; CHECK-NEXT: ret i32 [[ADD]]
16 %x = load i32, ptr %p, align 4, !invariant.load !0
17 %conv = trunc i32 %x to i8
18 store i8 %conv, ptr %q, align 1
19 %y = load i32, ptr %p, align 4, !invariant.load !0
24 define i32 @test2(ptr nocapture %p, ptr nocapture %q) {
25 ; CHECK-LABEL: define i32 @test2
26 ; CHECK-SAME: (ptr nocapture [[P:%.*]], ptr nocapture [[Q:%.*]]) {
28 ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 4
29 ; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[X]] to i8
30 ; CHECK-NEXT: store i8 [[CONV]], ptr [[Q]], align 1
31 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], 1
32 ; CHECK-NEXT: ret i32 [[ADD]]
35 %x = load i32, ptr %p, align 4
36 %conv = trunc i32 %x to i8
37 store i8 %conv, ptr %q, align 1
38 %y = load i32, ptr %p, align 4, !invariant.load !0
43 ; With the invariant.load metadata, what would otherwise
44 ; be a case for PRE becomes a full redundancy.
45 define i32 @test3(i1 %cnd, ptr %p, ptr %q) {
46 ; CHECK-LABEL: define i32 @test3
47 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]]) {
49 ; CHECK-NEXT: br i1 [[CND]], label [[BB1:%.*]], label [[BB2:%.*]]
51 ; CHECK-NEXT: store i32 5, ptr [[Q]], align 4
52 ; CHECK-NEXT: br label [[BB2]]
54 ; CHECK-NEXT: ret i32 0
57 %v1 = load i32, ptr %p
58 br i1 %cnd, label %bb1, label %bb2
65 %v2 = load i32, ptr %p, !invariant.load !0
66 %res = sub i32 %v1, %v2
70 ; This test is here to document a case which doesn't optimize
71 ; as well as it could.
72 define i32 @test4(i1 %cnd, ptr %p, ptr %q) {
73 ; CHECK-LABEL: define i32 @test4
74 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]]) {
76 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !0
77 ; CHECK-NEXT: br i1 [[CND]], label [[BB1:%.*]], label [[BB2:%.*]]
79 ; CHECK-NEXT: store i32 5, ptr [[Q]], align 4
80 ; CHECK-NEXT: [[V2_PRE:%.*]] = load i32, ptr [[P]], align 4
81 ; CHECK-NEXT: br label [[BB2]]
83 ; CHECK-NEXT: [[V2:%.*]] = phi i32 [ [[V2_PRE]], [[BB1]] ], [ [[V1]], [[ENTRY:%.*]] ]
84 ; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
85 ; CHECK-NEXT: ret i32 [[RES]]
87 ; %v2 is redundant, but GVN currently doesn't catch that
89 %v1 = load i32, ptr %p, !invariant.load !0
90 br i1 %cnd, label %bb1, label %bb2
97 %v2 = load i32, ptr %p
98 %res = sub i32 %v1, %v2
102 ; Checks that we return the mustalias store as a def
103 ; so that it contributes to value forwarding. Note
104 ; that we could and should remove the store too.
105 define i32 @test5(i1 %cnd, ptr %p) {
106 ; CHECK-LABEL: define i32 @test5
107 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]]) {
109 ; CHECK-NEXT: store i32 5, ptr [[P]], align 4
110 ; CHECK-NEXT: ret i32 5
113 %v1 = load i32, ptr %p, !invariant.load !0
114 store i32 5, ptr %p ;; must alias store, want to exploit
115 %v2 = load i32, ptr %p, !invariant.load !0
122 ; Clobbering (mayalias) stores, even in function calls, can be ignored
123 define i32 @test6(i1 %cnd, ptr %p) {
124 ; CHECK-LABEL: define i32 @test6
125 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]]) {
127 ; CHECK-NEXT: call void @foo()
128 ; CHECK-NEXT: ret i32 0
131 %v1 = load i32, ptr %p, !invariant.load !0
133 %v2 = load i32, ptr %p, !invariant.load !0
134 %res = sub i32 %v1, %v2
138 declare noalias ptr @bar(...)
140 ; Same as previous, but a function with a noalias result (since they're handled
141 ; differently in MDA)
142 define i32 @test7(i1 %cnd, ptr %p) {
143 ; CHECK-LABEL: define i32 @test7
144 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]]) {
146 ; CHECK-NEXT: [[TMP0:%.*]] = call ptr (...) @bar(ptr [[P]])
147 ; CHECK-NEXT: ret i32 0
150 %v1 = load i32, ptr %p, !invariant.load !0
151 call ptr (...) @bar(ptr %p)
152 %v2 = load i32, ptr %p, !invariant.load !0
153 %res = sub i32 %v1, %v2
157 define i32 @test8(i1 %cnd, ptr %p) {
158 ; CHECK-LABEL: define i32 @test8
159 ; CHECK-SAME: (i1 [[CND:%.*]], ptr [[P:%.*]]) {
161 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !0
162 ; CHECK-NEXT: br i1 [[CND]], label [[TAKEN:%.*]], label [[MERGE:%.*]]
164 ; CHECK-NEXT: [[P2:%.*]] = call ptr (...) @bar(ptr [[P]])
165 ; CHECK-NEXT: [[V2_PRE:%.*]] = load i32, ptr [[P2]], align 4, !invariant.load !0
166 ; CHECK-NEXT: br label [[MERGE]]
168 ; CHECK-NEXT: [[V2:%.*]] = phi i32 [ [[V1]], [[ENTRY:%.*]] ], [ [[V2_PRE]], [[TAKEN]] ]
169 ; CHECK-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[ENTRY]] ], [ [[P2]], [[TAKEN]] ]
170 ; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
171 ; CHECK-NEXT: ret i32 [[RES]]
174 %v1 = load i32, ptr %p, !invariant.load !0
175 br i1 %cnd, label %taken, label %merge
177 %p2 = call ptr (...) @bar(ptr %p)
180 %p3 = phi ptr [%p, %entry], [%p2, %taken]
181 %v2 = load i32, ptr %p3, !invariant.load !0
182 %res = sub i32 %v1, %v2
186 define i32 @metadata_preservation(ptr nocapture %p, ptr nocapture %q) {
187 ; CHECK-LABEL: define i32 @metadata_preservation
188 ; CHECK-SAME: (ptr nocapture [[P:%.*]], ptr nocapture [[Q:%.*]]) {
190 ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !0
191 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[X]]
192 ; CHECK-NEXT: ret i32 [[ADD]]
195 %x = load i32, ptr %p, align 4, !invariant.load !0
196 %y = load i32, ptr %p, align 4
197 %add = add i32 %x, %y