1dff0c46cSDimitry Andric //===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// 2f22ef01cSRoman Divacky // 3f22ef01cSRoman Divacky // The LLVM Compiler Infrastructure 4f22ef01cSRoman Divacky // 5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source 6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details. 7f22ef01cSRoman Divacky // 8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===// 9f22ef01cSRoman Divacky 10f22ef01cSRoman Divacky #include "MipsTargetObjectFile.h" 11f22ef01cSRoman Divacky #include "MipsSubtarget.h" 12ff0cc061SDimitry Andric #include "MipsTargetMachine.h" 13db17bf38SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 14139f7f9bSDimitry Andric #include "llvm/IR/DataLayout.h" 15139f7f9bSDimitry Andric #include "llvm/IR/DerivedTypes.h" 16139f7f9bSDimitry Andric #include "llvm/IR/GlobalVariable.h" 17f22ef01cSRoman Divacky #include "llvm/MC/MCContext.h" 18f22ef01cSRoman Divacky #include "llvm/MC/MCSectionELF.h" 19f22ef01cSRoman Divacky #include "llvm/Support/CommandLine.h" 20139f7f9bSDimitry Andric #include "llvm/Target/TargetMachine.h" 21f22ef01cSRoman Divacky using namespace llvm; 22f22ef01cSRoman Divacky 23f22ef01cSRoman Divacky static cl::opt<unsigned> 24f22ef01cSRoman Divacky SSThreshold("mips-ssection-threshold", cl::Hidden, 25f22ef01cSRoman Divacky cl::desc("Small data and bss section threshold size (default=8)"), 26f22ef01cSRoman Divacky cl::init(8)); 27f22ef01cSRoman Divacky 2839d628a0SDimitry Andric static cl::opt<bool> 2939d628a0SDimitry Andric LocalSData("mlocal-sdata", cl::Hidden, 3039d628a0SDimitry Andric cl::desc("MIPS: Use gp_rel for object-local data."), 3139d628a0SDimitry Andric cl::init(true)); 3239d628a0SDimitry Andric 3339d628a0SDimitry Andric static cl::opt<bool> 3439d628a0SDimitry Andric ExternSData("mextern-sdata", cl::Hidden, 3539d628a0SDimitry Andric cl::desc("MIPS: Use gp_rel for data that is not defined by the " 3639d628a0SDimitry Andric "current object."), 3739d628a0SDimitry Andric cl::init(true)); 3839d628a0SDimitry Andric 392cab237bSDimitry Andric static cl::opt<bool> 402cab237bSDimitry Andric EmbeddedData("membedded-data", cl::Hidden, 412cab237bSDimitry Andric cl::desc("MIPS: Try to allocate variables in the following" 422cab237bSDimitry Andric " sections if possible: .rodata, .sdata, .data ."), 432cab237bSDimitry Andric cl::init(false)); 442cab237bSDimitry Andric 45f22ef01cSRoman Divacky void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ 46f22ef01cSRoman Divacky TargetLoweringObjectFileELF::Initialize(Ctx, TM); 473861d79fSDimitry Andric InitializeELF(TM.Options.UseInitArray); 48f22ef01cSRoman Divacky 49ff0cc061SDimitry Andric SmallDataSection = getContext().getELFSection( 503ca95b02SDimitry Andric ".sdata", ELF::SHT_PROGBITS, 513ca95b02SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); 52f22ef01cSRoman Divacky 53ff0cc061SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 543ca95b02SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC | 553ca95b02SDimitry Andric ELF::SHF_MIPS_GPREL); 56ff0cc061SDimitry Andric this->TM = &static_cast<const MipsTargetMachine &>(TM); 57f22ef01cSRoman Divacky } 58f22ef01cSRoman Divacky 59f22ef01cSRoman Divacky // A address must be loaded from a small section if its size is less than the 60f22ef01cSRoman Divacky // small section size threshold. Data in this section must be addressed using 61f22ef01cSRoman Divacky // gp_rel operator. 62f22ef01cSRoman Divacky static bool IsInSmallSection(uint64_t Size) { 6339d628a0SDimitry Andric // gcc has traditionally not treated zero-sized objects as small data, so this 6439d628a0SDimitry Andric // is effectively part of the ABI. 65f22ef01cSRoman Divacky return Size > 0 && Size <= SSThreshold; 66f22ef01cSRoman Divacky } 67f22ef01cSRoman Divacky 6839d628a0SDimitry Andric /// Return true if this global address should be placed into small data/bss 6939d628a0SDimitry Andric /// section. 70d88c1a5aSDimitry Andric bool MipsTargetObjectFile::IsGlobalInSmallSection( 71d88c1a5aSDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 7239d628a0SDimitry Andric // We first check the case where global is a declaration, because finding 7339d628a0SDimitry Andric // section kind using getKindForGlobal() is only allowed for global 7439d628a0SDimitry Andric // definitions. 75d88c1a5aSDimitry Andric if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage()) 76d88c1a5aSDimitry Andric return IsGlobalInSmallSectionImpl(GO, TM); 77f22ef01cSRoman Divacky 78d88c1a5aSDimitry Andric return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM)); 79f22ef01cSRoman Divacky } 80f22ef01cSRoman Divacky 8139d628a0SDimitry Andric /// Return true if this global address should be placed into small data/bss 8239d628a0SDimitry Andric /// section. 83f22ef01cSRoman Divacky bool MipsTargetObjectFile:: 84d88c1a5aSDimitry Andric IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM, 85f22ef01cSRoman Divacky SectionKind Kind) const { 862cab237bSDimitry Andric return IsGlobalInSmallSectionImpl(GO, TM) && 872cab237bSDimitry Andric (Kind.isData() || Kind.isBSS() || Kind.isCommon() || 882cab237bSDimitry Andric Kind.isReadOnly()); 8939d628a0SDimitry Andric } 90f22ef01cSRoman Divacky 9139d628a0SDimitry Andric /// Return true if this global address should be placed into small data/bss 9239d628a0SDimitry Andric /// section. This method does all the work, except for checking the section 9339d628a0SDimitry Andric /// kind. 9439d628a0SDimitry Andric bool MipsTargetObjectFile:: 95d88c1a5aSDimitry Andric IsGlobalInSmallSectionImpl(const GlobalObject *GO, 9639d628a0SDimitry Andric const TargetMachine &TM) const { 97ff0cc061SDimitry Andric const MipsSubtarget &Subtarget = 98ff0cc061SDimitry Andric *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl(); 993861d79fSDimitry Andric 1003861d79fSDimitry Andric // Return if small section is not available. 1013861d79fSDimitry Andric if (!Subtarget.useSmallSection()) 102f22ef01cSRoman Divacky return false; 103f22ef01cSRoman Divacky 104f22ef01cSRoman Divacky // Only global variables, not functions. 105d88c1a5aSDimitry Andric const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 106f22ef01cSRoman Divacky if (!GVA) 107f22ef01cSRoman Divacky return false; 108f22ef01cSRoman Divacky 1092cab237bSDimitry Andric // If the variable has an explicit section, it is placed in that section but 1102cab237bSDimitry Andric // it's addressing mode may change. 1112cab237bSDimitry Andric if (GVA->hasSection()) { 1122cab237bSDimitry Andric StringRef Section = GVA->getSection(); 1132cab237bSDimitry Andric 1142cab237bSDimitry Andric // Explicitly placing any variable in the small data section overrides 1152cab237bSDimitry Andric // the global -G value. 1162cab237bSDimitry Andric if (Section == ".sdata" || Section == ".sbss") 1172cab237bSDimitry Andric return true; 1182cab237bSDimitry Andric 1192cab237bSDimitry Andric // Otherwise reject accessing it through the gp pointer. There are some 1202cab237bSDimitry Andric // historic cases which GCC doesn't appear to respect any more. These 1212cab237bSDimitry Andric // are .lit4, .lit8 and .srdata. For the moment reject these as well. 1222cab237bSDimitry Andric return false; 1232cab237bSDimitry Andric } 1242cab237bSDimitry Andric 12539d628a0SDimitry Andric // Enforce -mlocal-sdata. 126d88c1a5aSDimitry Andric if (!LocalSData && GVA->hasLocalLinkage()) 127f22ef01cSRoman Divacky return false; 128f22ef01cSRoman Divacky 12939d628a0SDimitry Andric // Enforce -mextern-sdata. 130d88c1a5aSDimitry Andric if (!ExternSData && ((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 131d88c1a5aSDimitry Andric GVA->hasCommonLinkage())) 132f22ef01cSRoman Divacky return false; 133f22ef01cSRoman Divacky 1342cab237bSDimitry Andric // Enforce -membedded-data. 1352cab237bSDimitry Andric if (EmbeddedData && GVA->isConstant()) 1362cab237bSDimitry Andric return false; 1372cab237bSDimitry Andric 138d88c1a5aSDimitry Andric Type *Ty = GVA->getValueType(); 1397d523365SDimitry Andric return IsInSmallSection( 140d88c1a5aSDimitry Andric GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 141f22ef01cSRoman Divacky } 142f22ef01cSRoman Divacky 143d88c1a5aSDimitry Andric MCSection *MipsTargetObjectFile::SelectSectionForGlobal( 144d88c1a5aSDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 145f22ef01cSRoman Divacky // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" 146f22ef01cSRoman Divacky // sections? 147f22ef01cSRoman Divacky 148f22ef01cSRoman Divacky // Handle Small Section classification here. 149d88c1a5aSDimitry Andric if (Kind.isBSS() && IsGlobalInSmallSection(GO, TM, Kind)) 150f22ef01cSRoman Divacky return SmallBSSSection; 151d88c1a5aSDimitry Andric if (Kind.isData() && IsGlobalInSmallSection(GO, TM, Kind)) 152f22ef01cSRoman Divacky return SmallDataSection; 1532cab237bSDimitry Andric if (Kind.isReadOnly() && IsGlobalInSmallSection(GO, TM, Kind)) 1542cab237bSDimitry Andric return SmallDataSection; 155f22ef01cSRoman Divacky 156f22ef01cSRoman Divacky // Otherwise, we work the same as ELF. 157d88c1a5aSDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 158f22ef01cSRoman Divacky } 15939d628a0SDimitry Andric 16039d628a0SDimitry Andric /// Return true if this constant should be placed into small data section. 1617d523365SDimitry Andric bool MipsTargetObjectFile::IsConstantInSmallSection( 1627d523365SDimitry Andric const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const { 163ff0cc061SDimitry Andric return (static_cast<const MipsTargetMachine &>(TM) 164ff0cc061SDimitry Andric .getSubtargetImpl() 165ff0cc061SDimitry Andric ->useSmallSection() && 1667d523365SDimitry Andric LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType()))); 16739d628a0SDimitry Andric } 16839d628a0SDimitry Andric 1697d523365SDimitry Andric /// Return true if this constant should be placed into small data section. 1703ca95b02SDimitry Andric MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL, 1713ca95b02SDimitry Andric SectionKind Kind, 1723ca95b02SDimitry Andric const Constant *C, 1733ca95b02SDimitry Andric unsigned &Align) const { 1747d523365SDimitry Andric if (IsConstantInSmallSection(DL, C, *TM)) 17539d628a0SDimitry Andric return SmallDataSection; 17639d628a0SDimitry Andric 17739d628a0SDimitry Andric // Otherwise, we work the same as ELF. 1783ca95b02SDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align); 17939d628a0SDimitry Andric } 180077e1117SDimitry Andric 181077e1117SDimitry Andric const MCExpr * 182077e1117SDimitry Andric MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const { 183077e1117SDimitry Andric const MCExpr *Expr = 184077e1117SDimitry Andric MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); 185077e1117SDimitry Andric return MCBinaryExpr::createAdd( 186077e1117SDimitry Andric Expr, MCConstantExpr::create(0x8000, getContext()), getContext()); 187077e1117SDimitry Andric } 188