1//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MipsTargetObjectFile.h"
11#include "MipsSubtarget.h"
12#include "MipsTargetMachine.h"
13#include "llvm/IR/DataLayout.h"
14#include "llvm/IR/DerivedTypes.h"
15#include "llvm/IR/GlobalVariable.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCSectionELF.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/ELF.h"
20#include "llvm/Target/TargetMachine.h"
21using namespace llvm;
22
23static cl::opt<unsigned>
24SSThreshold("mips-ssection-threshold", cl::Hidden,
25            cl::desc("Small data and bss section threshold size (default=8)"),
26            cl::init(8));
27
28static cl::opt<bool>
29LocalSData("mlocal-sdata", cl::Hidden,
30           cl::desc("MIPS: Use gp_rel for object-local data."),
31           cl::init(true));
32
33static cl::opt<bool>
34ExternSData("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
39void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){
40  TargetLoweringObjectFileELF::Initialize(Ctx, TM);
41  InitializeELF(TM.Options.UseInitArray);
42
43  SmallDataSection = getContext().getELFSection(
44      ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC);
45
46  SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
47                                               ELF::SHF_WRITE | ELF::SHF_ALLOC);
48  this->TM = &static_cast<const MipsTargetMachine &>(TM);
49}
50
51// A address must be loaded from a small section if its size is less than the
52// small section size threshold. Data in this section must be addressed using
53// gp_rel operator.
54static bool IsInSmallSection(uint64_t Size) {
55  // gcc has traditionally not treated zero-sized objects as small data, so this
56  // is effectively part of the ABI.
57  return Size > 0 && Size <= SSThreshold;
58}
59
60/// Return true if this global address should be placed into small data/bss
61/// section.
62bool MipsTargetObjectFile::
63IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const {
64  // We first check the case where global is a declaration, because finding
65  // section kind using getKindForGlobal() is only allowed for global
66  // definitions.
67  if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
68    return IsGlobalInSmallSectionImpl(GV, TM);
69
70  return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM));
71}
72
73/// Return true if this global address should be placed into small data/bss
74/// section.
75bool MipsTargetObjectFile::
76IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
77                       SectionKind Kind) const {
78  return (IsGlobalInSmallSectionImpl(GV, TM) &&
79          (Kind.isData() || Kind.isBSS() || Kind.isCommon()));
80}
81
82/// Return true if this global address should be placed into small data/bss
83/// section. This method does all the work, except for checking the section
84/// kind.
85bool MipsTargetObjectFile::
86IsGlobalInSmallSectionImpl(const GlobalValue *GV,
87                           const TargetMachine &TM) const {
88  const MipsSubtarget &Subtarget =
89      *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl();
90
91  // Return if small section is not available.
92  if (!Subtarget.useSmallSection())
93    return false;
94
95  // Only global variables, not functions.
96  const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV);
97  if (!GVA)
98    return false;
99
100  // Enforce -mlocal-sdata.
101  if (!LocalSData && GV->hasLocalLinkage())
102    return false;
103
104  // Enforce -mextern-sdata.
105  if (!ExternSData && ((GV->hasExternalLinkage() && GV->isDeclaration()) ||
106                       GV->hasCommonLinkage()))
107    return false;
108
109  Type *Ty = GV->getType()->getElementType();
110  return IsInSmallSection(
111      GV->getParent()->getDataLayout().getTypeAllocSize(Ty));
112}
113
114MCSection *
115MipsTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
116                                             SectionKind Kind, Mangler &Mang,
117                                             const TargetMachine &TM) const {
118  // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*"
119  // sections?
120
121  // Handle Small Section classification here.
122  if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind))
123    return SmallBSSSection;
124  if (Kind.isData() && IsGlobalInSmallSection(GV, TM, Kind))
125    return SmallDataSection;
126
127  // Otherwise, we work the same as ELF.
128  return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM);
129}
130
131/// Return true if this constant should be placed into small data section.
132bool MipsTargetObjectFile::IsConstantInSmallSection(
133    const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const {
134  return (static_cast<const MipsTargetMachine &>(TM)
135              .getSubtargetImpl()
136              ->useSmallSection() &&
137          LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType())));
138}
139
140/// Return true if this constant should be placed into small data section.
141MCSection *MipsTargetObjectFile::getSectionForConstant(
142    const DataLayout &DL, SectionKind Kind, const Constant *C) const {
143  if (IsConstantInSmallSection(DL, C, *TM))
144    return SmallDataSection;
145
146  // Otherwise, we work the same as ELF.
147  return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C);
148}
149