forked from OSchip/llvm-project
[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:
parent
9760a44d1a
commit
b38db1eff8
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue