| # 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 |