1 ; RUN: llc -o - %s -mtriple=arm64-apple-ios -O2 | FileCheck %s
2 ; RUN: llc -o - %s -mtriple=arm64_32-apple-watchos -O2 | FileCheck %s
3 ; RUN: llc -o - %s -mtriple=arm64-linux-gnu -O2 | FileCheck %s --check-prefix=CHECK-ELF
6 ; CHECK-ELF-NOT: AdrpAdrp
7 ; CHECK-ELF-NOT: AdrpAdd
8 ; CHECK-ELF-NOT: AdrpLdrGot
10 @a = internal unnamed_addr global i32 0, align 4
11 @b = external global i32
13 ; Function Attrs: noinline nounwind ssp
14 define void @foo(i32 %t) {
16 %tmp = load i32, i32* @a, align 4
17 %add = add nsw i32 %tmp, %t
18 store i32 %add, i32* @a, align 4
22 ; Function Attrs: nounwind ssp
23 ; Testcase for <rdar://problem/15438605>, AdrpAdrp reuse is valid only when the first adrp
24 ; dominates the second.
25 ; The first adrp comes from the loading of 'a' and the second the loading of 'b'.
26 ; 'a' is loaded in if.then, 'b' in if.end4, if.then does not dominates if.end4.
29 ; CHECK-NOT: .loh AdrpAdrp
30 define i32 @test(i32 %t) {
32 %cmp = icmp sgt i32 %t, 5
33 br i1 %cmp, label %if.then, label %if.end4
35 if.then: ; preds = %entry
36 %tmp = load i32, i32* @a, align 4
37 %add = add nsw i32 %tmp, %t
38 %cmp1 = icmp sgt i32 %add, 12
39 br i1 %cmp1, label %if.then2, label %if.end4
41 if.then2: ; preds = %if.then
42 tail call void @foo(i32 %add)
43 %tmp1 = load i32, i32* @a, align 4
46 if.end4: ; preds = %if.then2, %if.then, %entry
47 %t.addr.0 = phi i32 [ %tmp1, %if.then2 ], [ %t, %if.then ], [ %t, %entry ]
48 %tmp2 = load i32, i32* @b, align 4
49 %add5 = add nsw i32 %tmp2, %t.addr.0
50 tail call void @foo(i32 %add5)
51 %tmp3 = load i32, i32* @b, align 4
52 %add6 = add nsw i32 %tmp3, %t.addr.0
56 @C = common global i32 0, align 4
58 ; Check that we catch AdrpLdrGotLdr case when we have a simple chain:
59 ; adrp -> ldrgot -> ldr.
61 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
62 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE
63 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
64 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF]
65 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
66 ; CHECK-NEXT: ldr w0, [x[[LDRGOT_REG]]]
68 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
70 %res = load i32, i32* @C, align 4
74 ; LDRSW supports loading from a literal.
75 ; Make sure we emit AdrpLdrGotLdr for those.
76 ; CHECK-LABEL: _getSExtC
77 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
78 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE
79 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
80 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF]
81 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
82 ; CHECK-NEXT: ldrsw x0, [x[[LDRGOT_REG]]]
84 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
85 define i64 @getSExtC() {
86 %res = load i32, i32* @C, align 4
87 %sextres = sext i32 %res to i64
91 ; It may not be safe to fold the literal in the load if the address is
93 ; Make sure we emit AdrpLdrGot for those.
94 ; CHECK-LABEL: _getSeveralC
95 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
96 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE
97 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
98 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF]
99 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], [x[[LDRGOT_REG]]]
100 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0
101 ; CHECK-NEXT: str [[ADD]], [x[[LDRGOT_REG]]]
103 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]]
104 define void @getSeveralC(i32 %t) {
106 %tmp = load i32, i32* @C, align 4
107 %add = add nsw i32 %tmp, %t
108 store i32 %add, i32* @C, align 4
112 ; Make sure we catch that:
113 ; adrp -> ldrgot -> str.
115 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
116 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE
117 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
118 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF]
119 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
120 ; CHECK-NEXT: str w0, [x[[LDRGOT_REG]]]
122 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
123 define void @setC(i32 %t) {
125 store i32 %t, i32* @C, align 4
129 ; Perform the same tests for internal global and a displacement
130 ; in the addressing mode.
131 ; Indeed we will get an ADD for those instead of LOADGot.
132 @InternalC = internal global i32 0, align 4
134 ; Check that we catch AdrpAddLdr case when we have a simple chain:
135 ; adrp -> add -> ldr.
136 ; CHECK-LABEL: _getInternalCPlus4
137 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
138 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
139 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]:
140 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF
141 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
142 ; CHECK-NEXT: ldr w0, {{\[}}[[ADDGOT_REG]], #16]
144 ; CHECK: .loh AdrpAddLdr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]]
145 define i32 @getInternalCPlus4() {
146 %addr = getelementptr inbounds i32, i32* @InternalC, i32 4
147 %res = load i32, i32* %addr, align 4
151 ; LDRSW supports loading from a literal.
152 ; Make sure we emit AdrpLdrGotLdr for those.
153 ; CHECK-LABEL: _getSExtInternalCPlus4
154 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
155 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
156 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]:
157 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF
158 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
159 ; CHECK-NEXT: ldrsw x0, {{\[}}[[ADDGOT_REG]], #16]
161 ; CHECK: .loh AdrpAddLdr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]]
162 define i64 @getSExtInternalCPlus4() {
163 %addr = getelementptr inbounds i32, i32* @InternalC, i32 4
164 %res = load i32, i32* %addr, align 4
165 %sextres = sext i32 %res to i64
169 ; It may not be safe to fold the literal in the load if the address is
170 ; used several times.
171 ; Make sure we emit AdrpAdd for those.
172 ; CHECK-LABEL: _getSeveralInternalCPlus4
173 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
174 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
175 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]:
176 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF
177 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], {{\[}}[[ADDGOT_REG]], #16]
178 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0
179 ; CHECK-NEXT: str [[ADD]], {{\[}}[[ADDGOT_REG]], #16]
181 ; CHECK: .loh AdrpAdd [[ADRP_LABEL]], [[ADDGOT_LABEL]]
182 define void @getSeveralInternalCPlus4(i32 %t) {
184 %addr = getelementptr inbounds i32, i32* @InternalC, i32 4
185 %tmp = load i32, i32* %addr, align 4
186 %add = add nsw i32 %tmp, %t
187 store i32 %add, i32* %addr, align 4
191 ; Make sure we catch that:
192 ; adrp -> add -> str.
193 ; CHECK-LABEL: _setInternalCPlus4
194 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
195 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
196 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]:
197 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF
198 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
199 ; CHECK-NEXT: str w0, {{\[}}[[ADDGOT_REG]], #16]
201 ; CHECK: .loh AdrpAddStr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]]
202 define void @setInternalCPlus4(i32 %t) {
204 %addr = getelementptr inbounds i32, i32* @InternalC, i32 4
205 store i32 %t, i32* %addr, align 4
209 ; Check that we catch AdrpAddLdr case when we have a simple chain:
211 ; CHECK-LABEL: _getInternalC
212 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
213 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
214 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
215 ; CHECK-NEXT: ldr w0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF]
217 ; CHECK: .loh AdrpLdr [[ADRP_LABEL]], [[LDR_LABEL]]
218 define i32 @getInternalC() {
219 %res = load i32, i32* @InternalC, align 4
223 ; LDRSW supports loading from a literal.
224 ; Make sure we emit AdrpLdrGotLdr for those.
225 ; CHECK-LABEL: _getSExtInternalC
226 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
227 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
228 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
229 ; CHECK-NEXT: ldrsw x0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF]
231 ; CHECK: .loh AdrpLdr [[ADRP_LABEL]], [[LDR_LABEL]]
232 define i64 @getSExtInternalC() {
233 %res = load i32, i32* @InternalC, align 4
234 %sextres = sext i32 %res to i64
238 ; It may not be safe to fold the literal in the load if the address is
239 ; used several times.
240 ; Make sure we do not catch anything here. We have a adrp alone,
241 ; there is not much we can do about it.
242 ; CHECK-LABEL: _getSeveralInternalC
243 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
244 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF]
245 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0
246 ; CHECK-NEXT: str [[ADD]], {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF]
248 define void @getSeveralInternalC(i32 %t) {
250 %tmp = load i32, i32* @InternalC, align 4
251 %add = add nsw i32 %tmp, %t
252 store i32 %add, i32* @InternalC, align 4
256 ; Make sure we do not catch anything when:
258 ; We cannot fold anything in the str at this point.
259 ; Indeed, strs do not support litterals.
260 ; CHECK-LABEL: _setInternalC
261 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE
262 ; CHECK-NEXT: str w0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF]
264 define void @setInternalC(i32 %t) {
266 store i32 %t, i32* @InternalC, align 4
270 ; Now check other variant of loads/stores.
272 @D = common global i8 0, align 4
274 ; LDRB does not support loading from a literal.
275 ; Make sure we emit AdrpLdrGot and not AdrpLdrGotLdr for those.
277 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
278 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE
279 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
280 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF]
281 ; CHECK-NEXT: ldrb w0, [x[[LDRGOT_REG]]]
283 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]]
285 %res = load i8, i8* @D, align 4
290 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
291 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE
292 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
293 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF]
294 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
295 ; CHECK-NEXT: strb w0, [x[[LDRGOT_REG]]]
297 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
298 define void @setD(i8 %t) {
299 store i8 %t, i8* @D, align 4
303 ; LDRSB supports loading from a literal.
304 ; Make sure we emit AdrpLdrGotLdr for those.
305 ; CHECK-LABEL: _getSExtD
306 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
307 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE
308 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
309 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF]
310 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
311 ; CHECK-NEXT: ldrsb w0, [x[[LDRGOT_REG]]]
313 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
314 define i32 @getSExtD() {
315 %res = load i8, i8* @D, align 4
316 %sextres = sext i8 %res to i32
320 ; LDRSB supports loading from a literal.
321 ; Make sure we emit AdrpLdrGotLdr for those.
322 ; CHECK-LABEL: _getSExt64D
323 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
324 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE
325 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
326 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF]
327 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
328 ; CHECK-NEXT: ldrsb x0, [x[[LDRGOT_REG]]]
330 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
331 define i64 @getSExt64D() {
332 %res = load i8, i8* @D, align 4
333 %sextres = sext i8 %res to i64
337 @E = common global i16 0, align 4
339 ; LDRH does not support loading from a literal.
340 ; Make sure we emit AdrpLdrGot and not AdrpLdrGotLdr for those.
342 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
343 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE
344 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
345 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF]
346 ; CHECK-NEXT: ldrh w0, [x[[LDRGOT_REG]]]
348 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]]
350 %res = load i16, i16* @E, align 4
354 ; LDRSH supports loading from a literal.
355 ; Make sure we emit AdrpLdrGotLdr for those.
356 ; CHECK-LABEL: _getSExtE
357 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
358 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE
359 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
360 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF]
361 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
362 ; CHECK-NEXT: ldrsh w0, [x[[LDRGOT_REG]]]
364 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
365 define i32 @getSExtE() {
366 %res = load i16, i16* @E, align 4
367 %sextres = sext i16 %res to i32
372 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
373 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE
374 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
375 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF]
376 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
377 ; CHECK-NEXT: strh w0, [x[[LDRGOT_REG]]]
379 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
380 define void @setE(i16 %t) {
381 store i16 %t, i16* @E, align 4
385 ; LDRSH supports loading from a literal.
386 ; Make sure we emit AdrpLdrGotLdr for those.
387 ; CHECK-LABEL: _getSExt64E
388 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
389 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE
390 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
391 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF]
392 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
393 ; CHECK-NEXT: ldrsh x0, [x[[LDRGOT_REG]]]
395 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
396 define i64 @getSExt64E() {
397 %res = load i16, i16* @E, align 4
398 %sextres = sext i16 %res to i64
402 @F = common global i64 0, align 4
404 ; LDR supports loading from a literal.
405 ; Make sure we emit AdrpLdrGotLdr for those.
407 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
408 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _F@GOTPAGE
409 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
410 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _F@GOTPAGEOFF]
411 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
412 ; CHECK-NEXT: ldr x0, [x[[LDRGOT_REG]]]
414 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
416 %res = load i64, i64* @F, align 4
421 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
422 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _F@GOTPAGE
423 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
424 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _F@GOTPAGEOFF]
425 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
426 ; CHECK-NEXT: str x0, [x[[LDRGOT_REG]]]
428 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
429 define void @setF(i64 %t) {
430 store i64 %t, i64* @F, align 4
434 @G = common global float 0.0, align 4
436 ; LDR float supports loading from a literal.
437 ; Make sure we emit AdrpLdrGotLdr for those.
439 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
440 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _G@GOTPAGE
441 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
442 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _G@GOTPAGEOFF]
443 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
444 ; CHECK-NEXT: ldr s0, [x[[LDRGOT_REG]]]
446 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
447 define float @getG() {
448 %res = load float, float* @G, align 4
453 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
454 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _G@GOTPAGE
455 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
456 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _G@GOTPAGEOFF]
457 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
458 ; CHECK-NEXT: str s0, [x[[LDRGOT_REG]]]
460 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
461 define void @setG(float %t) {
462 store float %t, float* @G, align 4
466 @H = common global half 0.0, align 4
468 ; LDR half supports loading from a literal.
469 ; Make sure we emit AdrpLdrGotLdr for those.
471 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
472 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _H@GOTPAGE
473 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
474 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _H@GOTPAGEOFF]
475 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
476 ; CHECK-NEXT: ldr h0, [x[[LDRGOT_REG]]]
478 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
479 define half @getH() {
480 %res = load half, half* @H, align 4
485 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
486 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _H@GOTPAGE
487 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
488 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _H@GOTPAGEOFF]
489 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
490 ; CHECK-NEXT: str h0, [x[[LDRGOT_REG]]]
492 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
493 define void @setH(half %t) {
494 store half %t, half* @H, align 4
498 @I = common global double 0.0, align 4
500 ; LDR double supports loading from a literal.
501 ; Make sure we emit AdrpLdrGotLdr for those.
503 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
504 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _I@GOTPAGE
505 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
506 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _I@GOTPAGEOFF]
507 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
508 ; CHECK-NEXT: ldr d0, [x[[LDRGOT_REG]]]
510 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
511 define double @getI() {
512 %res = load double, double* @I, align 4
517 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
518 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _I@GOTPAGE
519 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
520 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _I@GOTPAGEOFF]
521 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
522 ; CHECK-NEXT: str d0, [x[[LDRGOT_REG]]]
524 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
525 define void @setI(double %t) {
526 store double %t, double* @I, align 4
530 @J = common global <2 x i32> <i32 0, i32 0>, align 4
532 ; LDR 64-bit vector supports loading from a literal.
533 ; Make sure we emit AdrpLdrGotLdr for those.
535 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
536 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _J@GOTPAGE
537 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
538 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _J@GOTPAGEOFF]
539 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
540 ; CHECK-NEXT: ldr d0, [x[[LDRGOT_REG]]]
542 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
543 define <2 x i32> @getJ() {
544 %res = load <2 x i32>, <2 x i32>* @J, align 4
549 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
550 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _J@GOTPAGE
551 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
552 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _J@GOTPAGEOFF]
553 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
554 ; CHECK-NEXT: str d0, [x[[LDRGOT_REG]]]
556 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
557 define void @setJ(<2 x i32> %t) {
558 store <2 x i32> %t, <2 x i32>* @J, align 4
562 @K = common global <4 x i32> <i32 0, i32 0, i32 0, i32 0>, align 4
564 ; LDR 128-bit vector supports loading from a literal.
565 ; Make sure we emit AdrpLdrGotLdr for those.
567 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
568 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _K@GOTPAGE
569 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
570 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _K@GOTPAGEOFF]
571 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
572 ; CHECK-NEXT: ldr q0, [x[[LDRGOT_REG]]]
574 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
575 define <4 x i32> @getK() {
576 %res = load <4 x i32>, <4 x i32>* @K, align 4
581 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
582 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _K@GOTPAGE
583 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
584 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _K@GOTPAGEOFF]
585 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]:
586 ; CHECK-NEXT: str q0, [x[[LDRGOT_REG]]]
588 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]]
589 define void @setK(<4 x i32> %t) {
590 store <4 x i32> %t, <4 x i32>* @K, align 4
594 @L = common global <1 x i8> <i8 0>, align 4
596 ; LDR 8-bit vector supports loading from a literal.
597 ; Make sure we emit AdrpLdrGotLdr for those.
599 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
600 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _L@GOTPAGE
601 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
602 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _L@GOTPAGEOFF]
603 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]:
604 ; CHECK-NEXT: ldr b0, [x[[LDRGOT_REG]]]
606 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]]
607 define <1 x i8> @getL() {
608 %res = load <1 x i8>, <1 x i8>* @L, align 4
613 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]:
614 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _L@GOTPAGE
615 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]:
616 ; CHECK-NEXT: ldr {{[xw]}}[[LDRGOT_REG:[0-9]+]], {{\[}}[[ADRP_REG]], _L@GOTPAGEOFF]
618 ; Ultimately we should generate str b0, but right now, we match the vector
619 ; variant which does not allow to fold the immediate into the store.
620 ; CHECK-NEXT: st1.b { v0 }[0], [x[[LDRGOT_REG]]]
622 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]]
623 define void @setL(<1 x i8> %t) {
624 store <1 x i8> %t, <1 x i8>* @L, align 4
628 ; Make sure we do not assert when we do not track
629 ; all the aliases of a tuple register.
630 ; Indeed the tuple register can be tracked because of
631 ; one of its element, but the other elements of the tuple
632 ; do not need to be tracked and we used to assert on that.
633 ; Note: The test case is fragile in the sense that we need
634 ; a tuple register to appear in the lowering. Thus, the target
635 ; cpu is required to have the problem reproduced.
636 ; CHECK-LABEL: _uninterestingSub
637 ; CHECK: [[LOH_LABEL0:Lloh[0-9]+]]:
638 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], [[CONSTPOOL:lCPI[0-9]+_[0-9]+]]@PAGE
639 ; CHECK: [[LOH_LABEL1:Lloh[0-9]+]]:
640 ; CHECK: ldr q[[IDX:[0-9]+]], {{\[}}[[ADRP_REG]], [[CONSTPOOL]]@PAGEOFF]
641 ; The tuple comes from the next instruction.
642 ; CHECK: ext.16b v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}}, #1
644 ; CHECK: .loh AdrpLdr [[LOH_LABEL0]], [[LOH_LABEL1]]
645 define void @uninterestingSub(i8* nocapture %row) #0 {
646 %tmp = bitcast i8* %row to <16 x i8>*
647 %tmp1 = load <16 x i8>, <16 x i8>* %tmp, align 16
648 %vext43 = shufflevector <16 x i8> <i8 undef, i8 16, i8 15, i8 14, i8 13, i8 12, i8 11, i8 10, i8 9, i8 8, i8 7, i8 6, i8 5, i8 4, i8 3, i8 2>, <16 x i8> %tmp1, <16 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>
649 %add.i.414 = add <16 x i8> zeroinitializer, %vext43
650 store <16 x i8> %add.i.414, <16 x i8>* %tmp, align 16
651 %add.ptr51 = getelementptr inbounds i8, i8* %row, i64 16
652 %tmp2 = bitcast i8* %add.ptr51 to <16 x i8>*
653 %tmp3 = load <16 x i8>, <16 x i8>* %tmp2, align 16
654 %tmp4 = bitcast i8* undef to <16 x i8>*
655 %tmp5 = load <16 x i8>, <16 x i8>* %tmp4, align 16
656 %vext157 = shufflevector <16 x i8> %tmp3, <16 x i8> %tmp5, <16 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>
657 %add.i.402 = add <16 x i8> zeroinitializer, %vext157
658 store <16 x i8> %add.i.402, <16 x i8>* %tmp4, align 16
662 @.str.89 = external unnamed_addr constant [12 x i8], align 1
663 @.str.90 = external unnamed_addr constant [5 x i8], align 1
664 ; CHECK-LABEL: test_r274582
665 define void @test_r274582(double %x) {
667 br i1 undef, label %if.then.i, label %if.end.i
671 ; CHECK: .loh AdrpLdrGot
672 ; CHECK: .loh AdrpLdrGot
673 ; CHECK: .loh AdrpAdrp
674 ; CHECK: .loh AdrpLdr
675 %mul = fmul double %x, 1.000000e-06
676 %add = fadd double %mul, %mul
677 %sub = fsub double %add, %add
678 call void (i8*, ...) @callee(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.89, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.90, i64 0, i64 0), double %sub)
681 declare void @callee(i8* nocapture readonly, ...)
683 attributes #0 = { "target-cpu"="cyclone" }