diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp')
| -rw-r--r-- | contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp | 395 | 
1 files changed, 395 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp new file mode 100644 index 000000000000..4dacb1501392 --- /dev/null +++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp @@ -0,0 +1,395 @@ +//===-- HexagonTargetObjectFile.cpp ---------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the HexagonTargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "hexagon-sdata" + +#include "HexagonTargetObjectFile.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalObject.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Type.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +static cl::opt<unsigned> SmallDataThreshold("hexagon-small-data-threshold", +  cl::init(8), cl::Hidden, +  cl::desc("The maximum size of an object in the sdata section")); + +static cl::opt<bool> NoSmallDataSorting("mno-sort-sda", cl::init(false), +  cl::Hidden, cl::desc("Disable small data sections sorting")); + +static cl::opt<bool> StaticsInSData("hexagon-statics-in-small-data", +  cl::init(false), cl::Hidden, cl::ZeroOrMore, +  cl::desc("Allow static variables in .sdata")); + +static cl::opt<bool> TraceGVPlacement("trace-gv-placement", +  cl::Hidden, cl::init(false), +  cl::desc("Trace global value placement")); + +// TraceGVPlacement controls messages for all builds. For builds with assertions +// (debug or release), messages are also controlled by the usual debug flags +// (e.g. -debug and -debug-only=globallayout) +#define TRACE_TO(s, X) s << X +#ifdef NDEBUG +#define TRACE(X)                                                               \ +  do {                                                                         \ +    if (TraceGVPlacement) {                                                    \ +      TRACE_TO(errs(), X);                                                     \ +    }                                                                          \ +  } while (false) +#else +#define TRACE(X)                                                               \ +  do {                                                                         \ +    if (TraceGVPlacement) {                                                    \ +      TRACE_TO(errs(), X);                                                     \ +    } else {                                                                   \ +      DEBUG(TRACE_TO(dbgs(), X));                                              \ +    }                                                                          \ +  } while (false) +#endif + +// Returns true if the section name is such that the symbol will be put +// in a small data section. +// For instance, global variables with section attributes such as ".sdata" +// ".sdata.*", ".sbss", and ".sbss.*" will go into small data. +static bool isSmallDataSection(StringRef Sec) { +  // sectionName is either ".sdata" or ".sbss". Looking for an exact match +  // obviates the need for checks for section names such as ".sdatafoo". +  if (Sec.equals(".sdata") || Sec.equals(".sbss") || Sec.equals(".scommon")) +    return true; +  // If either ".sdata." or ".sbss." is a substring of the section name +  // then put the symbol in small data. +  return Sec.find(".sdata.") != StringRef::npos || +         Sec.find(".sbss.") != StringRef::npos || +         Sec.find(".scommon.") != StringRef::npos; +} + +static const char *getSectionSuffixForSize(unsigned Size) { +  switch (Size) { +  default: +    return ""; +  case 1: +    return ".1"; +  case 2: +    return ".2"; +  case 4: +    return ".4"; +  case 8: +    return ".8"; +  } +} + +void HexagonTargetObjectFile::Initialize(MCContext &Ctx, +      const TargetMachine &TM) { +  TargetLoweringObjectFileELF::Initialize(Ctx, TM); +  InitializeELF(TM.Options.UseInitArray); + +  SmallDataSection = +    getContext().getELFSection(".sdata", ELF::SHT_PROGBITS, +                               ELF::SHF_WRITE | ELF::SHF_ALLOC | +                               ELF::SHF_HEX_GPREL); +  SmallBSSSection = +    getContext().getELFSection(".sbss", ELF::SHT_NOBITS, +                               ELF::SHF_WRITE | ELF::SHF_ALLOC | +                               ELF::SHF_HEX_GPREL); +} + +MCSection *HexagonTargetObjectFile::SelectSectionForGlobal( +    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { +  TRACE("[SelectSectionForGlobal] GO(" << GO->getName() << ") "); +  TRACE("input section(" << GO->getSection() << ") "); + +  TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "") +         << (GO->hasLocalLinkage() ? "local_linkage " : "") +         << (GO->hasInternalLinkage() ? "internal " : "") +         << (GO->hasExternalLinkage() ? "external " : "") +         << (GO->hasCommonLinkage() ? "common_linkage " : "") +         << (GO->hasCommonLinkage() ? "common " : "" ) +         << (Kind.isCommon() ? "kind_common " : "" ) +         << (Kind.isBSS() ? "kind_bss " : "" ) +         << (Kind.isBSSLocal() ? "kind_bss_local " : "" )); + +  if (isGlobalInSmallSection(GO, TM)) +    return selectSmallSectionForGlobal(GO, Kind, TM); + +  if (Kind.isCommon()) { +    // This is purely for LTO+Linker Script because commons don't really have a +    // section. However, the BitcodeSectionWriter pass will query for the +    // sections of commons (and the linker expects us to know their section) so +    // we'll return one here. +    return BSSSection; +  } + +  TRACE("default_ELF_section\n"); +  // Otherwise, we work the same as ELF. +  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); +} + +MCSection *HexagonTargetObjectFile::getExplicitSectionGlobal( +    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { +  TRACE("[getExplicitSectionGlobal] GO(" << GO->getName() << ") from(" +        << GO->getSection() << ") "); +  TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "") +         << (GO->hasLocalLinkage() ? "local_linkage " : "") +         << (GO->hasInternalLinkage() ? "internal " : "") +         << (GO->hasExternalLinkage() ? "external " : "") +         << (GO->hasCommonLinkage() ? "common_linkage " : "") +         << (GO->hasCommonLinkage() ? "common " : "" ) +         << (Kind.isCommon() ? "kind_common " : "" ) +         << (Kind.isBSS() ? "kind_bss " : "" ) +         << (Kind.isBSSLocal() ? "kind_bss_local " : "" )); + +  if (GO->hasSection()) { +    StringRef Section = GO->getSection(); +    if (Section.find(".access.text.group") != StringRef::npos) +      return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS, +                                        ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); +    if (Section.find(".access.data.group") != StringRef::npos) +      return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS, +                                        ELF::SHF_WRITE | ELF::SHF_ALLOC); +  } + +  if (isGlobalInSmallSection(GO, TM)) +    return selectSmallSectionForGlobal(GO, Kind, TM); + +  // Otherwise, we work the same as ELF. +  TRACE("default_ELF_section\n"); +  return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM); +} + +/// Return true if this global value should be placed into small data/bss +/// section. +bool HexagonTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO, +      const TargetMachine &TM) const { +  // Only global variables, not functions. +  DEBUG(dbgs() << "Checking if value is in small-data, -G" +               << SmallDataThreshold << ": \"" << GO->getName() << "\": "); +  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO); +  if (!GVar) { +    DEBUG(dbgs() << "no, not a global variable\n"); +    return false; +  } + +  // Globals with external linkage that have an original section set must be +  // emitted to that section, regardless of whether we would put them into +  // small data or not. This is how we can support mixing -G0/-G8 in LTO. +  if (GVar->hasSection()) { +    bool IsSmall = isSmallDataSection(GVar->getSection()); +    DEBUG(dbgs() << (IsSmall ? "yes" : "no") << ", has section: " +                 << GVar->getSection() << '\n'); +    return IsSmall; +  } + +  if (GVar->isConstant()) { +    DEBUG(dbgs() << "no, is a constant\n"); +    return false; +  } + +  bool IsLocal = GVar->hasLocalLinkage(); +  if (!StaticsInSData && IsLocal) { +    DEBUG(dbgs() << "no, is static\n"); +    return false; +  } + +  Type *GType = GVar->getType(); +  if (PointerType *PT = dyn_cast<PointerType>(GType)) +    GType = PT->getElementType(); + +  if (isa<ArrayType>(GType)) { +    DEBUG(dbgs() << "no, is an array\n"); +    return false; +  } + +  // If the type is a struct with no body provided, treat is conservatively. +  // There cannot be actual definitions of object of such a type in this CU +  // (only references), so assuming that they are not in sdata is safe. If +  // these objects end up in the sdata, the references will still be valid. +  if (StructType *ST = dyn_cast<StructType>(GType)) { +    if (ST->isOpaque()) { +      DEBUG(dbgs() << "no, has opaque type\n"); +      return false; +    } +  } + +  unsigned Size = GVar->getParent()->getDataLayout().getTypeAllocSize(GType); +  if (Size == 0) { +    DEBUG(dbgs() << "no, has size 0\n"); +    return false; +  } +  if (Size > SmallDataThreshold) { +    DEBUG(dbgs() << "no, size exceeds sdata threshold: " << Size << '\n'); +    return false; +  } + +  DEBUG(dbgs() << "yes\n"); +  return true; +} + +bool HexagonTargetObjectFile::isSmallDataEnabled() const { +  return SmallDataThreshold > 0; +} + +unsigned HexagonTargetObjectFile::getSmallDataSize() const { +  return SmallDataThreshold; +} + +/// Descends any type down to "elementary" components, +/// discovering the smallest addressable one. +/// If zero is returned, declaration will not be modified. +unsigned HexagonTargetObjectFile::getSmallestAddressableSize(const Type *Ty, +      const GlobalValue *GV, const TargetMachine &TM) const { +  // Assign the smallest element access size to the highest +  // value which assembler can handle. +  unsigned SmallestElement = 8; + +  if (!Ty) +    return 0; +  switch (Ty->getTypeID()) { +  case Type::StructTyID: { +    const StructType *STy = cast<const StructType>(Ty); +    for (auto &E : STy->elements()) { +      unsigned AtomicSize = getSmallestAddressableSize(E, GV, TM); +      if (AtomicSize < SmallestElement) +        SmallestElement = AtomicSize; +    } +    return (STy->getNumElements() == 0) ? 0 : SmallestElement; +  } +  case Type::ArrayTyID: { +    const ArrayType *ATy = cast<const ArrayType>(Ty); +    return getSmallestAddressableSize(ATy->getElementType(), GV, TM); +  } +  case Type::VectorTyID: { +    const VectorType *PTy = cast<const VectorType>(Ty); +    return getSmallestAddressableSize(PTy->getElementType(), GV, TM); +  } +  case Type::PointerTyID: +  case Type::HalfTyID: +  case Type::FloatTyID: +  case Type::DoubleTyID: +  case Type::IntegerTyID: { +    const DataLayout &DL = GV->getParent()->getDataLayout(); +    // It is unfortunate that DL's function take non-const Type*. +    return DL.getTypeAllocSize(const_cast<Type*>(Ty)); +  } +  case Type::FunctionTyID: +  case Type::VoidTyID: +  case Type::X86_FP80TyID: +  case Type::FP128TyID: +  case Type::PPC_FP128TyID: +  case Type::LabelTyID: +  case Type::MetadataTyID: +  case Type::X86_MMXTyID: +  case Type::TokenTyID: +    return 0; +  } + +  return 0; +} + +MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal( +    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { +  const Type *GTy = GO->getType()->getElementType(); +  unsigned Size = getSmallestAddressableSize(GTy, GO, TM); + +  // If we have -ffunction-section or -fdata-section then we should emit the +  // global value to a unique section specifically for it... even for sdata. +  bool EmitUniquedSection = TM.getDataSections(); + +  TRACE("Small data. Size(" << Size << ")"); +  // Handle Small Section classification here. +  if (Kind.isBSS() || Kind.isBSSLocal()) { +    // If -mno-sort-sda is not set, find out smallest accessible entity in +    // declaration and add it to the section name string. +    // Note. It does not track the actual usage of the value, only its de- +    // claration. Also, compiler adds explicit pad fields to some struct +    // declarations - they are currently counted towards smallest addres- +    // sable entity. +    if (NoSmallDataSorting) { +      TRACE(" default sbss\n"); +      return SmallBSSSection; +    } + +    StringRef Prefix(".sbss"); +    SmallString<128> Name(Prefix); +    Name.append(getSectionSuffixForSize(Size)); + +    if (EmitUniquedSection) { +      Name.append("."); +      Name.append(GO->getName()); +    } +    TRACE(" unique sbss(" << Name << ")\n"); +    return getContext().getELFSection(Name.str(), ELF::SHT_NOBITS, +                ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_HEX_GPREL); +  } + +  if (Kind.isCommon()) { +    // This is purely for LTO+Linker Script because commons don't really have a +    // section. However, the BitcodeSectionWriter pass will query for the +    // sections of commons (and the linker expects us to know their section) so +    // we'll return one here. +    if (NoSmallDataSorting) +      return BSSSection; + +    Twine Name = Twine(".scommon") + getSectionSuffixForSize(Size); +    TRACE(" small COMMON (" << Name << ")\n"); + +    return getContext().getELFSection(Name.str(), ELF::SHT_NOBITS, +                                      ELF::SHF_WRITE | ELF::SHF_ALLOC | +                                      ELF::SHF_HEX_GPREL); +  } + +  // We could have changed sdata object to a constant... in this +  // case the Kind could be wrong for it. +  if (Kind.isMergeableConst()) { +    TRACE(" const_object_as_data "); +    const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO); +    if (GVar->hasSection() && isSmallDataSection(GVar->getSection())) +      Kind = SectionKind::getData(); +  } + +  if (Kind.isData()) { +    if (NoSmallDataSorting) { +      TRACE(" default sdata\n"); +      return SmallDataSection; +    } + +    StringRef Prefix(".sdata"); +    SmallString<128> Name(Prefix); +    Name.append(getSectionSuffixForSize(Size)); + +    if (EmitUniquedSection) { +      Name.append("."); +      Name.append(GO->getName()); +    } +    TRACE(" unique sdata(" << Name << ")\n"); +    return getContext().getELFSection(Name.str(), ELF::SHT_PROGBITS, +                ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_HEX_GPREL); +  } + +  TRACE("default ELF section\n"); +  // Otherwise, we work the same as ELF. +  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); +}  | 
