# REQUIRES: aarch64
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/lib.s -o %t/lib.o
# RUN: %lld -arch arm64 -dylib -o %t/lib.dylib %t/lib.o
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/external.s -o %t/near-got.o
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/external.s -defsym=PADDING=1 -o %t/far-got.o
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/local.s -o %t/local.o
# RUN: %lld -arch arm64 %t/near-got.o %t/lib.dylib -o %t/NearGot
# RUN: %lld -arch arm64 %t/far-got.o %t/lib.dylib -o %t/FarGot
# RUN: %lld -arch arm64 %t/local.o -o %t/Local
# RUN: llvm-objdump --no-print-imm-hex -d --macho %t/NearGot | FileCheck %s -check-prefix=NEAR-GOT
# RUN: llvm-objdump --no-print-imm-hex -d --macho %t/FarGot | FileCheck %s -check-prefix=FAR-GOT
# RUN: llvm-objdump --no-print-imm-hex -d --macho %t/Local | FileCheck %s -check-prefix=LOCAL
#--- external.s
.text
.align 2
.globl _main
_main:
## Basic test
L1: adrp x0, _external@GOTPAGE
L2: ldr x1, [x0, _external@GOTPAGEOFF]
L3: ldr x2, [x1]
# NEAR-GOT-LABEL: _main:
# NEAR-GOT-NEXT: nop
# NEAR-GOT-NEXT: ldr x1, #{{.*}} ; literal pool symbol address: _external
# NEAR-GOT-NEXT: ldr x2, [x1]
# FAR-GOT-LABEL: _main:
# FAR-GOT-NEXT: adrp x0
# FAR-GOT-NEXT: ldr x1
# FAR-GOT-NEXT: ldr x2, [x1]
## The second load has an offset
L4: adrp x0, _external@GOTPAGE
L5: ldr x1, [x0, _external@GOTPAGEOFF]
L6: ldr q2, [x1, #16]
# NEAR-GOT-NEXT: nop
# NEAR-GOT-NEXT: ldr x1, #{{.*}} ; literal pool symbol address: _external
# NEAR-GOT-NEXT: ldr q2, [x1, #16]
# FAR-GOT-NEXT: adrp x0
# FAR-GOT-NEXT: ldr x1
# FAR-GOT-NEXT: ldr q2, [x1, #16]
### Tests for invalid inputs
.ifndef PADDING
## Registers don't match
L7: adrp x0, _external@GOTPAGE
L8: ldr x1, [x1, _external@GOTPAGEOFF]
L9: ldr x2, [x1]
# NEAR-GOT-NEXT: adrp x0
# NEAR-GOT-NEXT: ldr x1
# NEAR-GOT-NEXT: ldr x2, [x1]
## Registers don't match
L10: adrp x0, _external@GOTPAGE
L11: ldr x1, [x0, _external@GOTPAGEOFF]
L12: ldr x2, [x0]
# NEAR-GOT-NEXT: adrp x0
# NEAR-GOT-NEXT: ldr x1
# NEAR-GOT-NEXT: ldr x2, [x0]
## Not an LDR (immediate)
L13: adrp x0, _external@GOTPAGE
L14: ldr x1, 0
L15: ldr x2, [x1]
# NEAR-GOT-NEXT: adrp x0
# NEAR-GOT-NEXT: ldr x1
# NEAR-GOT-NEXT: ldr x2, [x1]
.loh AdrpLdrGotLdr L7, L8, L9
.loh AdrpLdrGotLdr L10, L11, L12
.loh AdrpLdrGotLdr L13, L14, L15
.endif
.loh AdrpLdrGotLdr L1, L2, L3
.loh AdrpLdrGotLdr L4, L5, L6
.ifdef PADDING
.space 1048576
.endif
.data
#--- lib.s
.data
.align 4
.globl _external
_external:
.zero 32
#--- local.s
.text
.align 2
.globl _main
_main:
### Transformation to a literal LDR
## Basic case
L1: adrp x0, _close@GOTPAGE
L2: ldr x1, [x0, _close@GOTPAGEOFF]
L3: ldr x2, [x1]
# LOCAL-LABEL: _main:
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr x2
## Load with offset
L4: adrp x0, _close@GOTPAGE
L5: ldr x1, [x0, _close@GOTPAGEOFF]
L6: ldr x2, [x1, #8]
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr x2
## 32 bit load
L7: adrp x0, _close@GOTPAGE
L8: ldr x1, [x0, _close@GOTPAGEOFF]
L9: ldr w1, [x1]
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr w1, _close
## Floating point
L10: adrp x0, _close@GOTPAGE
L11: ldr x1, [x0, _close@GOTPAGEOFF]
L12: ldr s1, [x1]
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr s1, _close
L13: adrp x0, _close@GOTPAGE
L14: ldr x1, [x0, _close@GOTPAGEOFF]
L15: ldr d1, [x1, #8]
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr d1, _close8
L16: adrp x0, _close@GOTPAGE
L17: ldr x1, [x0, _close@GOTPAGEOFF]
L18: ldr q0, [x1]
# LOCAL-NEXT: nop
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr q0, _close
### Transformation to ADR+LDR
## 1 byte floating point load
L19: adrp x0, _close@GOTPAGE
L20: ldr x1, [x0, _close@GOTPAGEOFF]
L21: ldr b2, [x1]
# LOCAL-NEXT: adr x1
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr b2, [x1]
## 1 byte GPR load, zero extend
L22: adrp x0, _close@GOTPAGE
L23: ldr x1, [x0, _close@GOTPAGEOFF]
L24: ldrb w2, [x1]
# LOCAL-NEXT: adr x1
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldrb w2, [x1]
## 1 byte GPR load, sign extend
L25: adrp x0, _close@GOTPAGE
L26: ldr x1, [x0, _close@GOTPAGEOFF]
L27: ldrsb x2, [x1]
# LOCAL-NEXT: adr x1
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldrsb x2, [x1]
## Unaligned
L28: adrp x0, _unaligned@GOTPAGE
L29: ldr x1, [x0, _unaligned@GOTPAGEOFF]
L30: ldr x2, [x1]
# LOCAL-NEXT: adr x1
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr x2, [x1]
### Transformation to ADRP + immediate LDR
## Basic test: target is far
L31: adrp x0, _far@GOTPAGE
L32: ldr x1, [x0, _far@GOTPAGEOFF]
L33: ldr x2, [x1]
# LOCAL-NEXT: adrp x0
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr x2
## With offset
L34: adrp x0, _far@GOTPAGE
L35: ldr x1, [x0, _far@GOTPAGEOFF]
L36: ldr x2, [x1, #8]
# LOCAL-NEXT: adrp x0
# LOCAL-NEXT: nop
# LOCAL-NEXT: ldr x2
### No changes other than GOT relaxation
## Far and unaligned
L37: adrp x0, _far_unaligned@GOTPAGE
L38: ldr x1, [x0, _far_unaligned@GOTPAGEOFF]
L39: ldr x2, [x1]
# LOCAL-NEXT: adrp x0
# LOCAL-NEXT: add x1, x0
# LOCAL-NEXT: ldr x2, [x1]
## Far with large offset (_far_offset@GOTPAGEOFF + #255 > 4095)
L40: adrp x0, _far_offset@GOTPAGE
L41: ldr x1, [x0, _far_offset@GOTPAGEOFF]
L42: ldrb w2, [x1, #255]
# LOCAL-NEXT: adrp x0
# LOCAL-NEXT: add x1, x0
# LOCAL-NEXT: ldrb w2, [x1, #255]
### Tests for invalid inputs, only GOT relaxation should happen
## Registers don't match
L43: adrp x0, _far@GOTPAGE
L44: ldr x1, [x0, _far@GOTPAGEOFF]
L45: ldr x2, [x2]
# LOCAL-NEXT: adrp x0
# LOCAL-NEXT: add x1, x0
# LOCAL-NEXT: ldr x2, [x2]
.data
.align 4
.quad 0
_close:
.quad 0
_close8:
.quad 0
.byte 0
_unaligned:
.quad 0
.space 1048576
.align 12
.quad 0
_far:
.quad 0
.byte 0
_far_unaligned:
.quad 0
.space 4000
_far_offset:
.byte 0
.loh AdrpLdrGotLdr L1, L2, L3
.loh AdrpLdrGotLdr L4, L5, L6
.loh AdrpLdrGotLdr L7, L8, L9
.loh AdrpLdrGotLdr L10, L11, L12
.loh AdrpLdrGotLdr L13, L14, L15
.loh AdrpLdrGotLdr L16, L17, L18
.loh AdrpLdrGotLdr L19, L20, L21
.loh AdrpLdrGotLdr L22, L23, L24
.loh AdrpLdrGotLdr L25, L26, L27
.loh AdrpLdrGotLdr L28, L29, L30
.loh AdrpLdrGotLdr L31, L32, L33
.loh AdrpLdrGotLdr L34, L35, L36
.loh AdrpLdrGotLdr L37, L38, L39
.loh AdrpLdrGotLdr L40, L41, L42
.loh AdrpLdrGotLdr L43, L44, L45