Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===//
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "MipsTargetObjectFile.h"
10
#include "MipsSubtarget.h"
11
#include "MipsTargetMachine.h"
12
#include "MCTargetDesc/MipsMCExpr.h"
13
#include "llvm/BinaryFormat/ELF.h"
14
#include "llvm/IR/DataLayout.h"
15
#include "llvm/IR/DerivedTypes.h"
16
#include "llvm/IR/GlobalVariable.h"
17
#include "llvm/MC/MCContext.h"
18
#include "llvm/MC/MCSectionELF.h"
19
#include "llvm/Support/CommandLine.h"
20
#include "llvm/Target/TargetMachine.h"
21
using namespace llvm;
22
23
static cl::opt<unsigned>
24
SSThreshold("mips-ssection-threshold", cl::Hidden,
25
            cl::desc("Small data and bss section threshold size (default=8)"),
26
            cl::init(8));
27
28
static cl::opt<bool>
29
LocalSData("mlocal-sdata", cl::Hidden,
30
           cl::desc("MIPS: Use gp_rel for object-local data."),
31
           cl::init(true));
32
33
static cl::opt<bool>
34
ExternSData("mextern-sdata", cl::Hidden,
35
            cl::desc("MIPS: Use gp_rel for data that is not defined by the "
36
                     "current object."),
37
            cl::init(true));
38
39
static cl::opt<bool>
40
EmbeddedData("membedded-data", cl::Hidden,
41
             cl::desc("MIPS: Try to allocate variables in the following"
42
                      " sections if possible: .rodata, .sdata, .data ."),
43
             cl::init(false));
44
45
2.01k
void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){
46
2.01k
  TargetLoweringObjectFileELF::Initialize(Ctx, TM);
47
2.01k
  InitializeELF(TM.Options.UseInitArray);
48
2.01k
49
2.01k
  SmallDataSection = getContext().getELFSection(
50
2.01k
      ".sdata", ELF::SHT_PROGBITS,
51
2.01k
      ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL);
52
2.01k
53
2.01k
  SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
54
2.01k
                                               ELF::SHF_WRITE | ELF::SHF_ALLOC |
55
2.01k
                                                   ELF::SHF_MIPS_GPREL);
56
2.01k
  this->TM = &static_cast<const MipsTargetMachine &>(TM);
57
2.01k
}
58
59
// A address must be loaded from a small section if its size is less than the
60
// small section size threshold. Data in this section must be addressed using
61
// gp_rel operator.
62
25
static bool IsInSmallSection(uint64_t Size) {
63
25
  // gcc has traditionally not treated zero-sized objects as small data, so this
64
25
  // is effectively part of the ABI.
65
25
  return Size > 0 && Size <= SSThreshold;
66
25
}
67
68
/// Return true if this global address should be placed into small data/bss
69
/// section.
70
bool MipsTargetObjectFile::IsGlobalInSmallSection(
71
3.57k
    const GlobalObject *GO, const TargetMachine &TM) const {
72
3.57k
  // We first check the case where global is a declaration, because finding
73
3.57k
  // section kind using getKindForGlobal() is only allowed for global
74
3.57k
  // definitions.
75
3.57k
  if (GO->isDeclaration() || 
GO->hasAvailableExternallyLinkage()3.30k
)
76
262
    return IsGlobalInSmallSectionImpl(GO, TM);
77
3.30k
78
3.30k
  return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM));
79
3.30k
}
80
81
/// Return true if this global address should be placed into small data/bss
82
/// section.
83
bool MipsTargetObjectFile::
84
IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM,
85
8.05k
                       SectionKind Kind) const {
86
8.05k
  return IsGlobalInSmallSectionImpl(GO, TM) &&
87
8.05k
         
(27
Kind.isData()27
||
Kind.isBSS()15
||
Kind.isCommon()8
||
88
27
          
Kind.isReadOnly()8
);
89
8.05k
}
90
91
/// Return true if this global address should be placed into small data/bss
92
/// section. This method does all the work, except for checking the section
93
/// kind.
94
bool MipsTargetObjectFile::
95
IsGlobalInSmallSectionImpl(const GlobalObject *GO,
96
8.31k
                           const TargetMachine &TM) const {
97
8.31k
  const MipsSubtarget &Subtarget =
98
8.31k
      *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl();
99
8.31k
100
8.31k
  // Return if small section is not available.
101
8.31k
  if (!Subtarget.useSmallSection())
102
8.28k
    return false;
103
31
104
31
  // Only global variables, not functions.
105
31
  const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO);
