Index: llvm/trunk/lib/Target/X86/X86FastISel.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86FastISel.cpp +++ llvm/trunk/lib/Target/X86/X86FastISel.cpp @@ -3157,25 +3157,10 @@ unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; // See if we need any target-specific flags on the GV operand. - unsigned char OpFlags = 0; - - // 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 - // has hidden or protected visibility, or if it is static or local, then - // we don't need to use the PLT - we can directly call it. - if (Subtarget->isTargetELF() && - TM.getRelocationModel() == Reloc::PIC_ && - GV->hasDefaultVisibility() && !GV->hasLocalLinkage()) { - OpFlags = X86II::MO_PLT; - } else if (Subtarget->isPICStyleStubAny() && - !GV->isStrongDefinitionForLinker() && - (!Subtarget->getTargetTriple().isMacOSX() || - Subtarget->getTargetTriple().isMacOSXVersionLT(10, 5))) { - // PC-relative references to external symbols should go through $stub, - // unless we're building with the leopard linker or later, which - // automatically synthesizes these stubs. - OpFlags = X86II::MO_DARWIN_STUB; - } + unsigned char OpFlags = Subtarget->classifyGlobalFunctionReference(GV, TM); + // Ignore NonLazyBind attribute in FastISel + if (OpFlags == X86II::MO_GOTPCREL) + OpFlags = 0; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc)); if (Symbol) Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -3273,31 +3273,8 @@ // non-JIT mode. const GlobalValue *GV = G->getGlobal(); if (!GV->hasDLLImportStorageClass()) { - unsigned char OpFlags = 0; - - // 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 - // has hidden or protected visibility, or if it is static or local, then - // we don't need to use the PLT - we can directly call it. - if (Subtarget.isTargetELF() && - DAG.getTarget().getRelocationModel() == Reloc::PIC_ && - GV->hasDefaultVisibility() && !GV->hasLocalLinkage()) { - OpFlags = X86II::MO_PLT; - } else if (Subtarget.isPICStyleStubAny() && - !GV->isStrongDefinitionForLinker() && - (!Subtarget.getTargetTriple().isMacOSX() || - Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5))) { - // PC-relative references to external symbols should go through $stub, - // 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(GV) && - cast(GV)->hasFnAttribute(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; - } + unsigned char OpFlags = + Subtarget.classifyGlobalFunctionReference(GV, DAG.getTarget()); Callee = DAG.getTargetGlobalAddress( GV, dl, getPointerTy(DAG.getDataLayout()), G->getOffset(), OpFlags); Index: llvm/trunk/lib/Target/X86/X86Subtarget.h =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.h +++ llvm/trunk/lib/Target/X86/X86Subtarget.h @@ -554,6 +554,11 @@ unsigned char ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM)const; + /// classifyGlobalFunctionReference - Classify a global function reference + /// for the current subtarget. + unsigned char classifyGlobalFunctionReference(const GlobalValue *GV, + const TargetMachine &TM) const; + /// Classify a blockaddress reference for the current subtarget according to /// how we should reference it in a non-pcrel context. unsigned char ClassifyBlockAddressReference() const; Index: llvm/trunk/lib/Target/X86/X86Subtarget.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.cpp +++ llvm/trunk/lib/Target/X86/X86Subtarget.cpp @@ -144,6 +144,35 @@ return X86II::MO_NO_FLAG; } +unsigned char X86Subtarget::classifyGlobalFunctionReference( + const GlobalValue *GV, const TargetMachine &TM) const { + // 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 + // has hidden or protected visibility, or if it is static or local, then + // we don't need to use the PLT - we can directly call it. + // In PIE mode, calls to global functions don't need to go through PLT + if (isTargetELF() && TM.getRelocationModel() == Reloc::PIC_ && + (!TM.Options.PositionIndependentExecutable || + GV->isDeclarationForLinker()) && + GV->hasDefaultVisibility() && !GV->hasLocalLinkage()) { + return X86II::MO_PLT; + } else if (isPICStyleStubAny() && !GV->isStrongDefinitionForLinker() && + (!getTargetTriple().isMacOSX() || + getTargetTriple().isMacOSXVersionLT(10, 5))) { + // PC-relative references to external symbols should go through $stub, + // unless we're building with the leopard linker or later, which + // automatically synthesizes these stubs. + return X86II::MO_DARWIN_STUB; + } else if (isPICStyleRIPRel() && isa(GV) && + cast(GV)->hasFnAttribute(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). + return X86II::MO_GOTPCREL; + } + + return X86II::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 Index: llvm/trunk/test/CodeGen/X86/pie.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/pie.ll +++ llvm/trunk/test/CodeGen/X86/pie.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s -O0 -mcpu=generic -mtriple=i686-linux-gnu -relocation-model=pic -enable-pie | FileCheck %s +; RUN: llc < %s -O0 -mcpu=generic -mtriple=i686-linux-gnu -fast-isel -relocation-model=pic -enable-pie | FileCheck %s +; RUN: llc < %s -O0 -mcpu=generic -mtriple=x86_64-linux-gnu -relocation-model=pic -enable-pie | FileCheck %s +; RUN: llc < %s -O0 -mcpu=generic -mtriple=x86_64-linux-gnu -fast-isel -relocation-model=pic -enable-pie | FileCheck %s + +; CHECK-LABEL: bar: +; CHECK: call{{l|q}} foo{{$}} +; CHECK: call{{l|q}} weak_odr_foo{{$}} +; CHECK: call{{l|q}} weak_foo{{$}} +; CHECK: call{{l|q}} internal_foo{{$}} +; CHECK: call{{l|q}} ext_baz@PLT + +define weak void @weak_foo() { + ret void +} + +define weak_odr void @weak_odr_foo() { + ret void +} + +define internal void @internal_foo() { + ret void +} + +declare i32 @ext_baz() + +define void @foo() { + ret void +} + +define void @bar() { +entry: + call void @foo() + call void @weak_odr_foo() + call void @weak_foo() + call void @internal_foo() + call i32 @ext_baz() + ret void +} + +; -fpie for local global data tests should be added here