brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.7 KiB · 0c1b0ae Raw
462 lines · cpp
1//===-- HexagonTargetObjectFile.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the declarations of the HexagonTargetAsmInfo properties.10//11//===----------------------------------------------------------------------===//12 13#include "HexagonTargetObjectFile.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/ADT/Twine.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/IR/DataLayout.h"19#include "llvm/IR/DerivedTypes.h"20#include "llvm/IR/GlobalObject.h"21#include "llvm/IR/GlobalValue.h"22#include "llvm/IR/GlobalVariable.h"23#include "llvm/IR/Module.h"24#include "llvm/IR/Type.h"25#include "llvm/MC/MCContext.h"26#include "llvm/MC/SectionKind.h"27#include "llvm/Support/Casting.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/Debug.h"30#include "llvm/Support/raw_ostream.h"31#include "llvm/Target/TargetMachine.h"32 33#define DEBUG_TYPE "hexagon-sdata"34 35using namespace llvm;36 37static cl::opt<unsigned> SmallDataThreshold("hexagon-small-data-threshold",38  cl::init(8), cl::Hidden,39  cl::desc("The maximum size of an object in the sdata section"));40 41static cl::opt<bool> NoSmallDataSorting("mno-sort-sda", cl::init(false),42  cl::Hidden, cl::desc("Disable small data sections sorting"));43 44static cl::opt<bool>45    StaticsInSData("hexagon-statics-in-small-data", cl::Hidden,46                   cl::desc("Allow static variables in .sdata"));47 48static cl::opt<bool> TraceGVPlacement("trace-gv-placement",49  cl::Hidden, cl::init(false),50  cl::desc("Trace global value placement"));51 52static cl::opt<bool>53    EmitJtInText("hexagon-emit-jt-text", cl::Hidden, cl::init(false),54                 cl::desc("Emit hexagon jump tables in function section"));55 56static cl::opt<bool>57    EmitLutInText("hexagon-emit-lut-text", cl::Hidden, cl::init(false),58                 cl::desc("Emit hexagon lookup tables in function section"));59 60// TraceGVPlacement controls messages for all builds. For builds with assertions61// (debug or release), messages are also controlled by the usual debug flags62// (e.g. -debug and -debug-only=globallayout)63#define TRACE_TO(s, X) s << X64#ifdef NDEBUG65#define TRACE(X)                                                               \66  do {                                                                         \67    if (TraceGVPlacement) {                                                    \68      TRACE_TO(errs(), X);                                                     \69    }                                                                          \70  } while (false)71#else72#define TRACE(X)                                                               \73  do {                                                                         \74    if (TraceGVPlacement) {                                                    \75      TRACE_TO(errs(), X);                                                     \76    } else {                                                                   \77      LLVM_DEBUG(TRACE_TO(dbgs(), X));                                         \78    }                                                                          \79  } while (false)80#endif81 82// Returns true if the section name is such that the symbol will be put83// in a small data section.84// For instance, global variables with section attributes such as ".sdata"85// ".sdata.*", ".sbss", and ".sbss.*" will go into small data.86static bool isSmallDataSection(StringRef Sec) {87  // sectionName is either ".sdata" or ".sbss". Looking for an exact match88  // obviates the need for checks for section names such as ".sdatafoo".89  if (Sec == ".sdata" || Sec == ".sbss" || Sec == ".scommon")90    return true;91  // If either ".sdata." or ".sbss." is a substring of the section name92  // then put the symbol in small data.93  return Sec.contains(".sdata.") || Sec.contains(".sbss.") ||94         Sec.contains(".scommon.");95}96 97static const char *getSectionSuffixForSize(unsigned Size) {98  switch (Size) {99  default:100    return "";101  case 1:102    return ".1";103  case 2:104    return ".2";105  case 4:106    return ".4";107  case 8:108    return ".8";109  }110}111 112void HexagonTargetObjectFile::Initialize(MCContext &Ctx,113      const TargetMachine &TM) {114  TargetLoweringObjectFileELF::Initialize(Ctx, TM);115 116  SmallDataSection =117    getContext().getELFSection(".sdata", ELF::SHT_PROGBITS,118                               ELF::SHF_WRITE | ELF::SHF_ALLOC |119                               ELF::SHF_HEX_GPREL);120  SmallBSSSection =121    getContext().getELFSection(".sbss", ELF::SHT_NOBITS,122                               ELF::SHF_WRITE | ELF::SHF_ALLOC |123                               ELF::SHF_HEX_GPREL);124}125 126MCSection *HexagonTargetObjectFile::SelectSectionForGlobal(127    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {128  TRACE("[SelectSectionForGlobal] GO(" << GO->getName() << ") ");129  TRACE("input section(" << GO->getSection() << ") ");130 131  TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "")132         << (GO->hasLocalLinkage() ? "local_linkage " : "")133         << (GO->hasInternalLinkage() ? "internal " : "")134         << (GO->hasExternalLinkage() ? "external " : "")135         << (GO->hasCommonLinkage() ? "common_linkage " : "")136         << (GO->hasCommonLinkage() ? "common " : "" )137         << (Kind.isCommon() ? "kind_common " : "" )138         << (Kind.isBSS() ? "kind_bss " : "" )139         << (Kind.isBSSLocal() ? "kind_bss_local " : "" ));140 141  // If the lookup table is used by more than one function, do not place142  // it in text section.143  if (EmitLutInText && GO->getName().starts_with("switch.table")) {144    if (const Function *Fn = getLutUsedFunction(GO))145      return selectSectionForLookupTable(GO, TM, Fn);146  }147 148  if (isGlobalInSmallSection(GO, TM))149    return selectSmallSectionForGlobal(GO, Kind, TM);150 151  if (Kind.isCommon()) {152    // This is purely for LTO+Linker Script because commons don't really have a153    // section. However, the BitcodeSectionWriter pass will query for the154    // sections of commons (and the linker expects us to know their section) so155    // we'll return one here.156    return BSSSection;157  }158 159  TRACE("default_ELF_section\n");160  // Otherwise, we work the same as ELF.161  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);162}163 164MCSection *HexagonTargetObjectFile::getExplicitSectionGlobal(165    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {166  TRACE("[getExplicitSectionGlobal] GO(" << GO->getName() << ") from("167        << GO->getSection() << ") ");168  TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "")169         << (GO->hasLocalLinkage() ? "local_linkage " : "")170         << (GO->hasInternalLinkage() ? "internal " : "")171         << (GO->hasExternalLinkage() ? "external " : "")172         << (GO->hasCommonLinkage() ? "common_linkage " : "")173         << (GO->hasCommonLinkage() ? "common " : "" )174         << (Kind.isCommon() ? "kind_common " : "" )175         << (Kind.isBSS() ? "kind_bss " : "" )176         << (Kind.isBSSLocal() ? "kind_bss_local " : "" ));177 178  if (GO->hasSection()) {179    StringRef Section = GO->getSection();180    if (Section.contains(".access.text.group"))181      return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS,182                                        ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);183    if (Section.contains(".access.data.group"))184      return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS,185                                        ELF::SHF_WRITE | ELF::SHF_ALLOC);186  }187 188  if (isGlobalInSmallSection(GO, TM))189    return selectSmallSectionForGlobal(GO, Kind, TM);190 191  // Otherwise, we work the same as ELF.192  TRACE("default_ELF_section\n");193  return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM);194}195 196/// Return true if this global value should be placed into small data/bss197/// section.198bool HexagonTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO,199      const TargetMachine &TM) const {200  bool HaveSData = isSmallDataEnabled(TM);201  if (!HaveSData)202    LLVM_DEBUG(dbgs() << "Small-data allocation is disabled, but symbols "203                         "may have explicit section assignments...\n");204  // Only global variables, not functions.205  LLVM_DEBUG(dbgs() << "Checking if value is in small-data, -G"206                    << SmallDataThreshold << ": \"" << GO->getName() << "\": ");207  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO);208  if (!GVar) {209    LLVM_DEBUG(dbgs() << "no, not a global variable\n");210    return false;211  }212 213  // Globals with external linkage that have an original section set must be214  // emitted to that section, regardless of whether we would put them into215  // small data or not. This is how we can support mixing -G0/-G8 in LTO.216  if (GVar->hasSection()) {217    bool IsSmall = isSmallDataSection(GVar->getSection());218    LLVM_DEBUG(dbgs() << (IsSmall ? "yes" : "no")219                      << ", has section: " << GVar->getSection() << '\n');220    return IsSmall;221  }222 223  // If sdata is disabled, stop the checks here.224  if (!HaveSData) {225    LLVM_DEBUG(dbgs() << "no, small-data allocation is disabled\n");226    return false;227  }228 229  if (GVar->isConstant()) {230    LLVM_DEBUG(dbgs() << "no, is a constant\n");231    return false;232  }233 234  bool IsLocal = GVar->hasLocalLinkage();235  if (!StaticsInSData && IsLocal) {236    LLVM_DEBUG(dbgs() << "no, is static\n");237    return false;238  }239 240  Type *GType = GVar->getValueType();241  if (isa<ArrayType>(GType)) {242    LLVM_DEBUG(dbgs() << "no, is an array\n");243    return false;244  }245 246  // If the type is a struct with no body provided, treat is conservatively.247  // There cannot be actual definitions of object of such a type in this CU248  // (only references), so assuming that they are not in sdata is safe. If249  // these objects end up in the sdata, the references will still be valid.250  if (StructType *ST = dyn_cast<StructType>(GType)) {251    if (ST->isOpaque()) {252      LLVM_DEBUG(dbgs() << "no, has opaque type\n");253      return false;254    }255  }256 257  unsigned Size = GVar->getDataLayout().getTypeAllocSize(GType);258  if (Size == 0) {259    LLVM_DEBUG(dbgs() << "no, has size 0\n");260    return false;261  }262  if (Size > SmallDataThreshold) {263    LLVM_DEBUG(dbgs() << "no, size exceeds sdata threshold: " << Size << '\n');264    return false;265  }266 267  LLVM_DEBUG(dbgs() << "yes\n");268  return true;269}270 271bool HexagonTargetObjectFile::isSmallDataEnabled(const TargetMachine &TM)272    const {273  return SmallDataThreshold > 0 && !TM.isPositionIndependent();274}275 276unsigned HexagonTargetObjectFile::getSmallDataSize() const {277  return SmallDataThreshold;278}279 280bool HexagonTargetObjectFile::shouldPutJumpTableInFunctionSection(281    bool UsesLabelDifference, const Function &F) const {282  return EmitJtInText;283}284 285/// Descends any type down to "elementary" components,286/// discovering the smallest addressable one.287/// If zero is returned, declaration will not be modified.288unsigned HexagonTargetObjectFile::getSmallestAddressableSize(const Type *Ty,289      const GlobalValue *GV, const TargetMachine &TM) const {290  // Assign the smallest element access size to the highest291  // value which assembler can handle.292  unsigned SmallestElement = 8;293 294  if (!Ty)295    return 0;296  switch (Ty->getTypeID()) {297  case Type::StructTyID: {298    const StructType *STy = cast<const StructType>(Ty);299    for (auto &E : STy->elements()) {300      unsigned AtomicSize = getSmallestAddressableSize(E, GV, TM);301      if (AtomicSize < SmallestElement)302        SmallestElement = AtomicSize;303    }304    return (STy->getNumElements() == 0) ? 0 : SmallestElement;305  }306  case Type::ArrayTyID: {307    const ArrayType *ATy = cast<const ArrayType>(Ty);308    return getSmallestAddressableSize(ATy->getElementType(), GV, TM);309  }310  case Type::FixedVectorTyID:311  case Type::ScalableVectorTyID: {312    const VectorType *PTy = cast<const VectorType>(Ty);313    return getSmallestAddressableSize(PTy->getElementType(), GV, TM);314  }315  case Type::PointerTyID:316  case Type::HalfTyID:317  case Type::FloatTyID:318  case Type::DoubleTyID:319  case Type::IntegerTyID: {320    const DataLayout &DL = GV->getDataLayout();321    // It is unfortunate that DL's function take non-const Type*.322    return DL.getTypeAllocSize(const_cast<Type*>(Ty));323  }324  case Type::FunctionTyID:325  case Type::VoidTyID:326  case Type::BFloatTyID:327  case Type::X86_FP80TyID:328  case Type::FP128TyID:329  case Type::PPC_FP128TyID:330  case Type::LabelTyID:331  case Type::MetadataTyID:332  case Type::X86_AMXTyID:333  case Type::TokenTyID:334  case Type::TypedPointerTyID:335  case Type::TargetExtTyID:336    return 0;337  }338 339  return 0;340}341 342MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(343    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {344  const Type *GTy = GO->getValueType();345  unsigned Size = getSmallestAddressableSize(GTy, GO, TM);346 347  // If we have -ffunction-section or -fdata-section then we should emit the348  // global value to a unique section specifically for it... even for sdata.349  bool EmitUniquedSection = TM.getDataSections();350 351  TRACE("Small data. Size(" << Size << ")");352  // Handle Small Section classification here.353  if (Kind.isBSS() || Kind.isBSSLocal()) {354    // If -mno-sort-sda is not set, find out smallest accessible entity in355    // declaration and add it to the section name string.356    // Note. It does not track the actual usage of the value, only its de-357    // claration. Also, compiler adds explicit pad fields to some struct358    // declarations - they are currently counted towards smallest addres-359    // sable entity.360    if (NoSmallDataSorting) {361      TRACE(" default sbss\n");362      return SmallBSSSection;363    }364 365    StringRef Prefix(".sbss");366    SmallString<128> Name(Prefix);367    Name.append(getSectionSuffixForSize(Size));368 369    if (EmitUniquedSection) {370      Name.append(".");371      Name.append(GO->getName());372    }373    TRACE(" unique sbss(" << Name << ")\n");374    return getContext().getELFSection(Name.str(), ELF::SHT_NOBITS,375                ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_HEX_GPREL);376  }377 378  if (Kind.isCommon()) {379    // This is purely for LTO+Linker Script because commons don't really have a380    // section. However, the BitcodeSectionWriter pass will query for the381    // sections of commons (and the linker expects us to know their section) so382    // we'll return one here.383    if (NoSmallDataSorting)384      return BSSSection;385 386    Twine Name = Twine(".scommon") + getSectionSuffixForSize(Size);387    TRACE(" small COMMON (" << Name << ")\n");388 389    return getContext().getELFSection(Name.str(), ELF::SHT_NOBITS,390                                      ELF::SHF_WRITE | ELF::SHF_ALLOC |391                                      ELF::SHF_HEX_GPREL);392  }393 394  // We could have changed sdata object to a constant... in this395  // case the Kind could be wrong for it.396  if (Kind.isMergeableConst()) {397    TRACE(" const_object_as_data ");398    const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO);399    if (GVar->hasSection() && isSmallDataSection(GVar->getSection()))400      Kind = SectionKind::getData();401  }402 403  if (Kind.isData()) {404    if (NoSmallDataSorting) {405      TRACE(" default sdata\n");406      return SmallDataSection;407    }408 409    StringRef Prefix(".sdata");410    SmallString<128> Name(Prefix);411    Name.append(getSectionSuffixForSize(Size));412 413    if (EmitUniquedSection) {414      Name.append(".");415      Name.append(GO->getName());416    }417    TRACE(" unique sdata(" << Name << ")\n");418    return getContext().getELFSection(Name.str(), ELF::SHT_PROGBITS,419                ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_HEX_GPREL);420  }421 422  TRACE("default ELF section\n");423  // Otherwise, we work the same as ELF.424  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);425}426 427// Return the function that uses the lookup table. If there are more428// than one live function that uses this look table, bail out and place429// the lookup table in default section.430const Function *431HexagonTargetObjectFile::getLutUsedFunction(const GlobalObject *GO) const {432  const Function *ReturnFn = nullptr;433  for (const auto *U : GO->users()) {434    // validate each instance of user to be a live function.435    auto *I = dyn_cast<Instruction>(U);436    if (!I)437      continue;438    auto *Bb = I->getParent();439    if (!Bb)440      continue;441    auto *UserFn = Bb->getParent();442    if (!ReturnFn)443      ReturnFn = UserFn;444    else if (ReturnFn != UserFn)445      return nullptr;446  }447  return ReturnFn;448}449 450MCSection *HexagonTargetObjectFile::selectSectionForLookupTable(451    const GlobalObject *GO, const TargetMachine &TM, const Function *Fn) const {452 453  SectionKind Kind = SectionKind::getText();454  // If the function has explicit section, place the lookup table in this455  // explicit section.456  if (Fn->hasSection())457    return getExplicitSectionGlobal(Fn, Kind, TM);458 459  const auto *FuncObj = dyn_cast<GlobalObject>(Fn);460  return SelectSectionForGlobal(FuncObj, Kind, TM);461}462