diff options
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/X86/X86FastISel.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 44 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86Subtarget.cpp | 210 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86Subtarget.h | 13 |
4 files changed, 130 insertions, 155 deletions
diff --git a/llvm/lib/Target/X86/X86FastISel.cpp b/llvm/lib/Target/X86/X86FastISel.cpp index 69fd8bac64b..b5a000de631 100644 --- a/llvm/lib/Target/X86/X86FastISel.cpp +++ b/llvm/lib/Target/X86/X86FastISel.cpp @@ -947,10 +947,8 @@ bool X86FastISel::X86SelectCallAddress(const Value *V, X86AddressMode &AM) { // base and index registers are unused. assert(AM.Base.Reg == 0 && AM.IndexReg == 0); AM.Base.Reg = X86::RIP; - } else if (Subtarget->isPICStyleStubPIC()) { - AM.GVOpFlags = X86II::MO_PIC_BASE_OFFSET; - } else if (Subtarget->isPICStyleGOT()) { - AM.GVOpFlags = X86II::MO_GOTOFF; + } else { + AM.GVOpFlags = Subtarget->classifyLocalReference(nullptr); } return true; @@ -3453,17 +3451,13 @@ unsigned X86FastISel::X86MaterializeFP(const ConstantFP *CFP, MVT VT) { // x86-32 PIC requires a PIC base register for constant pools. unsigned PICBase = 0; - unsigned char OpFlag = 0; - if (Subtarget->isPICStyleStubPIC()) { // Not dynamic-no-pic - OpFlag = X86II::MO_PIC_BASE_OFFSET; + unsigned char OpFlag = Subtarget->classifyLocalReference(nullptr); + if (OpFlag == X86II::MO_PIC_BASE_OFFSET) PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF); - } else if (Subtarget->isPICStyleGOT()) { - OpFlag = X86II::MO_GOTOFF; + else if (OpFlag == X86II::MO_GOTOFF) PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF); - } else if (Subtarget->isPICStyleRIPRel() && - TM.getCodeModel() == CodeModel::Small) { + else if (Subtarget->is64Bit() && TM.getCodeModel() == CodeModel::Small) PICBase = X86::RIP; - } // Create the load from the constant pool. unsigned CPI = MCP.getConstantPoolIndex(CFP, Align); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index b8c1d0dd4b8..6e4fbc18105 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -3279,21 +3279,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, } } } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { - unsigned char OpFlags = 0; - - // On ELF targets, in either X86-64 or X86-32 mode, direct calls to - // external symbols should go through the PLT. - if (Subtarget.isTargetELF() && - DAG.getTarget().getRelocationModel() == Reloc::PIC_) { - OpFlags = X86II::MO_PLT; - } else if (Subtarget.isPICStyleStubAny() && - (!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; - } + const Module *Mod = DAG.getMachineFunction().getFunction()->getParent(); + unsigned char OpFlags = + Subtarget.classifyGlobalFunctionReference(nullptr, *Mod); Callee = DAG.getTargetExternalSymbol( S->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlags); @@ -12542,17 +12530,13 @@ X86TargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { // In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the // global base reg. - unsigned char OpFlag = 0; + unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr); unsigned WrapperKind = X86ISD::Wrapper; CodeModel::Model M = DAG.getTarget().getCodeModel(); if (Subtarget.isPICStyleRIPRel() && (M == CodeModel::Small || M == CodeModel::Kernel)) WrapperKind = X86ISD::WrapperRIP; - else if (Subtarget.isPICStyleGOT()) - OpFlag = X86II::MO_GOTOFF; - else if (Subtarget.isPICStyleStubPIC()) - OpFlag = X86II::MO_PIC_BASE_OFFSET; auto PtrVT = getPointerTy(DAG.getDataLayout()); SDValue Result = DAG.getTargetConstantPool( @@ -12574,17 +12558,13 @@ SDValue X86TargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { // In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the // global base reg. - unsigned char OpFlag = 0; + unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr); unsigned WrapperKind = X86ISD::Wrapper; CodeModel::Model M = DAG.getTarget().getCodeModel(); if (Subtarget.isPICStyleRIPRel() && (M == CodeModel::Small || M == CodeModel::Kernel)) WrapperKind = X86ISD::WrapperRIP; - else if (Subtarget.isPICStyleGOT()) - OpFlag = X86II::MO_GOTOFF; - else if (Subtarget.isPICStyleStubPIC()) - OpFlag = X86II::MO_PIC_BASE_OFFSET; auto PtrVT = getPointerTy(DAG.getDataLayout()); SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OpFlag); @@ -12606,22 +12586,14 @@ X86TargetLowering::LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const { // In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the // global base reg. - unsigned char OpFlag = 0; + const Module *Mod = DAG.getMachineFunction().getFunction()->getParent(); + unsigned char OpFlag = Subtarget.classifyGlobalReference(nullptr, *Mod); unsigned WrapperKind = X86ISD::Wrapper; CodeModel::Model M = DAG.getTarget().getCodeModel(); if (Subtarget.isPICStyleRIPRel() && - (M == CodeModel::Small || M == CodeModel::Kernel)) { - if (Subtarget.isTargetDarwin() || Subtarget.isTargetELF()) - OpFlag = X86II::MO_GOTPCREL; + (M == CodeModel::Small || M == CodeModel::Kernel)) WrapperKind = X86ISD::WrapperRIP; - } else if (Subtarget.isPICStyleGOT()) { - OpFlag = X86II::MO_GOT; - } else if (Subtarget.isPICStyleStubPIC()) { - OpFlag = X86II::MO_DARWIN_NONLAZY_PIC_BASE; - } else if (Subtarget.isPICStyleStubNoDynamic()) { - OpFlag = X86II::MO_DARWIN_NONLAZY; - } auto PtrVT = getPointerTy(DAG.getDataLayout()); SDValue Result = DAG.getTargetExternalSymbol(Sym, PtrVT, OpFlag); diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp index fe3cd466d00..7f033bea962 100644 --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -47,136 +47,146 @@ X86EarlyIfConv("x86-early-ifcvt", cl::Hidden, /// Classify a blockaddress reference for the current subtarget according to how /// we should reference it in a non-pcrel context. unsigned char X86Subtarget::classifyBlockAddressReference() const { - if (isPICStyleGOT()) // 32-bit ELF targets. - return X86II::MO_GOTOFF; + return classifyLocalReference(nullptr); +} - if (isPICStyleStubPIC()) // Darwin/32 in PIC mode. - return X86II::MO_PIC_BASE_OFFSET; +// FIXME: make this a proper option +static bool CanUseCopyRelocWithPIE = false; - // Direct static reference to label. - return X86II::MO_NO_FLAG; -} +static bool shouldAssumeDSOLocal(Reloc::Model RM, const Triple &TT, + const Module &M, const GlobalValue *GV) { + // DLLImport explicitly marks the GV as external. + if (GV && GV->hasDLLImportStorageClass()) + return false; -/// Classify a global variable reference for the current subtarget according to -/// how we should reference it in a non-pcrel context. -unsigned char -X86Subtarget::classifyGlobalReference(const GlobalValue *GV) const { - // DLLImport only exists on windows, it is implemented as a load from a - // DLLIMPORT stub. - if (GV->hasDLLImportStorageClass()) - return X86II::MO_DLLIMPORT; + // Every other GV is local on COFF + if (TT.isOSBinFormatCOFF()) + return true; + + if (RM == Reloc::Static) + return true; + + if (GV && (GV->hasInternalLinkage() || !GV->hasDefaultVisibility())) + return true; + + if (TT.isOSBinFormatELF()) { + assert(RM != Reloc::DynamicNoPIC); + // Some linkers can use copy relocations with pie executables. + if (M.getPIELevel() != PIELevel::Default) { + if (CanUseCopyRelocWithPIE) + return true; - bool isDef = GV->isStrongDefinitionForLinker(); - - // X86-64 in PIC mode. - if (isPICStyleRIPRel()) { - // Large model never uses stubs. - if (TM.getCodeModel() == CodeModel::Large) - return X86II::MO_NO_FLAG; - - if (isTargetDarwin()) { - // If symbol visibility is hidden, the extra load is not needed if - // target is x86-64 or the symbol is definitely defined in the current - // translation unit. - if (GV->hasDefaultVisibility() && !isDef) - return X86II::MO_GOTPCREL; - } else if (!isTargetWin64()) { - assert(isTargetELF() && "Unknown rip-relative target"); - - // Extra load is needed for all externally visible globals except with - // PIE as the definition of the global in an executable is not - // overridden. - - if (!GV->hasLocalLinkage() && GV->hasDefaultVisibility() && - !isGlobalDefinedInPIE(GV)) - return X86II::MO_GOTPCREL; + // If the symbol is defined, it cannot be preempted. + if (GV && !GV->isDeclarationForLinker()) + return true; + return false; } - return X86II::MO_NO_FLAG; + // ELF supports preemption of other symbols. + return false; } - if (isPICStyleGOT()) { // 32-bit ELF targets. - // Extra load is needed for all externally visible globals except with - // PIE as the definition of the global in an executable is not overridden. + assert(TT.isOSBinFormatMachO()); + if (GV && GV->isStrongDefinitionForLinker()) + return true; - if (GV->hasLocalLinkage() || GV->hasHiddenVisibility() || - isGlobalDefinedInPIE(GV)) - return X86II::MO_GOTOFF; - return X86II::MO_GOT; - } + return false; +} - if (isPICStyleStubPIC()) { // Darwin/32 in PIC mode. - // Determine whether we have a stub reference and/or whether the reference - // is relative to the PIC base or not. +/// Classify a global variable reference for the current subtarget according to +/// how we should reference it in a non-pcrel context. +unsigned char +X86Subtarget::classifyGlobalReference(const GlobalValue *GV) const { + return classifyGlobalReference(GV, *GV->getParent()); +} - // If this is a strong reference to a definition, it is definitely not - // through a stub. - if (isDef) - return X86II::MO_PIC_BASE_OFFSET; +unsigned char +X86Subtarget::classifyLocalReference(const GlobalValue *GV) const { + // 64 bits can use %rip addressing for anything local. + if (is64Bit()) + return X86II::MO_NO_FLAG; - // Unless we have a symbol with hidden visibility, we have to go through a - // normal $non_lazy_ptr stub because this symbol might be resolved late. - if (!GV->hasHiddenVisibility()) // $non_lazy_ptr reference. - return X86II::MO_DARWIN_NONLAZY_PIC_BASE; + // If this is for a position dependent executable, the static linker can + // figure it out. + if (TM.getRelocationModel() != Reloc::PIC_) + return X86II::MO_NO_FLAG; - // If symbol visibility is hidden, we have a stub for common symbol - // references and external declarations. - if (GV->isDeclarationForLinker() || GV->hasCommonLinkage()) { - // $non_lazy_ptr reference. + // The COFF dynamic linker just patches the executable sections. + if (isTargetCOFF()) + return X86II::MO_NO_FLAG; + + if (isTargetDarwin()) { + // 32 bit macho has no relocation for a-b if a is undefined, even if + // b is in the section that is being relocated. + // This means we have to use o load even for GVs that are known to be + // local to the dso. + if (GV && (GV->isDeclarationForLinker() || GV->hasCommonLinkage())) return X86II::MO_DARWIN_NONLAZY_PIC_BASE; - } - // Otherwise, no stub. return X86II::MO_PIC_BASE_OFFSET; } - if (isPICStyleStubNoDynamic()) { // Darwin/32 in -mdynamic-no-pic mode. - // Determine whether we have a stub reference. + return X86II::MO_GOTOFF; +} - // If this is a strong reference to a definition, it is definitely not - // through a stub. - if (isDef) - return X86II::MO_NO_FLAG; +unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV, + const Module &M) const { + // Large model never uses stubs. + if (TM.getCodeModel() == CodeModel::Large) + return X86II::MO_NO_FLAG; - // Unless we have a symbol with hidden visibility, we have to go through a - // normal $non_lazy_ptr stub because this symbol might be resolved late. - if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. - return X86II::MO_DARWIN_NONLAZY; + Reloc::Model RM = TM.getRelocationModel(); + if (shouldAssumeDSOLocal(RM, TargetTriple, M, GV)) + return classifyLocalReference(GV); - // Otherwise, no stub. - return X86II::MO_NO_FLAG; + if (isTargetCOFF()) + return X86II::MO_DLLIMPORT; + + if (is64Bit()) + return X86II::MO_GOTPCREL; + + if (isTargetDarwin()) { + if (RM != Reloc::PIC_) + return X86II::MO_DARWIN_NONLAZY; + return X86II::MO_DARWIN_NONLAZY_PIC_BASE; } - // Direct static reference to global. - return X86II::MO_NO_FLAG; + return X86II::MO_GOT; } unsigned char X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV) 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_ && - !isGlobalDefinedInPIE(GV) && GV->hasDefaultVisibility() && - !GV->hasLocalLinkage()) { + return classifyGlobalFunctionReference(GV, *GV->getParent()); +} + +unsigned char +X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV, + const Module &M) const { + if (shouldAssumeDSOLocal(TM.getRelocationModel(), TargetTriple, M, GV)) + return X86II::MO_NO_FLAG; + + assert(!isTargetCOFF()); + + if (isTargetELF()) 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<Function>(GV) && - cast<Function>(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; + + if (is64Bit()) { + auto *F = dyn_cast_or_null<Function>(GV); + if (F && F->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; } + // 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. + if (!getTargetTriple().isMacOSX() || + getTargetTriple().isMacOSXVersionLT(10, 5)) + return X86II::MO_DARWIN_STUB; + return X86II::MO_NO_FLAG; } diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h index 68672c28060..f77a33f2348 100644 --- a/llvm/lib/Target/X86/X86Subtarget.h +++ b/llvm/lib/Target/X86/X86Subtarget.h @@ -556,18 +556,17 @@ public: } } - /// Determine if this global is defined in a Position Independent - /// Executable (PIE) where its definition cannot be interposed. - bool isGlobalDefinedInPIE(const GlobalValue *GV) const { - return GV->getParent()->getPIELevel() != PIELevel::Default && - !GV->isDeclarationForLinker(); - } - /// Classify a global variable reference for the current subtarget according /// to how we should reference it in a non-pcrel context. + unsigned char classifyLocalReference(const GlobalValue *GV) const; + + unsigned char classifyGlobalReference(const GlobalValue *GV, + const Module &M) const; unsigned char classifyGlobalReference(const GlobalValue *GV) const; /// Classify a global function reference for the current subtarget. + unsigned char classifyGlobalFunctionReference(const GlobalValue *GV, + const Module &M) const; unsigned char classifyGlobalFunctionReference(const GlobalValue *GV) const; /// Classify a blockaddress reference for the current subtarget according to |