diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp | 460 | 
1 files changed, 460 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp b/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp new file mode 100644 index 000000000000..cfc8ed813c92 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp @@ -0,0 +1,460 @@ +//===-- HexagonTargetObjectFile.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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/Module.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")); + +static cl::opt<bool> +    EmitJtInText("hexagon-emit-jt-text", cl::Hidden, cl::init(false), +                 cl::desc("Emit hexagon jump tables in function section")); + +static cl::opt<bool> +    EmitLutInText("hexagon-emit-lut-text", cl::Hidden, cl::init(false), +                 cl::desc("Emit hexagon lookup tables in function section")); + +// 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 {                                                                   \ +      LLVM_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); + +  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 the lookup table is used by more than one function, do not place +  // it in text section. +  if (EmitLutInText && GO->getName().startswith("switch.table")) { +    if (const Function *Fn = getLutUsedFunction(GO)) +      return selectSectionForLookupTable(GO, TM, Fn); +  } + +  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 { +  bool HaveSData = isSmallDataEnabled(TM); +  if (!HaveSData) +    LLVM_DEBUG(dbgs() << "Small-data allocation is disabled, but symbols " +                         "may have explicit section assignments...\n"); +  // Only global variables, not functions. +  LLVM_DEBUG(dbgs() << "Checking if value is in small-data, -G" +                    << SmallDataThreshold << ": \"" << GO->getName() << "\": "); +  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO); +  if (!GVar) { +    LLVM_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()); +    LLVM_DEBUG(dbgs() << (IsSmall ? "yes" : "no") +                      << ", has section: " << GVar->getSection() << '\n'); +    return IsSmall; +  } + +  // If sdata is disabled, stop the checks here. +  if (!HaveSData) { +    LLVM_DEBUG(dbgs() << "no, small-data allocation is disabled\n"); +    return false; +  } + +  if (GVar->isConstant()) { +    LLVM_DEBUG(dbgs() << "no, is a constant\n"); +    return false; +  } + +  bool IsLocal = GVar->hasLocalLinkage(); +  if (!StaticsInSData && IsLocal) { +    LLVM_DEBUG(dbgs() << "no, is static\n"); +    return false; +  } + +  Type *GType = GVar->getValueType(); +  if (isa<ArrayType>(GType)) { +    LLVM_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()) { +      LLVM_DEBUG(dbgs() << "no, has opaque type\n"); +      return false; +    } +  } + +  unsigned Size = GVar->getParent()->getDataLayout().getTypeAllocSize(GType); +  if (Size == 0) { +    LLVM_DEBUG(dbgs() << "no, has size 0\n"); +    return false; +  } +  if (Size > SmallDataThreshold) { +    LLVM_DEBUG(dbgs() << "no, size exceeds sdata threshold: " << Size << '\n'); +    return false; +  } + +  LLVM_DEBUG(dbgs() << "yes\n"); +  return true; +} + +bool HexagonTargetObjectFile::isSmallDataEnabled(const TargetMachine &TM) +    const { +  return SmallDataThreshold > 0 && !TM.isPositionIndependent(); +} + +unsigned HexagonTargetObjectFile::getSmallDataSize() const { +  return SmallDataThreshold; +} + +bool HexagonTargetObjectFile::shouldPutJumpTableInFunctionSection( +    bool UsesLabelDifference, const Function &F) const { +  return EmitJtInText; +} + +/// 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::FixedVectorTyID: +  case Type::ScalableVectorTyID: { +    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::BFloatTyID: +  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->getValueType(); +  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); +} + +// Return the function that uses the lookup table. If there are more +// than one live function that uses this look table, bail out and place +// the lookup table in default section. +const Function * +HexagonTargetObjectFile::getLutUsedFunction(const GlobalObject *GO) const { +  const Function *ReturnFn = nullptr; +  for (auto U : GO->users()) { +    // validate each instance of user to be a live function. +    auto *I = dyn_cast<Instruction>(U); +    if (!I) +      continue; +    auto *Bb = I->getParent(); +    if (!Bb) +      continue; +    auto *UserFn = Bb->getParent(); +    if (!ReturnFn) +      ReturnFn = UserFn; +    else if (ReturnFn != UserFn) +      return nullptr; +  } +  return ReturnFn; +} + +MCSection *HexagonTargetObjectFile::selectSectionForLookupTable( +    const GlobalObject *GO, const TargetMachine &TM, const Function *Fn) const { + +  SectionKind Kind = SectionKind::getText(); +  // If the function has explicit section, place the lookup table in this +  // explicit section. +  if (Fn->hasSection()) +    return getExplicitSectionGlobal(Fn, Kind, TM); + +  const auto *FuncObj = dyn_cast<GlobalObject>(Fn); +  return SelectSectionForGlobal(FuncObj, Kind, TM); +}  | 
