[mips] Add the following MIPS options that control gp-relative addressing of

small data items: -mgpopt, -mlocal-sdata, -mextern-sdata. Implement gp-relative
addressing for constants.

Differential Revision: http://reviews.llvm.org/D4903


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221450 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sasa Stankovic 2014-11-06 13:20:12 +00:00
parent ea60f51d87
commit 2b8f96996b
6 changed files with 112 additions and 43 deletions

View File

@ -1693,8 +1693,6 @@ SDValue MipsTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const {
SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const { SelectionDAG &DAG) const {
// FIXME there isn't actually debug info here
SDLoc DL(Op);
EVT Ty = Op.getValueType(); EVT Ty = Op.getValueType();
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
const GlobalValue *GV = N->getGlobal(); const GlobalValue *GV = N->getGlobal();
@ -1704,15 +1702,9 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
const MipsTargetObjectFile &TLOF = const MipsTargetObjectFile &TLOF =
(const MipsTargetObjectFile&)getObjFileLowering(); (const MipsTargetObjectFile&)getObjFileLowering();
// %gp_rel relocation if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine()))
if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) { // %gp_rel relocation
SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, 0, return getAddrGPRel(N, Ty, DAG);
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);
}
// %hi/%lo relocation // %hi/%lo relocation
return getAddrNonPIC(N, Ty, DAG); return getAddrNonPIC(N, Ty, DAG);
@ -1843,21 +1835,20 @@ lowerJumpTable(SDValue Op, SelectionDAG &DAG) const
SDValue MipsTargetLowering:: SDValue MipsTargetLowering::
lowerConstantPool(SDValue Op, SelectionDAG &DAG) const 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<ConstantPoolSDNode>(Op); ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
EVT Ty = Op.getValueType(); EVT Ty = Op.getValueType();
if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && 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 getAddrNonPIC(N, Ty, DAG);
}
return getAddrLocal(N, Ty, DAG, return getAddrLocal(N, Ty, DAG,
Subtarget.isABI_N32() || Subtarget.isABI_N64()); Subtarget.isABI_N32() || Subtarget.isABI_N64());

View File

@ -331,6 +331,21 @@ namespace llvm {
DAG.getNode(MipsISD::Lo, DL, Ty, Lo)); 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<class NodeTy>
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 /// 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 /// be used when a function call node is created. It also generates
/// copyToReg nodes to set up argument registers. /// copyToReg nodes to set up argument registers.

View File

@ -58,6 +58,10 @@ Mips16ConstantIslands(
cl::desc("MIPS: mips16 constant islands enable."), cl::desc("MIPS: mips16 constant islands enable."),
cl::init(true)); cl::init(true));
static cl::opt<bool>
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. /// Select the Mips CPU for the given triple and cpu name.
/// FIXME: Merge with the copy in MipsMCTargetDesc.cpp /// FIXME: Merge with the copy in MipsMCTargetDesc.cpp
static StringRef selectMipsCPU(Triple TT, StringRef CPU) { static StringRef selectMipsCPU(Triple TT, StringRef CPU) {
@ -171,10 +175,16 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU,
if (TT.find("linux") == std::string::npos) if (TT.find("linux") == std::string::npos)
IsLinux = false; IsLinux = false;
if (NoABICalls && TM->getRelocationModel() == Reloc::PIC_)
report_fatal_error("position-independent code requires '-mabicalls'");
// Set UseSmallSection. // Set UseSmallSection.
// TODO: Investigate the IsLinux check. I suspect it's really checking for UseSmallSection = GPOpt;
// bare-metal. if (!NoABICalls && GPOpt) {
UseSmallSection = !IsLinux && (TM->getRelocationModel() == Reloc::Static); errs() << "warning: cannot use small-data accesses for '-mabicalls'"
<< "\n";
UseSmallSection = false;
}
} }
/// This overrides the PostRAScheduler bit in the SchedModel for any CPU. /// This overrides the PostRAScheduler bit in the SchedModel for any CPU.

View File

