Skip to content

Commit

Permalink
AArch64: support nonlazybind
Browse files Browse the repository at this point in the history
It's almost certainly not a good idea to actually use it in most cases (there's
a pretty large code size overhead on AArch64), but we can't do those
experiments until it's supported.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300462 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
TNorthover committed Apr 17, 2017
1 parent f1a890d commit a017dc6
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 19 deletions.
34 changes: 15 additions & 19 deletions lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3239,30 +3239,26 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
// node so that legalize doesn't hack it.
if (getTargetMachine().getCodeModel() == CodeModel::Large &&
Subtarget->isTargetMachO()) {
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
auto GV = G->getGlobal();
if (Subtarget->classifyGlobalFunctionReference(GV, getTargetMachine()) ==
AArch64II::MO_GOT) {
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, AArch64II::MO_GOT);
Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
} else {
const GlobalValue *GV = G->getGlobal();
bool InternalLinkage = GV->hasInternalLinkage();
if (InternalLinkage)
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);
else {
Callee =
DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, AArch64II::MO_GOT);
Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
}
} else if (ExternalSymbolSDNode *S =
dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);
}
} else if (auto *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
if (getTargetMachine().getCodeModel() == CodeModel::Large &&
Subtarget->isTargetMachO()) {
const char *Sym = S->getSymbol();
Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, AArch64II::MO_GOT);
Callee = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, Callee);
} else {
const char *Sym = S->getSymbol();
Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, 0);
}
} else if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
const GlobalValue *GV = G->getGlobal();
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);
} else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
const char *Sym = S->getSymbol();
Callee = DAG.getTargetExternalSymbol(Sym, PtrVT, 0);
}

// We don't usually want to end the call-sequence here because we would tidy
Expand Down
17 changes: 17 additions & 0 deletions lib/Target/AArch64/AArch64Subtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,23 @@ AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
return AArch64II::MO_NO_FLAG;
}

unsigned char AArch64Subtarget::classifyGlobalFunctionReference(
const GlobalValue *GV, const TargetMachine &TM) const {
// MachO large model always goes via a GOT, because we don't have the
// relocations available to do anything else..
if (TM.getCodeModel() == CodeModel::Large && isTargetMachO() &&
!GV->hasInternalLinkage())
return AArch64II::MO_GOT;

// NonLazyBind goes via GOT unless we know it's available locally.
auto *F = dyn_cast<Function>(GV);
if (F && F->hasFnAttribute(Attribute::NonLazyBind) &&
!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return AArch64II::MO_GOT;

return AArch64II::MO_NO_FLAG;
}

/// This function returns the name of a function which has an interface
/// like the non-standard bzero function, if such a function exists on
/// the current subtarget and it is considered prefereable over
Expand Down
3 changes: 3 additions & 0 deletions lib/Target/AArch64/AArch64Subtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
unsigned char ClassifyGlobalReference(const GlobalValue *GV,
const TargetMachine &TM) const;

unsigned char classifyGlobalFunctionReference(const GlobalValue *GV,
const TargetMachine &TM) const;

/// This function returns the name of a function which has an interface
/// like the non-standard bzero function, if such a function exists on
/// the current subtarget and it is considered prefereable over
Expand Down
32 changes: 32 additions & 0 deletions test/CodeGen/AArch64/nonlazybind.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
; RUN: llc -mtriple=aarch64-apple-ios %s -o - | FileCheck %s

define void @local() nonlazybind {
ret void
}

declare void @nonlocal() nonlazybind

define void @test_laziness() {
; CHECK-LABEL: test_laziness:

; CHECK: bl _local

; CHECK: adrp x[[TMP:[0-9]+]], _nonlocal@GOTPAGE
; CHECK: ldr [[FUNC:x[0-9]+]], [x[[TMP]], _nonlocal@GOTPAGEOFF]
; CHECK: blr [[FUNC]]

call void @local()
call void @nonlocal()
ret void
}

define void @test_laziness_tail() {
; CHECK-LABEL: test_laziness_tail:

; CHECK: adrp x[[TMP:[0-9]+]], _nonlocal@GOTPAGE
; CHECK: ldr [[FUNC:x[0-9]+]], [x[[TMP]], _nonlocal@GOTPAGEOFF]
; CHECK: br [[FUNC]]

tail call void @nonlocal()
ret void
}

0 comments on commit a017dc6

Please sign in to comment.