summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-06-15 20:36:13 +0000
committerJohn McCall <rjmccall@apple.com>2011-06-15 20:36:13 +0000
commit3a3465b71db858723988f61d72b7135e6dff329b (patch)
tree591e6ae22b2beba1e9466c96cc891664e0904d3c
parente97c7da59d65bbbd5e0d67b3ef9d742794437e2f (diff)
downloadllvm-3a3465b71db858723988f61d72b7135e6dff329b.tar.gz
llvm-3a3465b71db858723988f61d72b7135e6dff329b.tar.bz2
llvm-3a3465b71db858723988f61d72b7135e6dff329b.tar.xz
Add a new function attribute, nonlazybind, which inhibits lazy-loading
optimizations when emitting calls to the function; instead those calls may use faster relocations which require the function to be immediately resolved upon loading the dynamic object featuring the call. This is useful when it is known that the function will be called frequently and pervasively and therefore there is no merit in delaying binding of the function. Currently only implemented for x86-64, where it turns into a call through the global offset table. Patch by Dan Gohman, who assures me that he's going to add LangRef documentation for this once it's committed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133080 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Attributes.h5
-rw-r--r--lib/AsmParser/LLLexer.cpp1
-rw-r--r--lib/AsmParser/LLParser.cpp1
-rw-r--r--lib/AsmParser/LLToken.h1
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp20
-rw-r--r--lib/VMCore/Attributes.cpp2
-rw-r--r--test/CodeGen/X86/non-lazy-bind.ll27
-rw-r--r--test/Feature/paramattrs.ll2
-rw-r--r--utils/llvm.grm2
9 files changed, 60 insertions, 1 deletions
diff --git a/include/llvm/Attributes.h b/include/llvm/Attributes.h
index 8b69d6ecc1..233eab8bf1 100644
--- a/include/llvm/Attributes.h
+++ b/include/llvm/Attributes.h
@@ -69,6 +69,9 @@ const Attributes Hotpatch = 1<<29; ///< Function should have special
///'hotpatch' sequence in prologue
const Attributes UWTable = 1<<30; ///< Function must be in a unwind
///table
+const Attributes NonLazyBind = 1U<<31; ///< Function is called early and/or
+ /// often, so lazy binding isn't
+ /// worthwhile.
/// Note that uwtable is about the ABI or the user mandating an entry in the
/// unwind table. The nounwind attribute is about an exception passing by the
@@ -90,7 +93,7 @@ const Attributes ParameterOnly = ByVal | Nest | StructRet | NoCapture;
const Attributes FunctionOnly = NoReturn | NoUnwind | ReadNone | ReadOnly |
NoInline | AlwaysInline | OptimizeForSize | StackProtect | StackProtectReq |
NoRedZone | NoImplicitFloat | Naked | InlineHint | StackAlignment |
- Hotpatch | UWTable;
+ Hotpatch | UWTable | NonLazyBind;
/// @brief Parameter attributes that do not apply to vararg call arguments.
const Attributes VarArgsIncompatible = StructRet;
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index a363a653b2..a298c6af09 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -572,6 +572,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(noimplicitfloat);
KEYWORD(naked);
KEYWORD(hotpatch);
+ KEYWORD(nonlazybind);
KEYWORD(type);
KEYWORD(opaque);
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index 81e0747266..0260a7f639 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -985,6 +985,7 @@ bool LLParser::ParseOptionalAttrs(unsigned &Attrs, unsigned AttrKind) {
case lltok::kw_noimplicitfloat: Attrs |= Attribute::NoImplicitFloat; break;
case lltok::kw_naked: Attrs |= Attribute::Naked; break;
case lltok::kw_hotpatch: Attrs |= Attribute::Hotpatch; break;
+ case lltok::kw_nonlazybind: Attrs |= Attribute::NonLazyBind; break;
case lltok::kw_alignstack: {
unsigned Alignment;
diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h
index 02f97a3d3d..3b193dc8dc 100644
--- a/lib/AsmParser/LLToken.h
+++ b/lib/AsmParser/LLToken.h
@@ -99,6 +99,7 @@ namespace lltok {
kw_noimplicitfloat,
kw_naked,
kw_hotpatch,
+ kw_nonlazybind,
kw_type,
kw_opaque,
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 294a6a74cc..1cdf2b6aa6 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -2271,6 +2271,8 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
const GlobalValue *GV = G->getGlobal();
if (!GV->hasDLLImportLinkage()) {
unsigned char OpFlags = 0;
+ bool ExtraLoad = false;
+ unsigned WrapperKind = ISD::DELETED_NODE;
// On ELF targets, in both X86-64 and X86-32 mode, direct calls to
// external symbols most go through the PLT in PIC mode. If the symbol
@@ -2288,10 +2290,28 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
// unless we're building with the leopard linker or later, which
// automatically synthesizes these stubs.
OpFlags = X86II::MO_DARWIN_STUB;
+ } else if (Subtarget->isPICStyleRIPRel() &&
+ isa<Function>(GV) &&
+ cast<Function>(GV)->hasFnAttr(Attribute::NonLazyBind)) {
+ // If the function is marked as non-lazy, generate an indirect call
+ // which loads from the GOT directly. This avoids runtime overhead
+ // at the cost of eager binding (and one extra byte of encoding).
+ OpFlags = X86II::MO_GOTPCREL;
+ WrapperKind = X86ISD::WrapperRIP;
+ ExtraLoad = true;
}
Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(),
G->getOffset(), OpFlags);
+
+ // Add a wrapper if needed.
+ if (WrapperKind != ISD::DELETED_NODE)
+ Callee = DAG.getNode(X86ISD::WrapperRIP, dl, getPointerTy(), Callee);
+ // Add extra indirection if needed.
+ if (ExtraLoad)
+ Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), Callee,
+ MachinePointerInfo::getGOT(),
+ false, false, 0);
}
} else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
unsigned char OpFlags = 0;
diff --git a/lib/VMCore/Attributes.cpp b/lib/VMCore/Attributes.cpp
index ee257dbde5..bf6efa1645 100644
--- a/lib/VMCore/Attributes.cpp
+++ b/lib/VMCore/Attributes.cpp
@@ -74,6 +74,8 @@ std::string Attribute::getAsString(Attributes Attrs) {
Result += "naked ";
if (Attrs & Attribute::Hotpatch)
Result += "hotpatch ";
+ if (Attrs & Attribute::NonLazyBind)
+ Result += "nonlazybind ";
if (Attrs & Attribute::StackAlignment) {
Result += "alignstack(";
Result += utostr(Attribute::getStackAlignmentFromAttrs(Attrs));
diff --git a/test/CodeGen/X86/non-lazy-bind.ll b/test/CodeGen/X86/non-lazy-bind.ll
new file mode 100644
index 0000000000..f72965877d
--- /dev/null
+++ b/test/CodeGen/X86/non-lazy-bind.ll
@@ -0,0 +1,27 @@
+; RUN: llc -mtriple=x86_64-apple-darwin < %s | FileCheck %s
+
+declare void @lazy() nonlazybind
+declare void @not()
+
+; CHECK: foo:
+; CHECK: callq _not
+; CHECK: callq *_lazy@GOTPCREL(%rip)
+define void @foo() nounwind {
+ call void @not()
+ call void @lazy()
+ ret void
+}
+
+; CHECK: tail_call_regular:
+; CHECK: jmp _not
+define void @tail_call_regular() nounwind {
+ tail call void @not()
+ ret void
+}
+
+; CHECK: tail_call_eager:
+; CHECK: jmpq *_lazy@GOTPCREL(%rip)
+define void @tail_call_eager() nounwind {
+ tail call void @lazy()
+ ret void
+}
diff --git a/test/Feature/paramattrs.ll b/test/Feature/paramattrs.ll
index 3bee6177e0..d686257e79 100644
--- a/test/Feature/paramattrs.ll
+++ b/test/Feature/paramattrs.ll
@@ -20,3 +20,5 @@ define i32 @main(i32 inreg %argc, i8 ** inreg %argv) nounwind {
%retVal = sext i16 %two to i32
ret i32 %retVal
}
+
+declare void @function_to_resolve_eagerly() nonlazybind
diff --git a/utils/llvm.grm b/utils/llvm.grm
index 9d6bdf79f5..3f33702d2a 100644
--- a/utils/llvm.grm
+++ b/utils/llvm.grm
@@ -172,6 +172,8 @@ FuncAttr ::= noreturn
| optsize
| ssp
| sspreq
+ | hotpatch
+ | nonlazybind
;
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;