mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-23 02:29:18 +00:00
[AArch 64] Use a constant pool load for weak symbol references when
using static relocation model and small code model. Summary: currently we generate GOT based relocations for weak symbol references regardless of the underlying relocation model. This should be change so that in static relocation model we use a constant pool load instead. Patch from: Keith Walker Reviewers: Renato Golin, Tim Northover git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217503 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
96597a70dc
commit
3babc141b2
@ -372,6 +372,9 @@ unsigned AArch64FastISel::AArch64MaterializeGV(const GlobalValue *GV) {
|
||||
.addReg(ADRPReg)
|
||||
.addGlobalAddress(GV, 0, AArch64II::MO_GOT | AArch64II::MO_PAGEOFF |
|
||||
AArch64II::MO_NC);
|
||||
} else if (OpFlags & AArch64II::MO_CONSTPOOL) {
|
||||
// We can't handle addresses loaded from a constant pool quickly yet.
|
||||
return 0;
|
||||
} else {
|
||||
// ADRP + ADDX
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::ADRP),
|
||||
|
@ -2711,7 +2711,8 @@ SDValue AArch64TargetLowering::LowerGlobalAddress(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
EVT PtrVT = getPointerTy();
|
||||
SDLoc DL(Op);
|
||||
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
||||
const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
|
||||
const GlobalValue *GV = GN->getGlobal();
|
||||
unsigned char OpFlags =
|
||||
Subtarget->ClassifyGlobalReference(GV, getTargetMachine());
|
||||
|
||||
@ -2726,6 +2727,25 @@ SDValue AArch64TargetLowering::LowerGlobalAddress(SDValue Op,
|
||||
return DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, GotAddr);
|
||||
}
|
||||
|
||||
if ((OpFlags & AArch64II::MO_CONSTPOOL) != 0) {
|
||||
assert(getTargetMachine().getCodeModel() == CodeModel::Small &&
|
||||
"use of MO_CONSTPOOL only supported on small model");
|
||||
SDValue Hi = DAG.getTargetConstantPool(GV, PtrVT, 0, 0, AArch64II::MO_PAGE);
|
||||
SDValue ADRP = DAG.getNode(AArch64ISD::ADRP, DL, PtrVT, Hi);
|
||||
unsigned char LoFlags = AArch64II::MO_PAGEOFF | AArch64II::MO_NC;
|
||||
SDValue Lo = DAG.getTargetConstantPool(GV, PtrVT, 0, 0, LoFlags);
|
||||
SDValue PoolAddr = DAG.getNode(AArch64ISD::ADDlow, DL, PtrVT, ADRP, Lo);
|
||||
SDValue GlobalAddr = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), PoolAddr,
|
||||
MachinePointerInfo::getConstantPool(),
|
||||
/*isVolatile=*/ false,
|
||||
/*isNonTemporal=*/ true,
|
||||
/*isInvariant=*/ true, 8);
|
||||
if (GN->getOffset() != 0)
|
||||
return DAG.getNode(ISD::ADD, DL, PtrVT, GlobalAddr,
|
||||
DAG.getConstant(GN->getOffset(), PtrVT));
|
||||
return GlobalAddr;
|
||||
}
|
||||
|
||||
if (getTargetMachine().getCodeModel() == CodeModel::Large) {
|
||||
const unsigned char MO_NC = AArch64II::MO_NC;
|
||||
return DAG.getNode(
|
||||
|
@ -78,10 +78,15 @@ AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
|
||||
return AArch64II::MO_GOT;
|
||||
|
||||
// The small code mode's direct accesses use ADRP, which cannot necessarily
|
||||
// produce the value 0 (if the code is above 4GB). Therefore they must use the
|
||||
// GOT.
|
||||
if (TM.getCodeModel() == CodeModel::Small && GV->isWeakForLinker() && isDecl)
|
||||
// produce the value 0 (if the code is above 4GB).
|
||||
if (TM.getCodeModel() == CodeModel::Small &&
|
||||
GV->isWeakForLinker() && isDecl) {
|
||||
// In PIC mode use the GOT, but in absolute mode use a constant pool load.
|
||||
if (TM.getRelocationModel() == Reloc::Static)
|
||||
return AArch64II::MO_CONSTPOOL;
|
||||
else
|
||||
return AArch64II::MO_GOT;
|
||||
}
|
||||
|
||||
// If symbol visibility is hidden, the extra load is not needed if
|
||||
// the symbol is definitely defined in the current translation unit.
|
||||
|
@ -1271,7 +1271,12 @@ namespace AArch64II {
|
||||
/// thread-local symbol. On Darwin, only one type of thread-local access
|
||||
/// exists (pre linker-relaxation), but on ELF the TLSModel used for the
|
||||
/// referee will affect interpretation.
|
||||
MO_TLS = 0x20
|
||||
MO_TLS = 0x20,
|
||||
|
||||
/// MO_CONSTPOOL - This flag indicates that a symbol operand represents
|
||||
/// the address of a constant pool entry for the symbol, rather than the
|
||||
/// address of the symbol itself.
|
||||
MO_CONSTPOOL = 0x40
|
||||
};
|
||||
} // end namespace AArch64II
|
||||
|
||||
|
@ -1,16 +1,23 @@
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -o - < %s | FileCheck %s
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -o - < %s | FileCheck %s
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=static -o - < %s | FileCheck --check-prefix=CHECK-STATIC %s
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -code-model=large -o - < %s | FileCheck --check-prefix=CHECK-LARGE %s
|
||||
|
||||
declare extern_weak i32 @var()
|
||||
|
||||
define i32()* @foo() {
|
||||
; The usual ADRP/ADD pair can't be used for a weak reference because it must
|
||||
; evaluate to 0 if the symbol is undefined. We use a litpool entry.
|
||||
; evaluate to 0 if the symbol is undefined. We use a GOT entry for PIC
|
||||
; otherwise a litpool entry.
|
||||
ret i32()* @var
|
||||
|
||||
; CHECK: adrp x[[VAR:[0-9]+]], :got:var
|
||||
; CHECK: ldr x0, [x[[VAR]], :got_lo12:var]
|
||||
|
||||
; CHECK-STATIC: .LCPI0_0:
|
||||
; CHECK-STATIC-NEXT: .xword var
|
||||
; CHECK-STATIC: adrp x[[VAR:[0-9]+]], .LCPI0_0
|
||||
; CHECK-STATIC: ldr x0, [x[[VAR]], :lo12:.LCPI0_0]
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
; materialise 0.
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:var
|
||||
@ -29,6 +36,11 @@ define i32* @bar() {
|
||||
; CHECK: add x0, [[ARR_VAR]], #20
|
||||
ret i32* %addr
|
||||
|
||||
; CHECK-STATIC: .LCPI1_0:
|
||||
; CHECK-STATIC-NEXT: .xword arr_var
|
||||
; CHECK-STATIC: ldr [[BASE:x[0-9]+]], [{{x[0-9]+}}, :lo12:.LCPI1_0]
|
||||
; CHECK-STATIC: add x0, [[BASE]], #20
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
; materialise 0.
|
||||
; CHECK-LARGE: movz [[ARR_VAR:x[0-9]+]], #:abs_g3:arr_var
|
||||
@ -44,6 +56,9 @@ define i32* @wibble() {
|
||||
; CHECK: adrp [[BASE:x[0-9]+]], defined_weak_var
|
||||
; CHECK: add x0, [[BASE]], :lo12:defined_weak_var
|
||||
|
||||
; CHECK-STATIC: adrp [[BASE:x[0-9]+]], defined_weak_var
|
||||
; CHECK-STATIC: add x0, [[BASE]], :lo12:defined_weak_var
|
||||
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g2_nc:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g1_nc:defined_weak_var
|
||||
|
@ -1,17 +1,24 @@
|
||||
; RUN: llc -mtriple=aarch64-none-linux-gnu -o - %s | FileCheck %s
|
||||
; RUN: llc -mtriple=aarch64-none-linux-gnu -relocation-model=pic -o - %s | FileCheck %s
|
||||
; RUN: llc -mtriple=aarch64-none-linux-gnu -relocation-model=static -o - < %s | FileCheck --check-prefix=CHECK-STATIC %s
|
||||
; RUN: llc -mtriple=aarch64-none-linux-gnu -code-model=large -o - %s | FileCheck --check-prefix=CHECK-LARGE %s
|
||||
|
||||
declare extern_weak i32 @var()
|
||||
|
||||
define i32()* @foo() {
|
||||
; The usual ADRP/ADD pair can't be used for a weak reference because it must
|
||||
; evaluate to 0 if the symbol is undefined. We use a litpool entry.
|
||||
; evaluate to 0 if the symbol is undefined. We use a GOT entry for PIC
|
||||
; otherwise a litpool entry.
|
||||
ret i32()* @var
|
||||
|
||||
|
||||
; CHECK: adrp x[[ADDRHI:[0-9]+]], :got:var
|
||||
; CHECK: ldr x0, [x[[ADDRHI]], :got_lo12:var]
|
||||
|
||||
; CHECK-STATIC: .LCPI0_0:
|
||||
; CHECK-STATIC-NEXT: .xword var
|
||||
; CHECK-STATIC: adrp x[[VAR:[0-9]+]], .LCPI0_0
|
||||
; CHECK-STATIC: ldr x0, [x[[VAR]], :lo12:.LCPI0_0]
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
; materialise 0.
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:var
|
||||
@ -31,6 +38,11 @@ define i32* @bar() {
|
||||
; CHECK: ldr [[BASE:x[0-9]+]], [x[[ADDRHI]], :got_lo12:arr_var]
|
||||
; CHECK: add x0, [[BASE]], #20
|
||||
|
||||
; CHECK-STATIC: .LCPI1_0:
|
||||
; CHECK-STATIC-NEXT: .xword arr_var
|
||||
; CHECK-STATIC: ldr [[BASE:x[0-9]+]], [{{x[0-9]+}}, :lo12:.LCPI1_0]
|
||||
; CHECK-STATIC: add x0, [[BASE]], #20
|
||||
|
||||
ret i32* %addr
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
@ -49,6 +61,9 @@ define i32* @wibble() {
|
||||
; CHECK: adrp [[BASE:x[0-9]+]], defined_weak_var
|
||||
; CHECK: add x0, [[BASE]], :lo12:defined_weak_var
|
||||
|
||||
; CHECK-STATIC: adrp [[BASE:x[0-9]+]], defined_weak_var
|
||||
; CHECK-STATIC: add x0, [[BASE]], :lo12:defined_weak_var
|
||||
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g2_nc:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g1_nc:defined_weak_var
|
||||
|
Loading…
Reference in New Issue
Block a user