Index: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ include/llvm/IR/Module.h @@ -838,6 +838,16 @@ Metadata *getProfileSummary(); /// @} + /// @name Utility functions for querying and setting if PLT must be avoided. + + /// \brief Returns true if PLT should be avoided. + bool getAvoidPLT() const; + + /// \brief Set that PLT should be avoided. + void setAvoidPLT(); + /// @} + + /// Take ownership of the given memory buffer. void setOwnedMemoryBuffer(std::unique_ptr MB); }; Index: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ lib/IR/Module.cpp @@ -510,6 +510,19 @@ OwnedMemoryBuffer = std::move(MB); } +bool Module::getAvoidPLT() const { + auto *Val = cast_or_null(getModuleFlag("Avoid PLT")); + + if (!Val) + return true; + + return false; +} + +void Module::setAvoidPLT() { + addModuleFlag(ModFlagBehavior::Max, "AvoidPLT", 1); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallPtrSetImpl &Set, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; Index: lib/Target/TargetMachine.cpp =================================================================== --- lib/Target/TargetMachine.cpp +++ lib/Target/TargetMachine.cpp @@ -167,7 +167,9 @@ // symbol turns out to be external, the linker will convert a direct // access to an access via the plt, so don't assume it is local. const Function *F = dyn_cast_or_null(GV); - if (F && F->hasFnAttribute(Attribute::NonLazyBind)) + if (F && + (F->hasFnAttribute(Attribute::NonLazyBind) || + M.getAvoidPLT())) return false; bool IsTLS = GV && GV->isThreadLocal(); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -3732,11 +3732,23 @@ } } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { const Module *Mod = DAG.getMachineFunction().getFunction().getParent(); - unsigned char OpFlags = - Subtarget.classifyGlobalFunctionReference(nullptr, *Mod); + // If PLT must be avoided then the call should be via GOTPCREL. + unsigned char OpFlags = X86II::MO_GOTPCREL; + + if (!Mod->getAvoidPLT()) { + OpFlags = Subtarget.classifyGlobalFunctionReference(nullptr, *Mod); + } Callee = DAG.getTargetExternalSymbol( S->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlags); + + if (OpFlags == X86II::MO_GOTPCREL) { + Callee = DAG.getNode(X86ISD::WrapperRIP, dl, + getPointerTy(DAG.getDataLayout()), Callee); + Callee = DAG.getLoad( + getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); + } } else if (Subtarget.isTarget64BitILP32() && Callee->getValueType(0) == MVT::i32) { // Zero-extend the 32-bit Callee address into a 64-bit according to x32 ABI Index: test/CodeGen/X86/no-plt.ll =================================================================== --- test/CodeGen/X86/no-plt.ll +++ test/CodeGen/X86/no-plt.ll @@ -3,7 +3,16 @@ ; RUN: llc < %s -mcpu=generic -mtriple=x86_64-linux-gnu \ ; RUN: | FileCheck -check-prefix=X64 %s -define i32 @main() #0 { +; Function Attrs: noinline nounwind uwtable +define i32 @baz(i8* nocapture %a, i8* nocapture readonly %b, i32 returned %bytes) local_unnamed_addr #0 { +; X64: callq *memcpy@GOTPCREL(%rip) +entry: + %conv = sext i32 %bytes to i64 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 %conv, i32 1, i1 false) + ret i32 %bytes +} + +define i32 @main() #1 { ; X64: callq *_Z3foov@GOTPCREL(%rip) ; X64: callq _Z3barv ; X64: callq _Z3bazv @@ -18,13 +27,18 @@ } ; Function Attrs: nonlazybind -declare i32 @_Z3foov() #1 +declare i32 @_Z3foov() #2 -declare i32 @_Z3barv() #2 +declare i32 @_Z3barv() #3 ; Function Attrs: nonlazybind -declare hidden i32 @_Z3bazv() #3 +declare hidden i32 @_Z3bazv() #4 + +; Function Attrs: argmemonly nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) +attributes #2 = { nonlazybind } +attributes #4 = { nonlazybind } -attributes #1 = { nonlazybind } -attributes #3 = { nonlazybind } +!llvm.module.flags = !{!1} +!1 = !{i32 7, !"AvoidPLT", i32 1}