diff --git a/bolt/lib/Passes/ADRRelaxationPass.cpp b/bolt/lib/Passes/ADRRelaxationPass.cpp index 4b37a061ac12..c3954c94a7f9 100644 --- a/bolt/lib/Passes/ADRRelaxationPass.cpp +++ b/bolt/lib/Passes/ADRRelaxationPass.cpp @@ -81,17 +81,15 @@ void ADRRelaxationPass::runOnFunction(BinaryFunction &BF) { It = BB.eraseInstruction(std::prev(It)); } else if (std::next(It) != BB.end() && BC.MIB->isNoop(*std::next(It))) { BB.eraseInstruction(std::next(It)); - } else if (!opts::StrictMode && !BF.isSimple()) { + } else if (!BF.isSimple()) { // If the function is not simple, it may contain a jump table undetected // by us. This jump table may use an offset from the branch instruction // to land in the desired place. If we add new instructions, we // invalidate this offset, so we have to rely on linker-inserted NOP to // replace it with ADRP, and abort if it is not present. auto L = BC.scopeLock(); - BC.errs() << formatv( - "BOLT-ERROR: Cannot relax adr in non-simple function " - "{0}. Use --strict option to override\n", - BF.getOneName()); + BC.errs() << "BOLT-ERROR: cannot relax ADR in non-simple function " + << BF << '\n'; PassFailed = true; return; } diff --git a/bolt/test/AArch64/adr-relaxation-fail.s b/bolt/test/AArch64/adr-relaxation-fail.s new file mode 100644 index 000000000000..2b04bf8db697 --- /dev/null +++ b/bolt/test/AArch64/adr-relaxation-fail.s @@ -0,0 +1,33 @@ +## Check that llvm-bolt generates a proper error message when ADR instruction +## cannot be relaxed. + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static +# RUN: not llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s +# RUN: not llvm-bolt %t.exe -o %t.bolt --strict 2>&1 | FileCheck %s + +# CHECK: BOLT-ERROR: cannot relax ADR in non-simple function _start + +## The function contains unknown control flow and llvm-bolt fails to recover +## CFG. As BOLT has to preserve the function layout, the ADR instruction cannot +## be relaxed into ADRP+ADD. + .text + .globl _start + .type _start, %function +_start: + .cfi_startproc + adr x1, foo + adr x2, .L1 +.L1: + br x0 + ret x0 + .cfi_endproc + .size _start, .-_start + + .globl foo + .type foo, %function +foo: + .cfi_startproc + ret x0 + .cfi_endproc + .size foo, .-foo diff --git a/bolt/test/AArch64/adr-relaxation.s b/bolt/test/AArch64/adr-relaxation.s index 0aa3c71f29aa..a643a62339ba 100644 --- a/bolt/test/AArch64/adr-relaxation.s +++ b/bolt/test/AArch64/adr-relaxation.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static # RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=random2 -# RUN: llvm-objdump -d --disassemble-symbols=_start %t.bolt | FileCheck %s +# RUN: llvm-objdump -d -j .text %t.bolt | FileCheck %s # RUN: llvm-objdump -d --disassemble-symbols=foo.cold.0 %t.bolt \ # RUN: | FileCheck --check-prefix=CHECK-FOO %s @@ -13,11 +13,10 @@ .globl _start .type _start, %function _start: -# CHECK: <_start>: .cfi_startproc +# CHECK: <_start>: +# CHECK-NEXT: adr adr x1, _start -# CHECK-NOT: adrp -# CHECK: adr cmp x1, x11 b.hi .L1 mov x0, #0x0 @@ -38,12 +37,27 @@ foo: mov x0, #0x0 .L2: # CHECK-FOO: : - adr x1, foo -# CHECK-FOO: adrp +# CHECK-FOO-NEXT: adrp # CHECK-FOO-NEXT: add + adr x1, foo ret x30 .cfi_endproc .size foo, .-foo -## Force relocation mode. - .reloc 0, R_AARCH64_NONE +## bar is a non-simple function. We can still relax ADR, because it has a +## preceding NOP. + .globl bar + .type bar, %function +bar: + .cfi_startproc +# CHECK-LABEL: : +# CHECK-NEXT: adrp +# CHECK-NEXT: add + nop + adr x0, foo + adr x1, .L3 + br x1 +.L3: + ret x0 + .cfi_endproc + .size bar, .-bar diff --git a/bolt/test/AArch64/r_aarch64_prelxx.s b/bolt/test/AArch64/r_aarch64_prelxx.s index 73bf8387d363..5cbe2c50b294 100644 --- a/bolt/test/AArch64/r_aarch64_prelxx.s +++ b/bolt/test/AArch64/r_aarch64_prelxx.s @@ -12,16 +12,14 @@ // CHECKPREL-NEXT: R_AARCH64_PREL32 {{.*}} _start + 4 // CHECKPREL-NEXT: R_AARCH64_PREL64 {{.*}} _start + 8 -// RUN: llvm-bolt %t.exe -o %t.bolt --strict +// RUN: llvm-bolt %t.exe -o %t.bolt // RUN: llvm-objdump -D %t.bolt | FileCheck %s --check-prefix=CHECKPREL32 // CHECKPREL32: [[#%x,DATATABLEADDR:]] : // CHECKPREL32-NEXT: 00: // CHECKPREL32-NEXT: 04: {{.*}} .word 0x[[#%x,VALUE:]] -// 4 is offset in datatable -// 8 is addend -// CHECKPREL32: [[#DATATABLEADDR + 4 - 8 + VALUE]] <_start>: +// CHECKPREL32: [[#DATATABLEADDR + VALUE]] <_start>: // RUN: llvm-objdump -D %t.bolt | FileCheck %s --check-prefix=CHECKPREL64 // CHECKPREL64: [[#%x,DATATABLEADDR:]] : @@ -30,16 +28,15 @@ // CHECKPREL64-NEXT: 08: {{.*}} .word 0x[[#%x,VALUE:]] // CHECKPREL64-NEXT: 0c: {{.*}} .word 0x00000000 -// 8 is offset in datatable -// 12 is addend -// CHECKPREL64: [[#DATATABLEADDR + 8 - 12 + VALUE]] <_start>: +// CHECKPREL64: [[#DATATABLEADDR + VALUE]] <_start>: .section .text .align 4 .globl _start .type _start, %function _start: - adr x0, datatable + adrp x0, datatable + add x0, x0, :lo12:datable mov x0, #0 ret diff --git a/bolt/test/AArch64/test-indirect-branch.s b/bolt/test/AArch64/test-indirect-branch.s index b99737ee97ac..a9fa7737d3d2 100644 --- a/bolt/test/AArch64/test-indirect-branch.s +++ b/bolt/test/AArch64/test-indirect-branch.s @@ -7,8 +7,8 @@ // RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown -mattr=+pauth %s -o %t.o // RUN: %clang %cflags --target=aarch64-unknown-linux %t.o -o %t.exe -Wl,-q -// RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg --strict --debug-only=mcplus \ -// RUN: -v=1 2>&1 | FileCheck %s +// RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg --debug-only=mcplus -v=1 2>&1 \ +// RUN: | FileCheck %s // Pattern 1: there is no shift amount after the 'add' instruction. // @@ -45,6 +45,7 @@ _start: .type test1, %function test1: mov x1, #0 + nop adr x3, datatable add x3, x3, x1, lsl #2 ldr w2, [x3] @@ -56,6 +57,11 @@ test1_1: ret test1_2: ret + .size test1, .-test1 + +// Temporary workaround for PC-relative relocations from datatable leaking into +// test2 function and creating phantom entry points. +.skip 0x100 // Pattern 2 // CHECK: BOLT-DEBUG: failed to match indirect branch: nop/adr instead of adrp/add @@ -65,6 +71,7 @@ test2: nop adr x3, jump_table ldrh w3, [x3, x1, lsl #1] + nop adr x1, test2_0 add x3, x1, w3, sxth #2 br x3 diff --git a/bolt/test/runtime/AArch64/adrrelaxationpass.s b/bolt/test/runtime/AArch64/adrrelaxationpass.s deleted file mode 100644 index fa9fb63c613d..000000000000 --- a/bolt/test/runtime/AArch64/adrrelaxationpass.s +++ /dev/null @@ -1,62 +0,0 @@ -# The second and third ADR instructions are non-local to functions -# and must be replaced with ADRP + ADD by BOLT -# Also since main and test are non-simple, we can't change it's length so we -# have to replace NOP with adrp, and if there is no nop before adr in non-simple -# function, we can't guarantee we didn't break possible jump tables, so we -# fail in non-strict mode - -# REQUIRES: system-linux - -# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \ -# RUN: %s -o %t.o -# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -# RUN: llvm-bolt %t.exe -o %t.bolt --adr-relaxation=true --strict -# RUN: llvm-objdump --no-print-imm-hex -d --disassemble-symbols=main %t.bolt | FileCheck %s -# RUN: %t.bolt -# RUN: not llvm-bolt %t.exe -o %t.bolt --adr-relaxation=true \ -# RUN: 2>&1 | FileCheck %s --check-prefix CHECK-ERROR - - .text - .align 4 - .global test - .type test, %function -test: - adr x2, Gvar - mov x0, xzr - ret - .size test, .-test - - .align 4 - .global main - .type main, %function -main: - adr x0, .CI - nop - adr x1, test - adr x2, Gvar2 - adr x3, br -br: - br x1 - .size main, .-main -.CI: - .word 0xff - - .data - .align 8 - .global Gvar -Gvar: .xword 0x0 - .global Gvar2 -Gvar2: .xword 0x42 - .balign 4 -jmptable: - .word 0 - .word test - jmptable - -# CHECK:
: -# CHECK-NEXT: adr x0, 0x{{[1-8a-f][0-9a-f]*}} -# CHECK-NEXT: adrp x1, 0x{{[1-8a-f][0-9a-f]*}} -# CHECK-NEXT: add x1, x1, #{{[1-8a-f][0-9a-f]*}} -# CHECK-NEXT: adrp x2, 0x{{[1-8a-f][0-9a-f]*}} -# CHECK-NEXT: add x2, x2, #{{[1-8a-f][0-9a-f]*}} -# CHECK-NEXT: adr x3, 0x{{[1-8a-f][0-9a-f]*}} -# CHECK-ERROR: BOLT-ERROR: Cannot relax adr in non-simple function