1 ; RUN: llc -mtriple=arm64-apple-ios -O2 -aarch64-collect-loh -aarch64-collect-loh-bb-only=false < %s -o - | FileCheck %s 2 ; RUN: llc -mtriple=arm64-linux-gnu -O2 -aarch64-collect-loh -aarch64-collect-loh-bb-only=false < %s -o - | FileCheck %s --check-prefix=CHECK-ELF 3 4 ; CHECK-ELF-NOT: .loh 5 ; CHECK-ELF-NOT: AdrpAdrp 6 ; CHECK-ELF-NOT: AdrpAdd 7 ; CHECK-ELF-NOT: AdrpLdrGot 8 9 @a = internal unnamed_addr global i32 0, align 4 10 @b = external global i32 11 12 ; Function Attrs: noinline nounwind ssp 13 define void @foo(i32 %t) { 14 entry: 15 %tmp = load i32, i32* @a, align 4 16 %add = add nsw i32 %tmp, %t 17 store i32 %add, i32* @a, align 4 18 ret void 19 } 20 21 ; Function Attrs: nounwind ssp 22 ; Testcase for <rdar://problem/15438605>, AdrpAdrp reuse is valid only when the first adrp 23 ; dominates the second. 24 ; The first adrp comes from the loading of 'a' and the second the loading of 'b'. 25 ; 'a' is loaded in if.then, 'b' in if.end4, if.then does not dominates if.end4. 26 ; CHECK-LABEL: _test 27 ; CHECK: ret 28 ; CHECK-NOT: .loh AdrpAdrp 29 define i32 @test(i32 %t) { 30 entry: 31 %cmp = icmp sgt i32 %t, 5 32 br i1 %cmp, label %if.then, label %if.end4 33 34 if.then: ; preds = %entry 35 %tmp = load i32, i32* @a, align 4 36 %add = add nsw i32 %tmp, %t 37 %cmp1 = icmp sgt i32 %add, 12 38 br i1 %cmp1, label %if.then2, label %if.end4 39 40 if.then2: ; preds = %if.then 41 tail call void @foo(i32 %add) 42 %tmp1 = load i32, i32* @a, align 4 43 br label %if.end4 44 45 if.end4: ; preds = %if.then2, %if.then, %entry 46 %t.addr.0 = phi i32 [ %tmp1, %if.then2 ], [ %t, %if.then ], [ %t, %entry ] 47 %tmp2 = load i32, i32* @b, align 4 48 %add5 = add nsw i32 %tmp2, %t.addr.0 49 tail call void @foo(i32 %add5) 50 %tmp3 = load i32, i32* @b, align 4 51 %add6 = add nsw i32 %tmp3, %t.addr.0 52 ret i32 %add6 53 } 54 55 @C = common global i32 0, align 4 56 57 ; Check that we catch AdrpLdrGotLdr case when we have a simple chain: 58 ; adrp -> ldrgot -> ldr. 59 ; CHECK-LABEL: _getC 60 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 61 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE 62 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 63 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF] 64 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 65 ; CHECK-NEXT: ldr w0, {{\[}}[[LDRGOT_REG]]] 66 ; CHECK-NEXT: ret 67 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 68 define i32 @getC() { 69 %res = load i32, i32* @C, align 4 70 ret i32 %res 71 } 72 73 ; LDRSW supports loading from a literal. 74 ; Make sure we emit AdrpLdrGotLdr for those. 75 ; CHECK-LABEL: _getSExtC 76 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 77 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE 78 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 79 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF] 80 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 81 ; CHECK-NEXT: ldrsw x0, {{\[}}[[LDRGOT_REG]]] 82 ; CHECK-NEXT: ret 83 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 84 define i64 @getSExtC() { 85 %res = load i32, i32* @C, align 4 86 %sextres = sext i32 %res to i64 87 ret i64 %sextres 88 } 89 90 ; It may not be safe to fold the literal in the load if the address is 91 ; used several times. 92 ; Make sure we emit AdrpLdrGot for those. 93 ; CHECK-LABEL: _getSeveralC 94 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 95 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE 96 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 97 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF] 98 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], {{\[}}[[LDRGOT_REG]]] 99 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0 100 ; CHECK-NEXT: str [[ADD]], {{\[}}[[LDRGOT_REG]]] 101 ; CHECK-NEXT: ret 102 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]] 103 define void @getSeveralC(i32 %t) { 104 entry: 105 %tmp = load i32, i32* @C, align 4 106 %add = add nsw i32 %tmp, %t 107 store i32 %add, i32* @C, align 4 108 ret void 109 } 110 111 ; Make sure we catch that: 112 ; adrp -> ldrgot -> str. 113 ; CHECK-LABEL: _setC 114 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 115 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _C@GOTPAGE 116 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 117 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _C@GOTPAGEOFF] 118 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 119 ; CHECK-NEXT: str w0, {{\[}}[[LDRGOT_REG]]] 120 ; CHECK-NEXT: ret 121 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 122 define void @setC(i32 %t) { 123 entry: 124 store i32 %t, i32* @C, align 4 125 ret void 126 } 127 128 ; Perform the same tests for internal global and a displacement 129 ; in the addressing mode. 130 ; Indeed we will get an ADD for those instead of LOADGot. 131 @InternalC = internal global i32 0, align 4 132 133 ; Check that we catch AdrpAddLdr case when we have a simple chain: 134 ; adrp -> add -> ldr. 135 ; CHECK-LABEL: _getInternalCPlus4 136 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 137 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 138 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]: 139 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF 140 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 141 ; CHECK-NEXT: ldr w0, {{\[}}[[ADDGOT_REG]], #16] 142 ; CHECK-NEXT: ret 143 ; CHECK: .loh AdrpAddLdr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]] 144 define i32 @getInternalCPlus4() { 145 %addr = getelementptr i32, i32* @InternalC, i32 4 146 %res = load i32, i32* %addr, align 4 147 ret i32 %res 148 } 149 150 ; LDRSW supports loading from a literal. 151 ; Make sure we emit AdrpLdrGotLdr for those. 152 ; CHECK-LABEL: _getSExtInternalCPlus4 153 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 154 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 155 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]: 156 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF 157 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 158 ; CHECK-NEXT: ldrsw x0, {{\[}}[[ADDGOT_REG]], #16] 159 ; CHECK-NEXT: ret 160 ; CHECK: .loh AdrpAddLdr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]] 161 define i64 @getSExtInternalCPlus4() { 162 %addr = getelementptr i32, i32* @InternalC, i32 4 163 %res = load i32, i32* %addr, align 4 164 %sextres = sext i32 %res to i64 165 ret i64 %sextres 166 } 167 168 ; It may not be safe to fold the literal in the load if the address is 169 ; used several times. 170 ; Make sure we emit AdrpAdd for those. 171 ; CHECK-LABEL: _getSeveralInternalCPlus4 172 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 173 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 174 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]: 175 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF 176 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], {{\[}}[[ADDGOT_REG]], #16] 177 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0 178 ; CHECK-NEXT: str [[ADD]], {{\[}}[[ADDGOT_REG]], #16] 179 ; CHECK-NEXT: ret 180 ; CHECK: .loh AdrpAdd [[ADRP_LABEL]], [[ADDGOT_LABEL]] 181 define void @getSeveralInternalCPlus4(i32 %t) { 182 entry: 183 %addr = getelementptr i32, i32* @InternalC, i32 4 184 %tmp = load i32, i32* %addr, align 4 185 %add = add nsw i32 %tmp, %t 186 store i32 %add, i32* %addr, align 4 187 ret void 188 } 189 190 ; Make sure we catch that: 191 ; adrp -> add -> str. 192 ; CHECK-LABEL: _setInternalCPlus4 193 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 194 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 195 ; CHECK-NEXT: [[ADDGOT_LABEL:Lloh[0-9]+]]: 196 ; CHECK-NEXT: add [[ADDGOT_REG:x[0-9]+]], [[ADRP_REG]], _InternalC@PAGEOFF 197 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 198 ; CHECK-NEXT: str w0, {{\[}}[[ADDGOT_REG]], #16] 199 ; CHECK-NEXT: ret 200 ; CHECK: .loh AdrpAddStr [[ADRP_LABEL]], [[ADDGOT_LABEL]], [[LDR_LABEL]] 201 define void @setInternalCPlus4(i32 %t) { 202 entry: 203 %addr = getelementptr i32, i32* @InternalC, i32 4 204 store i32 %t, i32* %addr, align 4 205 ret void 206 } 207 208 ; Check that we catch AdrpAddLdr case when we have a simple chain: 209 ; adrp -> ldr. 210 ; CHECK-LABEL: _getInternalC 211 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 212 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 213 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 214 ; CHECK-NEXT: ldr w0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF] 215 ; CHECK-NEXT: ret 216 ; CHECK: .loh AdrpLdr [[ADRP_LABEL]], [[LDR_LABEL]] 217 define i32 @getInternalC() { 218 %res = load i32, i32* @InternalC, align 4 219 ret i32 %res 220 } 221 222 ; LDRSW supports loading from a literal. 223 ; Make sure we emit AdrpLdrGotLdr for those. 224 ; CHECK-LABEL: _getSExtInternalC 225 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 226 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 227 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 228 ; CHECK-NEXT: ldrsw x0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF] 229 ; CHECK-NEXT: ret 230 ; CHECK: .loh AdrpLdr [[ADRP_LABEL]], [[LDR_LABEL]] 231 define i64 @getSExtInternalC() { 232 %res = load i32, i32* @InternalC, align 4 233 %sextres = sext i32 %res to i64 234 ret i64 %sextres 235 } 236 237 ; It may not be safe to fold the literal in the load if the address is 238 ; used several times. 239 ; Make sure we do not catch anything here. We have a adrp alone, 240 ; there is not much we can do about it. 241 ; CHECK-LABEL: _getSeveralInternalC 242 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 243 ; CHECK-NEXT: ldr [[LOAD:w[0-9]+]], {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF] 244 ; CHECK-NEXT: add [[ADD:w[0-9]+]], [[LOAD]], w0 245 ; CHECK-NEXT: str [[ADD]], {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF] 246 ; CHECK-NEXT: ret 247 define void @getSeveralInternalC(i32 %t) { 248 entry: 249 %tmp = load i32, i32* @InternalC, align 4 250 %add = add nsw i32 %tmp, %t 251 store i32 %add, i32* @InternalC, align 4 252 ret void 253 } 254 255 ; Make sure we do not catch anything when: 256 ; adrp -> str. 257 ; We cannot fold anything in the str at this point. 258 ; Indeed, strs do not support litterals. 259 ; CHECK-LABEL: _setInternalC 260 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], _InternalC@PAGE 261 ; CHECK-NEXT: str w0, {{\[}}[[ADRP_REG]], _InternalC@PAGEOFF] 262 ; CHECK-NEXT: ret 263 define void @setInternalC(i32 %t) { 264 entry: 265 store i32 %t, i32* @InternalC, align 4 266 ret void 267 } 268 269 ; Now check other variant of loads/stores. 270 271 @D = common global i8 0, align 4 272 273 ; LDRB does not support loading from a literal. 274 ; Make sure we emit AdrpLdrGot and not AdrpLdrGotLdr for those. 275 ; CHECK-LABEL: _getD 276 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 277 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE 278 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 279 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF] 280 ; CHECK-NEXT: ldrb w0, {{\[}}[[LDRGOT_REG]]] 281 ; CHECK-NEXT: ret 282 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]] 283 define i8 @getD() { 284 %res = load i8, i8* @D, align 4 285 ret i8 %res 286 } 287 288 ; CHECK-LABEL: _setD 289 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 290 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE 291 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 292 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF] 293 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 294 ; CHECK-NEXT: strb w0, {{\[}}[[LDRGOT_REG]]] 295 ; CHECK-NEXT: ret 296 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 297 define void @setD(i8 %t) { 298 store i8 %t, i8* @D, align 4 299 ret void 300 } 301 302 ; LDRSB supports loading from a literal. 303 ; Make sure we emit AdrpLdrGotLdr for those. 304 ; CHECK-LABEL: _getSExtD 305 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 306 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE 307 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 308 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF] 309 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 310 ; CHECK-NEXT: ldrsb w0, {{\[}}[[LDRGOT_REG]]] 311 ; CHECK-NEXT: ret 312 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 313 define i32 @getSExtD() { 314 %res = load i8, i8* @D, align 4 315 %sextres = sext i8 %res to i32 316 ret i32 %sextres 317 } 318 319 ; LDRSB supports loading from a literal. 320 ; Make sure we emit AdrpLdrGotLdr for those. 321 ; CHECK-LABEL: _getSExt64D 322 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 323 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _D@GOTPAGE 324 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 325 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _D@GOTPAGEOFF] 326 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 327 ; CHECK-NEXT: ldrsb x0, {{\[}}[[LDRGOT_REG]]] 328 ; CHECK-NEXT: ret 329 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 330 define i64 @getSExt64D() { 331 %res = load i8, i8* @D, align 4 332 %sextres = sext i8 %res to i64 333 ret i64 %sextres 334 } 335 336 @E = common global i16 0, align 4 337 338 ; LDRH does not support loading from a literal. 339 ; Make sure we emit AdrpLdrGot and not AdrpLdrGotLdr for those. 340 ; CHECK-LABEL: _getE 341 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 342 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE 343 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 344 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF] 345 ; CHECK-NEXT: ldrh w0, {{\[}}[[LDRGOT_REG]]] 346 ; CHECK-NEXT: ret 347 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]] 348 define i16 @getE() { 349 %res = load i16, i16* @E, align 4 350 ret i16 %res 351 } 352 353 ; LDRSH supports loading from a literal. 354 ; Make sure we emit AdrpLdrGotLdr for those. 355 ; CHECK-LABEL: _getSExtE 356 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 357 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE 358 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 359 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF] 360 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 361 ; CHECK-NEXT: ldrsh w0, {{\[}}[[LDRGOT_REG]]] 362 ; CHECK-NEXT: ret 363 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 364 define i32 @getSExtE() { 365 %res = load i16, i16* @E, align 4 366 %sextres = sext i16 %res to i32 367 ret i32 %sextres 368 } 369 370 ; CHECK-LABEL: _setE 371 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 372 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE 373 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 374 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF] 375 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 376 ; CHECK-NEXT: strh w0, {{\[}}[[LDRGOT_REG]]] 377 ; CHECK-NEXT: ret 378 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 379 define void @setE(i16 %t) { 380 store i16 %t, i16* @E, align 4 381 ret void 382 } 383 384 ; LDRSH supports loading from a literal. 385 ; Make sure we emit AdrpLdrGotLdr for those. 386 ; CHECK-LABEL: _getSExt64E 387 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 388 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _E@GOTPAGE 389 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 390 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _E@GOTPAGEOFF] 391 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 392 ; CHECK-NEXT: ldrsh x0, {{\[}}[[LDRGOT_REG]]] 393 ; CHECK-NEXT: ret 394 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 395 define i64 @getSExt64E() { 396 %res = load i16, i16* @E, align 4 397 %sextres = sext i16 %res to i64 398 ret i64 %sextres 399 } 400 401 @F = common global i64 0, align 4 402 403 ; LDR supports loading from a literal. 404 ; Make sure we emit AdrpLdrGotLdr for those. 405 ; CHECK-LABEL: _getF 406 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 407 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _F@GOTPAGE 408 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 409 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _F@GOTPAGEOFF] 410 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 411 ; CHECK-NEXT: ldr x0, {{\[}}[[LDRGOT_REG]]] 412 ; CHECK-NEXT: ret 413 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 414 define i64 @getF() { 415 %res = load i64, i64* @F, align 4 416 ret i64 %res 417 } 418 419 ; CHECK-LABEL: _setF 420 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 421 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _F@GOTPAGE 422 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 423 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _F@GOTPAGEOFF] 424 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 425 ; CHECK-NEXT: str x0, {{\[}}[[LDRGOT_REG]]] 426 ; CHECK-NEXT: ret 427 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 428 define void @setF(i64 %t) { 429 store i64 %t, i64* @F, align 4 430 ret void 431 } 432 433 @G = common global float 0.0, align 4 434 435 ; LDR float supports loading from a literal. 436 ; Make sure we emit AdrpLdrGotLdr for those. 437 ; CHECK-LABEL: _getG 438 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 439 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _G@GOTPAGE 440 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 441 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _G@GOTPAGEOFF] 442 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 443 ; CHECK-NEXT: ldr s0, {{\[}}[[LDRGOT_REG]]] 444 ; CHECK-NEXT: ret 445 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 446 define float @getG() { 447 %res = load float, float* @G, align 4 448 ret float %res 449 } 450 451 ; CHECK-LABEL: _setG 452 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 453 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _G@GOTPAGE 454 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 455 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _G@GOTPAGEOFF] 456 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 457 ; CHECK-NEXT: str s0, {{\[}}[[LDRGOT_REG]]] 458 ; CHECK-NEXT: ret 459 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 460 define void @setG(float %t) { 461 store float %t, float* @G, align 4 462 ret void 463 } 464 465 @H = common global half 0.0, align 4 466 467 ; LDR half supports loading from a literal. 468 ; Make sure we emit AdrpLdrGotLdr for those. 469 ; CHECK-LABEL: _getH 470 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 471 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _H@GOTPAGE 472 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 473 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _H@GOTPAGEOFF] 474 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 475 ; CHECK-NEXT: ldr h0, {{\[}}[[LDRGOT_REG]]] 476 ; CHECK-NEXT: ret 477 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 478 define half @getH() { 479 %res = load half, half* @H, align 4 480 ret half %res 481 } 482 483 ; CHECK-LABEL: _setH 484 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 485 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _H@GOTPAGE 486 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 487 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _H@GOTPAGEOFF] 488 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 489 ; CHECK-NEXT: str h0, {{\[}}[[LDRGOT_REG]]] 490 ; CHECK-NEXT: ret 491 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 492 define void @setH(half %t) { 493 store half %t, half* @H, align 4 494 ret void 495 } 496 497 @I = common global double 0.0, align 4 498 499 ; LDR double supports loading from a literal. 500 ; Make sure we emit AdrpLdrGotLdr for those. 501 ; CHECK-LABEL: _getI 502 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 503 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _I@GOTPAGE 504 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 505 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _I@GOTPAGEOFF] 506 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 507 ; CHECK-NEXT: ldr d0, {{\[}}[[LDRGOT_REG]]] 508 ; CHECK-NEXT: ret 509 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 510 define double @getI() { 511 %res = load double, double* @I, align 4 512 ret double %res 513 } 514 515 ; CHECK-LABEL: _setI 516 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 517 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _I@GOTPAGE 518 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 519 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _I@GOTPAGEOFF] 520 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 521 ; CHECK-NEXT: str d0, {{\[}}[[LDRGOT_REG]]] 522 ; CHECK-NEXT: ret 523 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 524 define void @setI(double %t) { 525 store double %t, double* @I, align 4 526 ret void 527 } 528 529 @J = common global <2 x i32> <i32 0, i32 0>, align 4 530 531 ; LDR 64-bit vector supports loading from a literal. 532 ; Make sure we emit AdrpLdrGotLdr for those. 533 ; CHECK-LABEL: _getJ 534 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 535 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _J@GOTPAGE 536 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 537 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _J@GOTPAGEOFF] 538 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 539 ; CHECK-NEXT: ldr d0, {{\[}}[[LDRGOT_REG]]] 540 ; CHECK-NEXT: ret 541 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 542 define <2 x i32> @getJ() { 543 %res = load <2 x i32>, <2 x i32>* @J, align 4 544 ret <2 x i32> %res 545 } 546 547 ; CHECK-LABEL: _setJ 548 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 549 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _J@GOTPAGE 550 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 551 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _J@GOTPAGEOFF] 552 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 553 ; CHECK-NEXT: str d0, {{\[}}[[LDRGOT_REG]]] 554 ; CHECK-NEXT: ret 555 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 556 define void @setJ(<2 x i32> %t) { 557 store <2 x i32> %t, <2 x i32>* @J, align 4 558 ret void 559 } 560 561 @K = common global <4 x i32> <i32 0, i32 0, i32 0, i32 0>, align 4 562 563 ; LDR 128-bit vector supports loading from a literal. 564 ; Make sure we emit AdrpLdrGotLdr for those. 565 ; CHECK-LABEL: _getK 566 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 567 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _K@GOTPAGE 568 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 569 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _K@GOTPAGEOFF] 570 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 571 ; CHECK-NEXT: ldr q0, {{\[}}[[LDRGOT_REG]]] 572 ; CHECK-NEXT: ret 573 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 574 define <4 x i32> @getK() { 575 %res = load <4 x i32>, <4 x i32>* @K, align 4 576 ret <4 x i32> %res 577 } 578 579 ; CHECK-LABEL: _setK 580 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 581 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _K@GOTPAGE 582 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 583 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _K@GOTPAGEOFF] 584 ; CHECK-NEXT: [[STR_LABEL:Lloh[0-9]+]]: 585 ; CHECK-NEXT: str q0, {{\[}}[[LDRGOT_REG]]] 586 ; CHECK-NEXT: ret 587 ; CHECK: .loh AdrpLdrGotStr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[STR_LABEL]] 588 define void @setK(<4 x i32> %t) { 589 store <4 x i32> %t, <4 x i32>* @K, align 4 590 ret void 591 } 592 593 @L = common global <1 x i8> <i8 0>, align 4 594 595 ; LDR 8-bit vector supports loading from a literal. 596 ; Make sure we emit AdrpLdrGotLdr for those. 597 ; CHECK-LABEL: _getL 598 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 599 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _L@GOTPAGE 600 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 601 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _L@GOTPAGEOFF] 602 ; CHECK-NEXT: [[LDR_LABEL:Lloh[0-9]+]]: 603 ; CHECK-NEXT: ldr b0, {{\[}}[[LDRGOT_REG]]] 604 ; CHECK-NEXT: ret 605 ; CHECK: .loh AdrpLdrGotLdr [[ADRP_LABEL]], [[LDRGOT_LABEL]], [[LDR_LABEL]] 606 define <1 x i8> @getL() { 607 %res = load <1 x i8>, <1 x i8>* @L, align 4 608 ret <1 x i8> %res 609 } 610 611 ; CHECK-LABEL: _setL 612 ; CHECK: [[ADRP_LABEL:Lloh[0-9]+]]: 613 ; CHECK-NEXT: adrp [[ADRP_REG:x[0-9]+]], _L@GOTPAGE 614 ; CHECK-NEXT: [[LDRGOT_LABEL:Lloh[0-9]+]]: 615 ; CHECK-NEXT: ldr [[LDRGOT_REG:x[0-9]+]], {{\[}}[[ADRP_REG]], _L@GOTPAGEOFF] 616 ; CHECK-NEXT: ; kill 617 ; Ultimately we should generate str b0, but right now, we match the vector 618 ; variant which does not allow to fold the immediate into the store. 619 ; CHECK-NEXT: st1.b { v0 }[0], {{\[}}[[LDRGOT_REG]]] 620 ; CHECK-NEXT: ret 621 ; CHECK: .loh AdrpLdrGot [[ADRP_LABEL]], [[LDRGOT_LABEL]] 622 define void @setL(<1 x i8> %t) { 623 store <1 x i8> %t, <1 x i8>* @L, align 4 624 ret void 625 } 626 627 ; Make sure we do not assert when we do not track 628 ; all the aliases of a tuple register. 629 ; Indeed the tuple register can be tracked because of 630 ; one of its element, but the other elements of the tuple 631 ; do not need to be tracked and we used to assert on that. 632 ; Note: The test case is fragile in the sense that we need 633 ; a tuple register to appear in the lowering. Thus, the target 634 ; cpu is required to have the problem reproduced. 635 ; CHECK-LABEL: _uninterestingSub 636 ; CHECK: adrp [[ADRP_REG:x[0-9]+]], [[CONSTPOOL:lCPI[0-9]+_[0-9]+]]@PAGE 637 ; CHECK-NEXT: ldr q[[IDX:[0-9]+]], {{\[}}[[ADRP_REG]], [[CONSTPOOL]]@PAGEOFF] 638 ; The tuple comes from the next instruction. 639 ; CHECK-NEXT: tbl.16b v{{[0-9]+}}, { v{{[0-9]+}}, v{{[0-9]+}} }, v[[IDX]] 640 ; CHECK: ret 641 define void @uninterestingSub(i8* nocapture %row) #0 { 642 %tmp = bitcast i8* %row to <16 x i8>* 643 %tmp1 = load <16 x i8>, <16 x i8>* %tmp, align 16 644 %vext43 = shufflevector <16 x i8> <i8 undef, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0>, <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> 645 %add.i.414 = add <16 x i8> zeroinitializer, %vext43 646 store <16 x i8> %add.i.414, <16 x i8>* %tmp, align 16 647 %add.ptr51 = getelementptr inbounds i8, i8* %row, i64 16 648 %tmp2 = bitcast i8* %add.ptr51 to <16 x i8>* 649 %tmp3 = load <16 x i8>, <16 x i8>* %tmp2, align 16 650 %tmp4 = bitcast i8* undef to <16 x i8>* 651 %tmp5 = load <16 x i8>, <16 x i8>* %tmp4, align 16 652 %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> 653 %add.i.402 = add <16 x i8> zeroinitializer, %vext157 654 store <16 x i8> %add.i.402, <16 x i8>* %tmp4, align 16 655 ret void 656 } 657 658 @.str.89 = external unnamed_addr constant [12 x i8], align 1 659 @.str.90 = external unnamed_addr constant [5 x i8], align 1 660 ; CHECK-LABEL: test_r274582 661 define void @test_r274582() { 662 entry: 663 br i1 undef, label %if.then.i, label %if.end.i 664 if.then.i: 665 ret void 666 if.end.i: 667 ; CHECK: .loh AdrpAdrp Lloh91, Lloh93 668 ; CHECK: .loh AdrpLdr Lloh91, Lloh92 669 ; CHECK: .loh AdrpLdrGot Lloh93, Lloh95 670 ; CHECK: .loh AdrpLdrGot Lloh94, Lloh96 671 %mul.i.i.i = fmul double undef, 1.000000e-06 672 %add.i.i.i = fadd double undef, %mul.i.i.i 673 %sub.i.i = fsub double %add.i.i.i, undef 674 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.i.i) 675 unreachable 676 } 677 declare void @callee(i8* nocapture readonly, ...) 678 679 attributes #0 = { "target-cpu"="cyclone" } 680