Index: lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- lib/Target/PowerPC/PPCAsmPrinter.cpp +++ lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -669,30 +669,26 @@ MO.isBlockAddress()) && "Invalid operand for ADDIStocHA!"); MCSymbol *MOSymbol = nullptr; - bool IsExternal = false; - bool IsNonLocalFunction = false; - bool IsCommon = false; - bool IsAvailExt = false; + bool GlobalToc = false; if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); MOSymbol = getSymbol(GV); - IsExternal = GV->isDeclaration(); - IsCommon = GV->hasCommonLinkage(); - IsNonLocalFunction = GV->getType()->getElementType()->isFunctionTy() && - !GV->isStrongDefinitionForLinker(); - IsAvailExt = GV->hasAvailableExternallyLinkage(); - } else if (MO.isCPI()) + unsigned char gv_flags = Subtarget->ClassifyGlobalReference(GV); + GlobalToc = ((gv_flags & PPCII::MO_NLP_FLAG) || + (gv_flags & PPCII::MO_NLP_HIDDEN_FLAG)); + } else if (MO.isCPI()) { MOSymbol = GetCPISymbol(MO.getIndex()); - else if (MO.isJTI()) + } else if (MO.isJTI()) { MOSymbol = GetJTISymbol(MO.getIndex()); - else if (MO.isBlockAddress()) + } else if (MO.isBlockAddress()) { MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); + } - if (IsExternal || IsNonLocalFunction || IsCommon || IsAvailExt || - MO.isJTI() || MO.isBlockAddress() || - TM.getCodeModel() == CodeModel::Large) + if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || + TM.getCodeModel() == CodeModel::Large) { MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + } const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA, @@ -727,13 +723,15 @@ MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); } else if (MO.isGlobal()) { - const GlobalValue *GValue = MO.getGlobal(); - MOSymbol = getSymbol(GValue); - if (GValue->getType()->getElementType()->isFunctionTy() || - GValue->isDeclaration() || GValue->hasCommonLinkage() || - GValue->hasAvailableExternallyLinkage() || - TM.getCodeModel() == CodeModel::Large) - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + const GlobalValue *GV = MO.getGlobal(); + MOSymbol = getSymbol(GV); + DEBUG( + unsigned char gv_flags = Subtarget->ClassifyGlobalReference(GV); + assert(((gv_flags & PPCII::MO_NLP_FLAG) || + (gv_flags & PPCII::MO_NLP_HIDDEN_FLAG)) && + "LDtocL used on symbol that could be accessed directly is " + "invalid. Must match ADDIStocHA.")); + MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); } const MCExpr *Exp = @@ -754,21 +752,19 @@ const MachineOperand &MO = MI->getOperand(2); assert((MO.isGlobal() || MO.isCPI()) && "Invalid operand for ADDItocL"); MCSymbol *MOSymbol = nullptr; - bool IsExternal = false; - bool IsNonLocalFunction = false; if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); + DEBUG( + unsigned char gv_flags = Subtarget->ClassifyGlobalReference(GV); + assert ( + !(gv_flags & PPCII::MO_NLP_FLAG) && + !(gv_flags & PPCII::MO_NLP_HIDDEN_FLAG) && + "Interposable definitions must use indirect access.")); MOSymbol = getSymbol(GV); - IsExternal = GV->isDeclaration(); - IsNonLocalFunction = GV->getType()->getElementType()->isFunctionTy() && - !GV->isStrongDefinitionForLinker(); - } else if (MO.isCPI()) + } else if (MO.isCPI()) { MOSymbol = GetCPISymbol(MO.getIndex()); - - if (IsNonLocalFunction || IsExternal || - TM.getCodeModel() == CodeModel::Large) - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + } const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, Index: lib/Target/PowerPC/PPCFastISel.cpp =================================================================== --- lib/Target/PowerPC/PPCFastISel.cpp +++ lib/Target/PowerPC/PPCFastISel.cpp @@ -1972,19 +1972,16 @@ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::ADDIStocHA), HighPartReg).addReg(PPC::X2).addGlobalAddress(GV); - // If/when switches are implemented, jump tables should be handled - // on the "if" path here. - if (CModel == CodeModel::Large || - (GV->getType()->getElementType()->isFunctionTy() && - !GV->isStrongDefinitionForLinker()) || - GV->isDeclaration() || GV->hasCommonLinkage() || - GV->hasAvailableExternallyLinkage()) + unsigned char gv_flags = PPCSubTarget->ClassifyGlobalReference(GV); + if ((gv_flags & PPCII::MO_NLP_FLAG) || + (gv_flags & PPCII::MO_NLP_HIDDEN_FLAG)) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::LDtocL), DestReg).addGlobalAddress(GV).addReg(HighPartReg); - else + } else { // Otherwise generate the ADDItocL. BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::ADDItocL), DestReg).addReg(HighPartReg).addGlobalAddress(GV); + } } return DestReg; Index: lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -2902,9 +2902,7 @@ break; // The first source operand is a TargetGlobalAddress or a TargetJumpTable. - // If it is an externally defined symbol, a symbol with common linkage, - // a non-local function address, or a jump table address, or if we are - // generating code for large code model, we generate: + // If it must be toc-referenced according to PPCSubTarget, we generate: // LDtocL(, ADDIStocHA(%X2, )) // Otherwise we generate: // ADDItocL(ADDIStocHA(%X2, ), ) @@ -2919,13 +2917,13 @@ MVT::i64, GA, SDValue(Tmp, 0))); if (GlobalAddressSDNode *G = dyn_cast(GA)) { - const GlobalValue *GValue = G->getGlobal(); - if ((GValue->getType()->getElementType()->isFunctionTy() && - !GValue->isStrongDefinitionForLinker()) || - GValue->isDeclaration() || GValue->hasCommonLinkage() || - GValue->hasAvailableExternallyLinkage()) + const GlobalValue *GV = G->getGlobal(); + unsigned char gv_flags = PPCSubTarget->ClassifyGlobalReference(GV); + if ((gv_flags & PPCII::MO_NLP_FLAG) || + (gv_flags & PPCII::MO_NLP_HIDDEN_FLAG)) { return transferMemOperands(N, CurDAG->getMachineNode(PPC::LDtocL, dl, MVT::i64, GA, SDValue(Tmp, 0))); + } } return CurDAG->getMachineNode(PPC::ADDItocL, dl, MVT::i64, Index: lib/Target/PowerPC/PPCSubtarget.h =================================================================== --- lib/Target/PowerPC/PPCSubtarget.h +++ lib/Target/PowerPC/PPCSubtarget.h @@ -285,6 +285,10 @@ bool useAA() const override; bool enableSubRegLiveness() const override; + + /// ClassifyGlobalReference - Classify a global variable reference for the + /// current subtarget accourding to how we should reference it. + unsigned char ClassifyGlobalReference(const GlobalValue *GV) const; }; } // End llvm namespace Index: lib/Target/PowerPC/PPCSubtarget.cpp =================================================================== --- lib/Target/PowerPC/PPCSubtarget.cpp +++ lib/Target/PowerPC/PPCSubtarget.cpp @@ -210,5 +210,41 @@ return UseSubRegLiveness; } +unsigned char PPCSubtarget::ClassifyGlobalReference( + const GlobalValue *GV) const { + // Large model always uses a non local pointer and is pic. + if (TM.getCodeModel() == CodeModel::Large) + return PPCII::MO_NLP_FLAG | PPCII::MO_PIC_FLAG; + + // Gold incorrectly handles R_PPC64_TOC16* + // Until it is fixed, output toc accesses, even when unnecessary. + // isStrongDefinitionForLinker() is exactly what is needed to avoid this. + // If the definition is handy, we can do it ourselves, but we can't rely on + // the linker. + // FIXME: this is a bug in gold + if (!GV->isStrongDefinitionForLinker()) + return PPCII::MO_NLP_FLAG | PPCII::MO_PIC_FLAG; + + // Except for large code model, and external functions, static relocation is + // always direct. + if (TM.getRelocationModel() == Reloc::Static) + return PPCII::MO_NO_FLAG; + + unsigned char flags = PPCII::MO_NO_FLAG; + if (TM.getRelocationModel() == Reloc::PIC_) { + flags |= PPCII::MO_PIC_FLAG; + } + + if (!GV->hasLocalLinkage()) { + if (GV->hasHiddenVisibility()) { + flags |= PPCII::MO_NLP_HIDDEN_FLAG; + return flags; + } + flags |= PPCII::MO_NLP_FLAG; + return flags; + } + return flags; +} + bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); } bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); }