[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

llvm-svn: 221450
This commit is contained in:
Sasa Stankovic 2014-11-06 13:20:12 +00:00
parent 9760a44d1a
commit b38db1eff8
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,
SelectionDAG &DAG) const {
// FIXME there isn't actually debug info here
SDLoc DL(Op);
EVT Ty = Op.getValueType();
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
const GlobalValue *GV = N->getGlobal();
@ -1704,15 +1702,9 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
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 @@ lowerJumpTable(SDValue Op, SelectionDAG &DAG) const
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<ConstantPoolSDNode>(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());

View File

@ -331,6 +331,21 @@ namespace llvm {
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
/// be used when a function call node is created. It also generates
/// copyToReg nodes to set up argument registers.

View File

@ -58,6 +58,10 @@ Mips16ConstantIslands(
cl::desc("MIPS: mips16 constant islands enable."),
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.
/// FIXME: Merge with the copy in MipsMCTargetDesc.cpp
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)
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.

View File

@ -24,6 +24,17 @@ SSThreshold("mips-ssection-threshold", cl::Hidden,
cl::desc("Small data and bss section threshold size (default=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){
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
InitializeELF(TM.Options.UseInitArray);
@ -37,29 +48,46 @@ void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){
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<MipsSubtarget>();
// Return if small section is not available.
@ -71,13 +99,13 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
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 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(Ty));
}
const MCSection *MipsTargetObjectFile::
SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
Mangler &Mang, const TargetMachine &TM) const {
@ -96,9 +122,27 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
// 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<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 {
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

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
@i = internal unnamed_addr global i32 0, align 4