@ -24,6 +24,17 @@ SSThreshold("mips-ssection-threshold", cl::Hidden,
cl::desc("Small data and bss section threshold size (default=8)"), cl::desc("Small data and bss section threshold size (default=8)"),
cl::init(8)); cl::init(8));
static cl::opt<bool>
LocalSData("mlocal-sdata", cl::Hidden,
cl::desc("MIPS: Use gp_rel for object-local data."),
cl::init(true));
static cl::opt<bool>
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){ void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){
TargetLoweringObjectFileELF::Initialize(Ctx, TM); TargetLoweringObjectFileELF::Initialize(Ctx, TM);
InitializeELF(TM.Options.UseInitArray); InitializeELF(TM.Options.UseInitArray);
@ -37,29 +48,46 @@ void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){
getContext().getELFSection(".sbss", ELF::SHT_NOBITS, getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
ELF::SHF_WRITE |ELF::SHF_ALLOC, ELF::SHF_WRITE |ELF::SHF_ALLOC,
SectionKind::getBSS()); SectionKind::getBSS());
this->TM = &TM;
} }
// A address must be loaded from a small section if its size is less than the // 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 // small section size threshold. Data in this section must be addressed using
// gp_rel operator. // gp_rel operator.
static bool IsInSmallSection(uint64_t Size) { 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; return Size > 0 && Size <= SSThreshold;
} }
bool MipsTargetObjectFile::IsGlobalInSmallSection(const GlobalValue *GV, /// Return true if this global address should be placed into small data/bss
const TargetMachine &TM) const { /// 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()) if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
return false; return IsGlobalInSmallSectionImpl(GV, TM);
return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM));
} }
/// IsGlobalInSmallSection - Return true if this global address should be /// Return true if this global address should be placed into small data/bss
/// placed into small data/bss section. /// section.
bool MipsTargetObjectFile:: bool MipsTargetObjectFile::
IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
SectionKind Kind) const { 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<MipsSubtarget>(); const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>();
// Return if small section is not available. // Return if small section is not available.
@ -71,13 +99,13 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
if (!GVA) if (!GVA)
return false; return false;
// We can only do this for datarel or BSS objects for now. // Enforce -mlocal-sdata.
if (!Kind.isBSS() && !Kind.isDataRel()) if (!LocalSData && GV->hasLocalLinkage())
return false; return false;
// If this is a internal constant string, there is a special // Enforce -mextern-sdata.
// section for it, but not in small data/bss. if (!ExternSData && ((GV->hasExternalLinkage() && GV->isDeclaration()) ||
if (Kind.isMergeable1ByteCString()) GV->hasCommonLinkage()))
return false; return false;
Type *Ty = GV->getType()->getElementType(); Type *Ty = GV->getType()->getElementType();
@ -85,8 +113,6 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(Ty)); TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(Ty));
} }
const MCSection *MipsTargetObjectFile:: const MCSection *MipsTargetObjectFile::
SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
Mangler &Mang, const TargetMachine &TM) const { Mangler &Mang, const TargetMachine &TM) const {
@ -96,9 +122,27 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
// Handle Small Section classification here. // Handle Small Section classification here.
if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind))
return SmallBSSSection; return SmallBSSSection;
if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind)) if (Kind.isDataRel() && IsGlobalInSmallSection(GV, TM, Kind))
return SmallDataSection; return SmallDataSection;
// Otherwise, we work the same as ELF. // Otherwise, we work the same as ELF.
return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); 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<MipsSubtarget>().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);
}

View File

@ -17,21 +17,30 @@ namespace llvm {
class MipsTargetObjectFile : public TargetLoweringObjectFileELF { class MipsTargetObjectFile : public TargetLoweringObjectFileELF {
const MCSection *SmallDataSection; const MCSection *SmallDataSection;
const MCSection *SmallBSSSection; const MCSection *SmallBSSSection;
const TargetMachine *TM;
public: public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override; void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
/// Return true if this global address should be placed into small data/bss
/// IsGlobalInSmallSection - Return true if this global address should be /// section.
/// placed into small data/bss section. bool IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
bool IsGlobalInSmallSection(const GlobalValue *GV, SectionKind Kind) const;
const TargetMachine &TM, SectionKind Kind)const;
bool IsGlobalInSmallSection(const GlobalValue *GV, bool IsGlobalInSmallSection(const GlobalValue *GV,
const TargetMachine &TM) const; const TargetMachine &TM) const;
bool IsGlobalInSmallSectionImpl(const GlobalValue *GV,
const TargetMachine &TM) const;
const MCSection *SelectSectionForGlobal(const GlobalValue *GV, const MCSection *SelectSectionForGlobal(const GlobalValue *GV,
SectionKind Kind, Mangler &Mang, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM) const override; 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 } // end namespace llvm

View File

@ -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 ; RUN: | FileCheck %s
@i = internal unnamed_addr global i32 0, align 4 @i = internal unnamed_addr global i32 0, align 4