1234353Sdim//===-- ARMSubtarget.cpp - ARM Subtarget Information ----------------------===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10224145Sdim// This file implements the ARM specific subclass of TargetSubtargetInfo.
11193323Sed//
12193323Sed//===----------------------------------------------------------------------===//
13193323Sed
14193323Sed#include "ARMSubtarget.h"
15249423Sdim#include "ARMBaseInstrInfo.h"
16218893Sdim#include "ARMBaseRegisterInfo.h"
17249423Sdim#include "llvm/IR/Attributes.h"
18249423Sdim#include "llvm/IR/GlobalValue.h"
19249423Sdim#include "llvm/IR/Function.h"
20249423Sdim#include "llvm/Support/CommandLine.h"
21243830Sdim#include "llvm/Target/TargetInstrInfo.h"
22249423Sdim#include "llvm/Target/TargetOptions.h"
23224145Sdim
24224145Sdim#define GET_SUBTARGETINFO_TARGET_DESC
25224145Sdim#define GET_SUBTARGETINFO_CTOR
26224145Sdim#include "ARMGenSubtargetInfo.inc"
27224145Sdim
28193323Sedusing namespace llvm;
29193323Sed
30194710Sedstatic cl::opt<bool>
31194710SedReserveR9("arm-reserve-r9", cl::Hidden,
32194710Sed          cl::desc("Reserve R9, making it unavailable as GPR"));
33194710Sed
34199989Srdivackystatic cl::opt<bool>
35263508SdimArmUseMOVT("arm-use-movt", cl::init(true), cl::Hidden);
36199989Srdivacky
37218893Sdimstatic cl::opt<bool>
38243830SdimUseFusedMulOps("arm-use-mulops",
39243830Sdim               cl::init(true), cl::Hidden);
40243830Sdim
41263508Sdimenum AlignMode {
42263508Sdim  DefaultAlign,
43263508Sdim  StrictAlign,
44263508Sdim  NoStrictAlign
45263508Sdim};
46218893Sdim
47263508Sdimstatic cl::opt<AlignMode>
48263508SdimAlign(cl::desc("Load/store alignment support"),
49263508Sdim      cl::Hidden, cl::init(DefaultAlign),
50263508Sdim      cl::values(
51263508Sdim          clEnumValN(DefaultAlign,  "arm-default-align",
52263508Sdim                     "Generate unaligned accesses only on hardware/OS "
53263508Sdim                     "combinations that are known to support them"),
54263508Sdim          clEnumValN(StrictAlign,   "arm-strict-align",
55263508Sdim                     "Disallow all unaligned memory accesses"),
56263508Sdim          clEnumValN(NoStrictAlign, "arm-no-strict-align",
57263508Sdim                     "Allow unaligned memory accesses"),
58263508Sdim          clEnumValEnd));
59263508Sdim
60263508Sdimenum ITMode {
61263508Sdim  DefaultIT,
62263508Sdim  RestrictedIT,
63263508Sdim  NoRestrictedIT
64263508Sdim};
65263508Sdim
66263508Sdimstatic cl::opt<ITMode>
67263508SdimIT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT),
68263508Sdim   cl::ZeroOrMore,
69263508Sdim   cl::values(clEnumValN(DefaultIT, "arm-default-it",
70263508Sdim                         "Generate IT block based on arch"),
71263508Sdim              clEnumValN(RestrictedIT, "arm-restrict-it",
72263508Sdim                         "Disallow deprecated IT based on ARMv8"),
73263508Sdim              clEnumValN(NoRestrictedIT, "arm-no-restrict-it",
74263508Sdim                         "Allow IT blocks based on ARMv7"),
75263508Sdim              clEnumValEnd));
76263508Sdim
77224145SdimARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU,
78249423Sdim                           const std::string &FS, const TargetOptions &Options)
79224145Sdim  : ARMGenSubtargetInfo(TT, CPU, FS)
80218893Sdim  , ARMProcFamily(Others)
81263508Sdim  , ARMProcClass(None)
82193323Sed  , stackAlignment(4)
83224145Sdim  , CPUString(CPU)
84218893Sdim  , TargetTriple(TT)
85249423Sdim  , Options(Options)
86193323Sed  , TargetABI(ARM_ABI_APCS) {
87249423Sdim  initializeEnvironment();
88249423Sdim  resetSubtargetFeatures(CPU, FS);
89249423Sdim}
90249423Sdim
91249423Sdimvoid ARMSubtarget::initializeEnvironment() {
92249423Sdim  HasV4TOps = false;
93249423Sdim  HasV5TOps = false;
94249423Sdim  HasV5TEOps = false;
95249423Sdim  HasV6Ops = false;
96263508Sdim  HasV6MOps = false;
97249423Sdim  HasV6T2Ops = false;
98249423Sdim  HasV7Ops = false;
99263508Sdim  HasV8Ops = false;
100249423Sdim  HasVFPv2 = false;
101249423Sdim  HasVFPv3 = false;
102249423Sdim  HasVFPv4 = false;
103263508Sdim  HasFPARMv8 = false;
104249423Sdim  HasNEON = false;
105249423Sdim  UseNEONForSinglePrecisionFP = false;
106249423Sdim  UseMulOps = UseFusedMulOps;
107249423Sdim  SlowFPVMLx = false;
108249423Sdim  HasVMLxForwarding = false;
109249423Sdim  SlowFPBrcc = false;
110249423Sdim  InThumbMode = false;
111249423Sdim  HasThumb2 = false;
112249423Sdim  NoARM = false;
113249423Sdim  PostRAScheduler = false;
114249423Sdim  IsR9Reserved = ReserveR9;
115249423Sdim  UseMovt = false;
116249423Sdim  SupportsTailCall = false;
117249423Sdim  HasFP16 = false;
118249423Sdim  HasD16 = false;
119249423Sdim  HasHardwareDivide = false;
120249423Sdim  HasHardwareDivideInARM = false;
121249423Sdim  HasT2ExtractPack = false;
122249423Sdim  HasDataBarrier = false;
123249423Sdim  Pref32BitThumb = false;
124249423Sdim  AvoidCPSRPartialUpdate = false;
125249423Sdim  AvoidMOVsShifterOperand = false;
126249423Sdim  HasRAS = false;
127249423Sdim  HasMPExtension = false;
128263508Sdim  HasVirtualization = false;
129249423Sdim  FPOnlySP = false;
130263508Sdim  HasPerfMon = false;
131251662Sdim  HasTrustZone = false;
132263508Sdim  HasCrypto = false;
133263508Sdim  HasCRC = false;
134249423Sdim  AllowsUnalignedMem = false;
135249423Sdim  Thumb2DSP = false;
136249423Sdim  UseNaClTrap = false;
137249423Sdim  UnsafeFPMath = false;
138249423Sdim}
139249423Sdim
140249423Sdimvoid ARMSubtarget::resetSubtargetFeatures(const MachineFunction *MF) {
141249423Sdim  AttributeSet FnAttrs = MF->getFunction()->getAttributes();
142249423Sdim  Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex,
143249423Sdim                                           "target-cpu");
144249423Sdim  Attribute FSAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex,
145249423Sdim                                          "target-features");
146249423Sdim  std::string CPU =
147249423Sdim    !CPUAttr.hasAttribute(Attribute::None) ?CPUAttr.getValueAsString() : "";
148249423Sdim  std::string FS =
149249423Sdim    !FSAttr.hasAttribute(Attribute::None) ? FSAttr.getValueAsString() : "";
150249423Sdim  if (!FS.empty()) {
151249423Sdim    initializeEnvironment();
152249423Sdim    resetSubtargetFeatures(CPU, FS);
153249423Sdim  }
154249423Sdim}
155249423Sdim
156249423Sdimvoid ARMSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) {
157263508Sdim  if (CPUString.empty()) {
158263508Sdim    if (isTargetIOS() && TargetTriple.getArchName().endswith("v7s"))
159263508Sdim      // Default to the Swift CPU when targeting armv7s/thumbv7s.
160263508Sdim      CPUString = "swift";
161263508Sdim    else
162263508Sdim      CPUString = "generic";
163263508Sdim  }
164193323Sed
165224145Sdim  // Insert the architecture feature derived from the target triple into the
166224145Sdim  // feature string. This is important for setting features that are implied
167224145Sdim  // based on the architecture version.
168249423Sdim  std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple.getTriple(),
169249423Sdim                                              CPUString);
170224145Sdim  if (!FS.empty()) {
171224145Sdim    if (!ArchFS.empty())
172249423Sdim      ArchFS = ArchFS + "," + FS.str();
173224145Sdim    else
174224145Sdim      ArchFS = FS;
175218893Sdim  }
176224145Sdim  ParseSubtargetFeatures(CPUString, ArchFS);
177204961Srdivacky
178224145Sdim  // Thumb2 implies at least V6T2. FIXME: Fix tests to explicitly specify a
179224145Sdim  // ARM version or CPU and then remove this.
180224145Sdim  if (!HasV6T2Ops && hasThumb2())
181263508Sdim    HasV4TOps = HasV5TOps = HasV5TEOps = HasV6Ops = HasV6MOps = HasV6T2Ops = true;
182193323Sed
183239462Sdim  // Keep a pointer to static instruction cost data for the specified CPU.
184239462Sdim  SchedModel = getSchedModelForCPU(CPUString);
185239462Sdim
186224145Sdim  // Initialize scheduling itinerary for the specified CPU.
187224145Sdim  InstrItins = getInstrItineraryForCPU(CPUString);
188193323Sed
189249423Sdim  if ((TargetTriple.getTriple().find("eabi") != std::string::npos) ||
190249423Sdim      (isTargetIOS() && isMClass()))
191234353Sdim    // FIXME: We might want to separate AAPCS and EABI. Some systems, e.g.
192234353Sdim    // Darwin-EABI conforms to AACPS but not the rest of EABI.
193224145Sdim    TargetABI = ARM_ABI_AAPCS;
194198090Srdivacky
195193323Sed  if (isAAPCS_ABI())
196193323Sed    stackAlignment = 8;
197193323Sed
198263508Sdim  UseMovt = hasV6T2Ops() && ArmUseMOVT;
199263508Sdim
200263508Sdim  if (!isTargetIOS()) {
201263508Sdim    IsR9Reserved = ReserveR9;
202263508Sdim  } else {
203224145Sdim    IsR9Reserved = ReserveR9 | !HasV6Ops;
204234353Sdim    SupportsTailCall = !getTargetTriple().isOSVersionLT(5, 0);
205218893Sdim  }
206198090Srdivacky
207198396Srdivacky  if (!isThumb() || hasThumb2())
208198396Srdivacky    PostRAScheduler = true;
209218893Sdim
210263508Sdim  switch (Align) {
211263508Sdim    case DefaultAlign:
212263508Sdim      // Assume pre-ARMv6 doesn't support unaligned accesses.
213263508Sdim      //
214263508Sdim      // ARMv6 may or may not support unaligned accesses depending on the
215263508Sdim      // SCTLR.U bit, which is architecture-specific. We assume ARMv6
216263508Sdim      // Darwin targets support unaligned accesses, and others don't.
217263508Sdim      //
218263508Sdim      // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
219263508Sdim      // which raises an alignment fault on unaligned accesses. Linux
220263508Sdim      // defaults this bit to 0 and handles it as a system-wide (not
221263508Sdim      // per-process) setting. It is therefore safe to assume that ARMv7+
222263508Sdim      // Linux targets support unaligned accesses. The same goes for NaCl.
223263508Sdim      //
224263508Sdim      // The above behavior is consistent with GCC.
225263508Sdim      AllowsUnalignedMem = (
226263508Sdim          (hasV7Ops() && (isTargetLinux() || isTargetNaCl())) ||
227263508Sdim          (hasV6Ops() && isTargetDarwin()));
228263508Sdim      break;
229263508Sdim    case StrictAlign:
230263508Sdim      AllowsUnalignedMem = false;
231263508Sdim      break;
232263508Sdim    case NoStrictAlign:
233263508Sdim      AllowsUnalignedMem = true;
234263508Sdim      break;
235263508Sdim  }
236249423Sdim
237263508Sdim  switch (IT) {
238263508Sdim  case DefaultIT:
239263508Sdim    RestrictIT = hasV8Ops() ? true : false;
240263508Sdim    break;
241263508Sdim  case RestrictedIT:
242263508Sdim    RestrictIT = true;
243263508Sdim    break;
244263508Sdim  case NoRestrictedIT:
245263508Sdim    RestrictIT = false;
246263508Sdim    break;
247263508Sdim  }
248263508Sdim
249249423Sdim  // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default.
250249423Sdim  uint64_t Bits = getFeatureBits();
251249423Sdim  if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters
252249423Sdim      (Options.UnsafeFPMath || isTargetDarwin()))
253249423Sdim    UseNEONForSinglePrecisionFP = true;
254193323Sed}
255198090Srdivacky
256198090Srdivacky/// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol.
257198090Srdivackybool
258207618SrdivackyARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV,
259207618Srdivacky                                 Reloc::Model RelocM) const {
260198090Srdivacky  if (RelocM == Reloc::Static)
261198090Srdivacky    return false;
262198090Srdivacky
263203954Srdivacky  // Materializable GVs (in JIT lazy compilation mode) do not require an extra
264203954Srdivacky  // load from stub.
265219077Sdim  bool isDecl = GV->hasAvailableExternallyLinkage();
266219077Sdim  if (GV->isDeclaration() && !GV->isMaterializable())
267219077Sdim    isDecl = true;
268198090Srdivacky
269198090Srdivacky  if (!isTargetDarwin()) {
270198090Srdivacky    // Extra load is needed for all externally visible.
271198090Srdivacky    if (GV->hasLocalLinkage() || GV->hasHiddenVisibility())
272198090Srdivacky      return false;
273198090Srdivacky    return true;
274198090Srdivacky  } else {
275198090Srdivacky    if (RelocM == Reloc::PIC_) {
276198090Srdivacky      // If this is a strong reference to a definition, it is definitely not
277198090Srdivacky      // through a stub.
278198090Srdivacky      if (!isDecl && !GV->isWeakForLinker())
279198090Srdivacky        return false;
280198090Srdivacky
281198090Srdivacky      // Unless we have a symbol with hidden visibility, we have to go through a
282198090Srdivacky      // normal $non_lazy_ptr stub because this symbol might be resolved late.
283198090Srdivacky      if (!GV->hasHiddenVisibility())  // Non-hidden $non_lazy_ptr reference.
284198090Srdivacky        return true;
285198090Srdivacky
286198090Srdivacky      // If symbol visibility is hidden, we have a stub for common symbol
287198090Srdivacky      // references and external declarations.
288198090Srdivacky      if (isDecl || GV->hasCommonLinkage())
289198090Srdivacky        // Hidden $non_lazy_ptr reference.
290198090Srdivacky        return true;
291198090Srdivacky
292198090Srdivacky      return false;
293198090Srdivacky    } else {
294198090Srdivacky      // If this is a strong reference to a definition, it is definitely not
295198090Srdivacky      // through a stub.
296198090Srdivacky      if (!isDecl && !GV->isWeakForLinker())
297198090Srdivacky        return false;
298218893Sdim
299198090Srdivacky      // Unless we have a symbol with hidden visibility, we have to go through a
300198090Srdivacky      // normal $non_lazy_ptr stub because this symbol might be resolved late.
301198090Srdivacky      if (!GV->hasHiddenVisibility())  // Non-hidden $non_lazy_ptr reference.
302198090Srdivacky        return true;
303198090Srdivacky    }
304198090Srdivacky  }
305198090Srdivacky
306198090Srdivacky  return false;
307198090Srdivacky}
308199481Srdivacky
309218893Sdimunsigned ARMSubtarget::getMispredictionPenalty() const {
310239462Sdim  return SchedModel->MispredictPenalty;
311218893Sdim}
312218893Sdim
313263508Sdimbool ARMSubtarget::hasSinCos() const {
314263508Sdim  return getTargetTriple().getOS() == Triple::IOS &&
315263508Sdim    !getTargetTriple().isOSVersionLT(7, 0);
316263508Sdim}
317263508Sdim
318199481Srdivackybool ARMSubtarget::enablePostRAScheduler(
319199481Srdivacky           CodeGenOpt::Level OptLevel,
320224145Sdim           TargetSubtargetInfo::AntiDepBreakMode& Mode,
321199481Srdivacky           RegClassVector& CriticalPathRCs) const {
322263508Sdim  Mode = TargetSubtargetInfo::ANTIDEP_NONE;
323199481Srdivacky  return PostRAScheduler && OptLevel >= CodeGenOpt::Default;
324199481Srdivacky}
325