1//===-- ARMSubtarget.cpp - ARM Subtarget Information ----------------------===//
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// This file implements the ARM specific subclass of TargetSubtargetInfo.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ARMSubtarget.h"
15#include "ARMBaseInstrInfo.h"
16#include "ARMBaseRegisterInfo.h"
17#include "llvm/IR/Attributes.h"
18#include "llvm/IR/GlobalValue.h"
19#include "llvm/IR/Function.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Target/TargetInstrInfo.h"
22#include "llvm/Target/TargetOptions.h"
23
24#define GET_SUBTARGETINFO_TARGET_DESC
25#define GET_SUBTARGETINFO_CTOR
26#include "ARMGenSubtargetInfo.inc"
27
28using namespace llvm;
29
30cl::opt<bool>
31ReserveR9("arm-reserve-r9", cl::Hidden,
32          cl::desc("Reserve R9, making it unavailable as GPR"));
33
34static cl::opt<bool>
35DarwinUseMOVT("arm-darwin-use-movt", cl::init(true), cl::Hidden);
36
37static cl::opt<bool>
38UseFusedMulOps("arm-use-mulops",
39               cl::init(true), cl::Hidden);
40
41enum AlignMode {
42  DefaultAlign,
43  StrictAlign,
44  NoStrictAlign
45};
46
47static cl::opt<AlignMode>
48Align(cl::desc("Load/store alignment support"),
49      cl::Hidden, cl::init(DefaultAlign),
50      cl::values(
51          clEnumValN(DefaultAlign,  "arm-default-align",
52                     "Generate unaligned accesses only on hardware/OS "
53                     "combinations that are known to support them"),
54          clEnumValN(StrictAlign,   "arm-strict-align",
55                     "Disallow all unaligned memory accesses"),
56          clEnumValN(NoStrictAlign, "arm-no-strict-align",
57                     "Allow unaligned memory accesses"),
58          clEnumValEnd));
59
60ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU,
61                           const std::string &FS, const TargetOptions &Options)
62  : ARMGenSubtargetInfo(TT, CPU, FS)
63  , ARMProcFamily(Others)
64  , stackAlignment(4)
65  , CPUString(CPU)
66  , TargetTriple(TT)
67  , Options(Options)
68  , TargetABI(ARM_ABI_APCS) {
69  initializeEnvironment();
70  resetSubtargetFeatures(CPU, FS);
71}
72
73void ARMSubtarget::initializeEnvironment() {
74  HasV4TOps = false;
75  HasV5TOps = false;
76  HasV5TEOps = false;
77  HasV6Ops = false;
78  HasV6T2Ops = false;
79  HasV7Ops = false;
80  HasV8Ops = false;
81  HasVFPv2 = false;
82  HasVFPv3 = false;
83  HasVFPv4 = false;
84  HasV8FP = false;
85  HasNEON = false;
86  UseNEONForSinglePrecisionFP = false;
87  UseMulOps = UseFusedMulOps;
88  SlowFPVMLx = false;
89  HasVMLxForwarding = false;
90  SlowFPBrcc = false;
91  InThumbMode = false;
92  HasThumb2 = false;
93  IsMClass = false;
94  NoARM = false;
95  PostRAScheduler = false;
96  IsR9Reserved = ReserveR9;
97  UseMovt = false;
98  SupportsTailCall = false;
99  HasFP16 = false;
100  HasD16 = false;
101  HasHardwareDivide = false;
102  HasHardwareDivideInARM = false;
103  HasT2ExtractPack = false;
104  HasDataBarrier = false;
105  Pref32BitThumb = false;
106  AvoidCPSRPartialUpdate = false;
107  AvoidMOVsShifterOperand = false;
108  HasRAS = false;
109  HasMPExtension = false;
110  FPOnlySP = false;
111  HasPerfMon = false;
112  HasTrustZone = false;
113  AllowsUnalignedMem = false;
114  Thumb2DSP = false;
115  UseNaClTrap = false;
116  UnsafeFPMath = false;
117}
118
119void ARMSubtarget::resetSubtargetFeatures(const MachineFunction *MF) {
120  AttributeSet FnAttrs = MF->getFunction()->getAttributes();
121  Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex,
122                                           "target-cpu");
123  Attribute FSAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex,
124                                          "target-features");
125  std::string CPU =
126    !CPUAttr.hasAttribute(Attribute::None) ?CPUAttr.getValueAsString() : "";
127  std::string FS =
128    !FSAttr.hasAttribute(Attribute::None) ? FSAttr.getValueAsString() : "";
129  if (!FS.empty()) {
130    initializeEnvironment();
131    resetSubtargetFeatures(CPU, FS);
132  }
133}
134
135void ARMSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) {
136  if (CPUString.empty())
137    CPUString = "generic";
138
139  // Insert the architecture feature derived from the target triple into the
140  // feature string. This is important for setting features that are implied
141  // based on the architecture version.
142  std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple.getTriple(),
143                                              CPUString);
144  if (!FS.empty()) {
145    if (!ArchFS.empty())
146      ArchFS = ArchFS + "," + FS.str();
147    else
148      ArchFS = FS;
149  }
150  ParseSubtargetFeatures(CPUString, ArchFS);
151
152  // Thumb2 implies at least V6T2. FIXME: Fix tests to explicitly specify a
153  // ARM version or CPU and then remove this.
154  if (!HasV6T2Ops && hasThumb2())
155    HasV4TOps = HasV5TOps = HasV5TEOps = HasV6Ops = HasV6T2Ops = true;
156
157  // Keep a pointer to static instruction cost data for the specified CPU.
158  SchedModel = getSchedModelForCPU(CPUString);
159
160  // Initialize scheduling itinerary for the specified CPU.
161  InstrItins = getInstrItineraryForCPU(CPUString);
162
163  if ((TargetTriple.getTriple().find("eabi") != std::string::npos) ||
164      (isTargetIOS() && isMClass()))
165    // FIXME: We might want to separate AAPCS and EABI. Some systems, e.g.
166    // Darwin-EABI conforms to AACPS but not the rest of EABI.
167    TargetABI = ARM_ABI_AAPCS;
168
169  if (isAAPCS_ABI())
170    stackAlignment = 8;
171
172  if (!isTargetIOS())
173    UseMovt = hasV6T2Ops();
174  else {
175    IsR9Reserved = ReserveR9 | !HasV6Ops;
176    UseMovt = DarwinUseMOVT && hasV6T2Ops();
177    SupportsTailCall = !getTargetTriple().isOSVersionLT(5, 0);
178  }
179
180  if (!isThumb() || hasThumb2())
181    PostRAScheduler = true;
182
183  switch (Align) {
184    case DefaultAlign:
185      // Assume pre-ARMv6 doesn't support unaligned accesses.
186      //
187      // ARMv6 may or may not support unaligned accesses depending on the
188      // SCTLR.U bit, which is architecture-specific. We assume ARMv6
189      // Darwin targets support unaligned accesses, and others don't.
190      //
191      // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
192      // which raises an alignment fault on unaligned accesses. Linux
193      // defaults this bit to 0 and handles it as a system-wide (not
194      // per-process) setting. It is therefore safe to assume that ARMv7+
195      // Linux targets support unaligned accesses. The same goes for NaCl.
196      //
197      // The above behavior is consistent with GCC.
198      AllowsUnalignedMem = (
199          (hasV7Ops() && (isTargetLinux() || isTargetNaCl())) ||
200          (hasV6Ops() && isTargetDarwin()));
201      break;
202    case StrictAlign:
203      AllowsUnalignedMem = false;
204      break;
205    case NoStrictAlign:
206      AllowsUnalignedMem = true;
207      break;
208  }
209
210  // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default.
211  uint64_t Bits = getFeatureBits();
212  if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters
213      (Options.UnsafeFPMath || isTargetDarwin()))
214    UseNEONForSinglePrecisionFP = true;
215}
216
217/// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol.
218bool
219ARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV,
220                                 Reloc::Model RelocM) const {
221  if (RelocM == Reloc::Static)
222    return false;
223
224  // Materializable GVs (in JIT lazy compilation mode) do not require an extra
225  // load from stub.
226  bool isDecl = GV->hasAvailableExternallyLinkage();
227  if (GV->isDeclaration() && !GV->isMaterializable())
228    isDecl = true;
229
230  if (!isTargetDarwin()) {
231    // Extra load is needed for all externally visible.
232    if (GV->hasLocalLinkage() || GV->hasHiddenVisibility())
233      return false;
234    return true;
235  } else {
236    if (RelocM == Reloc::PIC_) {
237      // If this is a strong reference to a definition, it is definitely not
238      // through a stub.
239      if (!isDecl && !GV->isWeakForLinker())
240        return false;
241
242      // Unless we have a symbol with hidden visibility, we have to go through a
243      // normal $non_lazy_ptr stub because this symbol might be resolved late.
244      if (!GV->hasHiddenVisibility())  // Non-hidden $non_lazy_ptr reference.
245        return true;
246
247      // If symbol visibility is hidden, we have a stub for common symbol
248      // references and external declarations.
249      if (isDecl || GV->hasCommonLinkage())
250        // Hidden $non_lazy_ptr reference.
251        return true;
252
253      return false;
254    } else {
255      // If this is a strong reference to a definition, it is definitely not
256      // through a stub.
257      if (!isDecl && !GV->isWeakForLinker())
258        return false;
259
260      // Unless we have a symbol with hidden visibility, we have to go through a
261      // normal $non_lazy_ptr stub because this symbol might be resolved late.
262      if (!GV->hasHiddenVisibility())  // Non-hidden $non_lazy_ptr reference.
263        return true;
264    }
265  }
266
267  return false;
268}
269
270unsigned ARMSubtarget::getMispredictionPenalty() const {
271  return SchedModel->MispredictPenalty;
272}
273
274bool ARMSubtarget::enablePostRAScheduler(
275           CodeGenOpt::Level OptLevel,
276           TargetSubtargetInfo::AntiDepBreakMode& Mode,
277           RegClassVector& CriticalPathRCs) const {
278  Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL;
279  CriticalPathRCs.clear();
280  CriticalPathRCs.push_back(&ARM::GPRRegClass);
281  return PostRAScheduler && OptLevel >= CodeGenOpt::Default;
282}
283