Index: llvm/trunk/lib/Target/Mips/MipsISelLowering.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsISelLowering.h +++ llvm/trunk/lib/Target/Mips/MipsISelLowering.h @@ -331,6 +331,21 @@ DAG.getNode(MipsISD::Lo, DL, Ty, Lo)); } + // This method creates the following nodes, which are necessary for + // computing a symbol's address using gp-relative addressing: + // + // (add $gp, %gp_rel(sym)) + template + SDValue getAddrGPRel(NodeTy *N, EVT Ty, SelectionDAG &DAG) const { + SDLoc DL(N); + assert(Ty == MVT::i32); + SDValue GPRel = getTargetNode(N, Ty, DAG, MipsII::MO_GPREL); + return DAG.getNode(ISD::ADD, DL, Ty, + DAG.getRegister(Mips::GP, Ty), + DAG.getNode(MipsISD::GPRel, DL, DAG.getVTList(Ty), + GPRel)); + } + /// This function fills Ops, which is the list of operands that will later /// be used when a function call node is created. It also generates /// copyToReg nodes to set up argument registers. Index: llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp +++ llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp @@ -1693,8 +1693,6 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { - // FIXME there isn't actually debug info here - SDLoc DL(Op); EVT Ty = Op.getValueType(); GlobalAddressSDNode *N = cast(Op); const GlobalValue *GV = N->getGlobal(); @@ -1704,15 +1702,9 @@ const MipsTargetObjectFile &TLOF = (const MipsTargetObjectFile&)getObjFileLowering(); - // %gp_rel relocation - if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) { - SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, 0, - MipsII::MO_GPREL); - SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, DL, - DAG.getVTList(MVT::i32), GA); - SDValue GPReg = DAG.getRegister(Mips::GP, MVT::i32); - return DAG.getNode(ISD::ADD, DL, MVT::i32, GPReg, GPRelNode); - } + if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) + // %gp_rel relocation + return getAddrGPRel(N, Ty, DAG); // %hi/%lo relocation return getAddrNonPIC(N, Ty, DAG); @@ -1843,21 +1835,20 @@ SDValue MipsTargetLowering:: lowerConstantPool(SDValue Op, SelectionDAG &DAG) const { - // gp_rel relocation - // FIXME: we should reference the constant pool using small data sections, - // but the asm printer currently doesn't support this feature without - // hacking it. This feature should come soon so we can uncomment the - // stuff below. - //if (IsInSmallSection(C->getType())) { - // SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, MVT::i32, CP); - // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); - // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); ConstantPoolSDNode *N = cast(Op); EVT Ty = Op.getValueType(); if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && - !Subtarget.isABI_N64()) + !Subtarget.isABI_N64()) { + const MipsTargetObjectFile &TLOF = + (const MipsTargetObjectFile&)getObjFileLowering(); + + if (TLOF.IsConstantInSmallSection(N->getConstVal(), getTargetMachine())) + // %gp_rel relocation + return getAddrGPRel(N, Ty, DAG); + return getAddrNonPIC(N, Ty, DAG); + } return getAddrLocal(N, Ty, DAG, Subtarget.isABI_N32() || Subtarget.isABI_N64()); Index: llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp +++ llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp @@ -58,6 +58,10 @@ cl::desc("MIPS: mips16 constant islands enable."), cl::init(true)); +static cl::opt +GPOpt("mgpopt", cl::Hidden, + cl::desc("MIPS: Enable gp-relative addressing of small data items")); + /// Select the Mips CPU for the given triple and cpu name. /// FIXME: Merge with the copy in MipsMCTargetDesc.cpp static StringRef selectMipsCPU(Triple TT, StringRef CPU) { @@ -171,10 +175,16 @@ if (TT.find("linux") == std::string::npos) IsLinux = false; + if (NoABICalls && TM->getRelocationModel() == Reloc::PIC_) + report_fatal_error("position-independent code requires '-mabicalls'"); + // Set UseSmallSection. - // TODO: Investigate the IsLinux check. I suspect it's really checking for - // bare-metal. - UseSmallSection = !IsLinux && (TM->getRelocationModel() == Reloc::Static); + UseSmallSection = GPOpt; + if (!NoABICalls && GPOpt) { + errs() << "warning: cannot use small-data accesses for '-mabicalls'" + << "\n"; + UseSmallSection = false; + } } /// This overrides the PostRAScheduler bit in the SchedModel for any CPU. Index: llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.h +++ llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.h @@ -17,21 +17,30 @@ class MipsTargetObjectFile : public TargetLoweringObjectFileELF { const MCSection *SmallDataSection; const MCSection *SmallBSSSection; + const TargetMachine *TM; public: void Initialize(MCContext &Ctx, const TargetMachine &TM) override; - - /// IsGlobalInSmallSection - Return true if this global address should be - /// placed into small data/bss section. - bool IsGlobalInSmallSection(const GlobalValue *GV, - const TargetMachine &TM, SectionKind Kind)const; + /// Return true if this global address should be placed into small data/bss + /// section. + bool IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const; bool IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const; + bool IsGlobalInSmallSectionImpl(const GlobalValue *GV, + const TargetMachine &TM) const; const MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const override; + + /// Return true if this constant should be placed into small data section. + bool IsConstantInSmallSection(const Constant *CN, + const TargetMachine &TM) const; + + const MCSection *getSectionForConstant(SectionKind Kind, + const Constant *C) const override; }; } // end namespace llvm Index: llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.cpp +++ llvm/trunk/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -24,6 +24,17 @@ cl::desc("Small data and bss section threshold size (default=8)"), cl::init(8)); +static cl::opt +LocalSData("mlocal-sdata", cl::Hidden, + cl::desc("MIPS: Use gp_rel for object-local data."), + cl::init(true)); + +static cl::opt +ExternSData("mextern-sdata", cl::Hidden, + cl::desc("MIPS: Use gp_rel for data that is not defined by the " + "current object."), + cl::init(true)); + void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(TM.Options.UseInitArray); @@ -37,29 +48,46 @@ getContext().getELFSection(".sbss", ELF::SHT_NOBITS, ELF::SHF_WRITE |ELF::SHF_ALLOC, SectionKind::getBSS()); + this->TM = &TM; } // A address must be loaded from a small section if its size is less than the // small section size threshold. Data in this section must be addressed using // gp_rel operator. static bool IsInSmallSection(uint64_t Size) { + // gcc has traditionally not treated zero-sized objects as small data, so this + // is effectively part of the ABI. return Size > 0 && Size <= SSThreshold; } -bool MipsTargetObjectFile::IsGlobalInSmallSection(const GlobalValue *GV, - const TargetMachine &TM) const { +/// Return true if this global address should be placed into small data/bss +/// section. +bool MipsTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const { + // We first check the case where global is a declaration, because finding + // section kind using getKindForGlobal() is only allowed for global + // definitions. if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) - return false; + return IsGlobalInSmallSectionImpl(GV, TM); return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); } -/// IsGlobalInSmallSection - Return true if this global address should be -/// placed into small data/bss section. +/// Return true if this global address should be placed into small data/bss +/// section. bool MipsTargetObjectFile:: IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, SectionKind Kind) const { + return (IsGlobalInSmallSectionImpl(GV, TM) && + (Kind.isDataRel() || Kind.isBSS() || Kind.isCommon())); +} +/// Return true if this global address should be placed into small data/bss +/// section. This method does all the work, except for checking the section +/// kind. +bool MipsTargetObjectFile:: +IsGlobalInSmallSectionImpl(const GlobalValue *GV, + const TargetMachine &TM) const { const MipsSubtarget &Subtarget = TM.getSubtarget(); // Return if small section is not available. @@ -71,13 +99,13 @@ if (!GVA) return false; - // We can only do this for datarel or BSS objects for now. - if (!Kind.isBSS() && !Kind.isDataRel()) + // Enforce -mlocal-sdata. + if (!LocalSData && GV->hasLocalLinkage()) return false; - // If this is a internal constant string, there is a special - // section for it, but not in small data/bss. - if (Kind.isMergeable1ByteCString()) + // Enforce -mextern-sdata. + if (!ExternSData && ((GV->hasExternalLinkage() && GV->isDeclaration()) || + GV->hasCommonLinkage())) return false; Type *Ty = GV->getType()->getElementType(); @@ -85,8 +113,6 @@ TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(Ty)); } - - const MCSection *MipsTargetObjectFile:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const { @@ -96,9 +122,27 @@ // Handle Small Section classification here. if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) return SmallBSSSection; - if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind)) + if (Kind.isDataRel() && IsGlobalInSmallSection(GV, TM, Kind)) return SmallDataSection; // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); } + +/// Return true if this constant should be placed into small data section. +bool MipsTargetObjectFile:: +IsConstantInSmallSection(const Constant *CN, const TargetMachine &TM) const { + return (TM.getSubtarget().useSmallSection() && + LocalSData && + IsInSmallSection(TM.getSubtargetImpl()->getDataLayout() + ->getTypeAllocSize(CN->getType()))); +} + +const MCSection *MipsTargetObjectFile:: +getSectionForConstant(SectionKind Kind, const Constant *C) const { + if (IsConstantInSmallSection(C, *TM)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::getSectionForConstant(Kind, C); +} Index: llvm/trunk/test/CodeGen/Mips/small-section-reserve-gp.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/small-section-reserve-gp.ll +++ llvm/trunk/test/CodeGen/Mips/small-section-reserve-gp.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple=mipsel-sde-elf -march=mipsel -relocation-model=static < %s \ +; RUN: llc -mtriple=mipsel-sde-elf -march=mipsel -relocation-model=static -mattr=+noabicalls -mgpopt < %s \ ; RUN: | FileCheck %s @i = internal unnamed_addr global i32 0, align 4