10b57cec5SDimitry Andric // 20b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 30b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 40b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 50b57cec5SDimitry Andric // 60b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 70b57cec5SDimitry Andric 80b57cec5SDimitry Andric #include "LanaiTargetObjectFile.h" 90b57cec5SDimitry Andric 100b57cec5SDimitry Andric #include "LanaiSubtarget.h" 110b57cec5SDimitry Andric #include "LanaiTargetMachine.h" 120b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 130b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 140b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 150b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 180b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 190b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric static cl::opt<unsigned> SSThreshold( 240b57cec5SDimitry Andric "lanai-ssection-threshold", cl::Hidden, 250b57cec5SDimitry Andric cl::desc("Small data and bss section threshold size (default=0)"), 260b57cec5SDimitry Andric cl::init(0)); 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric void LanaiTargetObjectFile::Initialize(MCContext &Ctx, 290b57cec5SDimitry Andric const TargetMachine &TM) { 300b57cec5SDimitry Andric TargetLoweringObjectFileELF::Initialize(Ctx, TM); 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric SmallDataSection = getContext().getELFSection( 330b57cec5SDimitry Andric ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 340b57cec5SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 350b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC); 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric // A address must be loaded from a small section if its size is less than the 390b57cec5SDimitry Andric // small section size threshold. Data in this section must be addressed using 400b57cec5SDimitry Andric // gp_rel operator. 410b57cec5SDimitry Andric static bool isInSmallSection(uint64_t Size) { 420b57cec5SDimitry Andric // gcc has traditionally not treated zero-sized objects as small data, so this 430b57cec5SDimitry Andric // is effectively part of the ABI. 440b57cec5SDimitry Andric return Size > 0 && Size <= SSThreshold; 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 480b57cec5SDimitry Andric // section. 490b57cec5SDimitry Andric bool LanaiTargetObjectFile::isGlobalInSmallSection( 500b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 510b57cec5SDimitry Andric if (GO == nullptr) return TM.getCodeModel() == CodeModel::Small; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // We first check the case where global is a declaration, because finding 540b57cec5SDimitry Andric // section kind using getKindForGlobal() is only allowed for global 550b57cec5SDimitry Andric // definitions. 560b57cec5SDimitry Andric if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage()) 570b57cec5SDimitry Andric return isGlobalInSmallSectionImpl(GO, TM); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric return isGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM)); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 630b57cec5SDimitry Andric // section. 640b57cec5SDimitry Andric bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO, 650b57cec5SDimitry Andric const TargetMachine &TM, 660b57cec5SDimitry Andric SectionKind Kind) const { 670b57cec5SDimitry Andric return isGlobalInSmallSectionImpl(GO, TM); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 710b57cec5SDimitry Andric // section. This method does all the work, except for checking the section 720b57cec5SDimitry Andric // kind. 730b57cec5SDimitry Andric bool LanaiTargetObjectFile::isGlobalInSmallSectionImpl( 740b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 750b57cec5SDimitry Andric const auto *GVA = dyn_cast<GlobalVariable>(GO); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // If not a GlobalVariable, only consider the code model. 780b57cec5SDimitry Andric if (!GVA) return TM.getCodeModel() == CodeModel::Small; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // Global values placed in sections starting with .ldata do not fit in 810b57cec5SDimitry Andric // 21-bits, so always use large memory access for them. FIXME: This is a 820b57cec5SDimitry Andric // workaround for a tool limitation. 83*5f757f3fSDimitry Andric if (GVA->getSection().starts_with(".ldata")) 840b57cec5SDimitry Andric return false; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric if (TM.getCodeModel() == CodeModel::Small) 870b57cec5SDimitry Andric return true; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric if (GVA->hasLocalLinkage()) 900b57cec5SDimitry Andric return false; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 930b57cec5SDimitry Andric GVA->hasCommonLinkage())) 940b57cec5SDimitry Andric return false; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric Type *Ty = GVA->getValueType(); 970b57cec5SDimitry Andric return isInSmallSection( 980b57cec5SDimitry Andric GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric MCSection *LanaiTargetObjectFile::SelectSectionForGlobal( 1020b57cec5SDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 1030b57cec5SDimitry Andric // Handle Small Section classification here. 1040b57cec5SDimitry Andric if (Kind.isBSS() && isGlobalInSmallSection(GO, TM, Kind)) 1050b57cec5SDimitry Andric return SmallBSSSection; 1060b57cec5SDimitry Andric if (Kind.isData() && isGlobalInSmallSection(GO, TM, Kind)) 1070b57cec5SDimitry Andric return SmallDataSection; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1100b57cec5SDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1140b57cec5SDimitry Andric bool LanaiTargetObjectFile::isConstantInSmallSection(const DataLayout &DL, 1150b57cec5SDimitry Andric const Constant *CN) const { 1160b57cec5SDimitry Andric return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1195ffd83dbSDimitry Andric MCSection *LanaiTargetObjectFile::getSectionForConstant( 1205ffd83dbSDimitry Andric const DataLayout &DL, SectionKind Kind, const Constant *C, 1215ffd83dbSDimitry Andric Align &Alignment) const { 1220b57cec5SDimitry Andric if (isConstantInSmallSection(DL, C)) 1230b57cec5SDimitry Andric return SmallDataSection; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1265ffd83dbSDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 1275ffd83dbSDimitry Andric Alignment); 1280b57cec5SDimitry Andric } 129