xref: /llvm-project/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp (revision ed8019d9fbed2e6a6b08f8f73e9fa54a24f3ed52)
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 
8 #include "LanaiTargetObjectFile.h"
9 
10 #include "llvm/BinaryFormat/ELF.h"
11 #include "llvm/IR/DataLayout.h"
12 #include "llvm/IR/GlobalVariable.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCSectionELF.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Target/TargetMachine.h"
17 
18 using namespace llvm;
19 
20 static cl::opt<unsigned> SSThreshold(
21     "lanai-ssection-threshold", cl::Hidden,
22     cl::desc("Small data and bss section threshold size (default=0)"),
23     cl::init(0));
24 
25 void LanaiTargetObjectFile::Initialize(MCContext &Ctx,
26                                        const TargetMachine &TM) {
27   TargetLoweringObjectFileELF::Initialize(Ctx, TM);
28 
29   SmallDataSection = getContext().getELFSection(
30       ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC);
31   SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
32                                                ELF::SHF_WRITE | ELF::SHF_ALLOC);
33 }
34 
35 // A address must be loaded from a small section if its size is less than the
36 // small section size threshold. Data in this section must be addressed using
37 // gp_rel operator.
38 static bool isInSmallSection(uint64_t Size) {
39   // gcc has traditionally not treated zero-sized objects as small data, so this
40   // is effectively part of the ABI.
41   return Size > 0 && Size <= SSThreshold;
42 }
43 
44 // Return true if this global address should be placed into small data/bss
45 // section.
46 bool LanaiTargetObjectFile::isGlobalInSmallSection(
47     const GlobalObject *GO, const TargetMachine &TM) const {
48   if (GO == nullptr) return TM.getCodeModel() == CodeModel::Small;
49 
50   // We first check the case where global is a declaration, because finding
51   // section kind using getKindForGlobal() is only allowed for global
52   // definitions.
53   if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage())
54     return isGlobalInSmallSectionImpl(GO, TM);
55 
56   return isGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM));
57 }
58 
59 // Return true if this global address should be placed into small data/bss
60 // section.
61 bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO,
62                                                    const TargetMachine &TM,
63                                                    SectionKind Kind) const {
64   return isGlobalInSmallSectionImpl(GO, TM);
65 }
66 
67 // Return true if this global address should be placed into small data/bss
68 // section. This method does all the work, except for checking the section
69 // kind.
70 bool LanaiTargetObjectFile::isGlobalInSmallSectionImpl(
71     const GlobalObject *GO, const TargetMachine &TM) const {
72   const auto *GVA = dyn_cast<GlobalVariable>(GO);
73 
74   // If not a GlobalVariable, only consider the code model.
75   if (!GVA) return TM.getCodeModel() == CodeModel::Small;
76 
77   // Global values placed in sections starting with .ldata do not fit in
78   // 21-bits, so always use large memory access for them. FIXME: This is a
79   // workaround for a tool limitation.
80   if (GVA->getSection().starts_with(".ldata"))
81     return false;
82 
83   if (TM.getCodeModel() == CodeModel::Small)
84     return true;
85 
86   if (GVA->hasLocalLinkage())
87     return false;
88 
89   if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
90        GVA->hasCommonLinkage()))
91     return false;
92 
93   Type *Ty = GVA->getValueType();
94   return isInSmallSection(
95       GVA->getDataLayout().getTypeAllocSize(Ty));
96 }
97 
98 MCSection *LanaiTargetObjectFile::SelectSectionForGlobal(
99     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
100   // Handle Small Section classification here.
101   if (Kind.isBSS() && isGlobalInSmallSection(GO, TM, Kind))
102     return SmallBSSSection;
103   if (Kind.isData() && isGlobalInSmallSection(GO, TM, Kind))
104     return SmallDataSection;
105 
106   // Otherwise, we work the same as ELF.
107   return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
108 }
109 
110 /// Return true if this constant should be placed into small data section.
111 bool LanaiTargetObjectFile::isConstantInSmallSection(const DataLayout &DL,
112                                                      const Constant *CN) const {
113   return isInSmallSection(DL.getTypeAllocSize(CN->getType()));
114 }
115 
116 MCSection *LanaiTargetObjectFile::getSectionForConstant(
117     const DataLayout &DL, SectionKind Kind, const Constant *C,
118     Align &Alignment) const {
119   if (isConstantInSmallSection(DL, C))
120     return SmallDataSection;
121 
122   // Otherwise, we work the same as ELF.
123   return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C,
124                                                             Alignment);
125 }
126