106
31
  if (!GVA)
107
0
    return false;
108
31
109
31
  // If the variable has an explicit section, it is placed in that section but
110
31
  // it's addressing mode may change.
111
31
  if (GVA->hasSection()) {
112
3
    StringRef Section = GVA->getSection();
113
3
114
3
    // Explicitly placing any variable in the small data section overrides
115
3
    // the global -G value.
116
3
    if (Section == ".sdata" || 
Section == ".sbss"2
)
117
2
      return true;
118
1
119
1
    // Otherwise reject accessing it through the gp pointer. There are some
120
1
    // historic cases which GCC doesn't appear to respect any more. These
121
1
    // are .lit4, .lit8 and .srdata. For the moment reject these as well.
122
1
    return false;
123
1
  }
124
28
125
28
  // Enforce -mlocal-sdata.
126
28
  if (!LocalSData && 
GVA->hasLocalLinkage()0
)
127
0
    return false;
128
28
129
28
  // Enforce -mextern-sdata.
130
28
  if (!ExternSData && 
(0
(0
GVA->hasExternalLinkage()0
&&
GVA->isDeclaration()0
) ||
131
0
                       GVA->hasCommonLinkage()))
132
0
    return false;
133
28
134
28
  // Enforce -membedded-data.
135
28
  if (EmbeddedData && 
GVA->isConstant()5
)
136
2
    return false;
137
26
138
26
  Type *Ty = GVA->getValueType();
139
26
140
26
  // It is possible that the type of the global is unsized, i.e. a declaration
141
26
  // of a extern struct. In this case don't presume it is in the small data
142
26
  // section. This happens e.g. when building the FreeBSD kernel.
143
26
  if (!Ty->isSized())
144
1
    return false;
145
25
146
25
  return IsInSmallSection(
147
25
      GVA->getParent()->getDataLayout().getTypeAllocSize(Ty));
148
25
}
149
150
MCSection *MipsTargetObjectFile::SelectSectionForGlobal(
151
17.9k
    const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
152
17.9k
  // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*"
153
17.9k
  // sections?
154
17.9k
155
17.9k
  // Handle Small Section classification here.
156
17.9k
  if (Kind.isBSS() && 
IsGlobalInSmallSection(GO, TM, Kind)1.89k
)
157
6
    return SmallBSSSection;
158
17.9k
  if (Kind.isData() && 
IsGlobalInSmallSection(GO, TM, Kind)2.62k
)
159
5
    return SmallDataSection;
160
17.9k
  if (Kind.isReadOnly() && 
IsGlobalInSmallSection(GO, TM, Kind)229
)
161
4
    return SmallDataSection;
162
17.9k
163
17.9k
  // Otherwise, we work the same as ELF.
164
17.9k
  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
165
17.9k
}
166
167
/// Return true if this constant should be placed into small data section.
168
bool MipsTargetObjectFile::IsConstantInSmallSection(
169
860
    const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const {
170
860
  return (static_cast<const MipsTargetMachine &>(TM)
171
860
              .getSubtargetImpl()
172
860
              ->useSmallSection() &&
173
860
          
LocalSData0
&&
IsInSmallSection(DL.getTypeAllocSize(CN->getType()))0
);
174
860
}
175
176
/// Return true if this constant should be placed into small data section.
177
MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL,
178
                                                       SectionKind Kind,
179
                                                       const Constant *C,
180
542
                                                       unsigned &Align) const {
181
542
  if (IsConstantInSmallSection(DL, C, *TM))
182
0
    return SmallDataSection;
183
542
184
542
  // Otherwise, we work the same as ELF.
185
542
  return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
186
542
}
187
188
const MCExpr *
189
6
MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
190
6
  const MCExpr *Expr =
191
6
      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
192
6
  Expr = MCBinaryExpr::createAdd(
193
6
      Expr, MCConstantExpr::create(0x8000, getContext()), getContext());
194
6
  return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL, Expr, getContext());
195
6
}