ARMTargetMachine.cpp revision 6948897e478cbd66626159776a8017b3c18579b9
1//===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===//
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//
11//===----------------------------------------------------------------------===//
12
13#include "ARM.h"
14#include "ARMFrameLowering.h"
15#include "ARMTargetMachine.h"
16#include "ARMTargetObjectFile.h"
17#include "ARMTargetTransformInfo.h"
18#include "llvm/CodeGen/Passes.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/LegacyPassManager.h"
21#include "llvm/MC/MCAsmInfo.h"
22#include "llvm/Support/CommandLine.h"
23#include "llvm/Support/FormattedStream.h"
24#include "llvm/Support/TargetRegistry.h"
25#include "llvm/Target/TargetOptions.h"
26#include "llvm/Transforms/Scalar.h"
27using namespace llvm;
28
29static cl::opt<bool>
30DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden,
31                   cl::desc("Inhibit optimization of S->D register accesses on A15"),
32                   cl::init(false));
33
34static cl::opt<bool>
35EnableAtomicTidy("arm-atomic-cfg-tidy", cl::Hidden,
36                 cl::desc("Run SimplifyCFG after expanding atomic operations"
37                          " to make use of cmpxchg flow-based information"),
38                 cl::init(true));
39
40static cl::opt<bool>
41EnableARMLoadStoreOpt("arm-load-store-opt", cl::Hidden,
42                      cl::desc("Enable ARM load/store optimization pass"),
43                      cl::init(true));
44
45// FIXME: Unify control over GlobalMerge.
46static cl::opt<cl::boolOrDefault>
47EnableGlobalMerge("arm-global-merge", cl::Hidden,
48                  cl::desc("Enable the global merge pass"));
49
50extern "C" void LLVMInitializeARMTarget() {
51  // Register the target.
52  RegisterTargetMachine<ARMLETargetMachine> X(TheARMLETarget);
53  RegisterTargetMachine<ARMBETargetMachine> Y(TheARMBETarget);
54  RegisterTargetMachine<ThumbLETargetMachine> A(TheThumbLETarget);
55  RegisterTargetMachine<ThumbBETargetMachine> B(TheThumbBETarget);
56}
57
58static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
59  if (TT.isOSBinFormatMachO())
60    return make_unique<TargetLoweringObjectFileMachO>();
61  if (TT.isOSWindows())
62    return make_unique<TargetLoweringObjectFileCOFF>();
63  return make_unique<ARMElfTargetObjectFile>();
64}
65
66static ARMBaseTargetMachine::ARMABI
67computeTargetABI(const Triple &TT, StringRef CPU,
68                 const TargetOptions &Options) {
69  if (Options.MCOptions.getABIName().startswith("aapcs"))
70    return ARMBaseTargetMachine::ARM_ABI_AAPCS;
71  else if (Options.MCOptions.getABIName().startswith("apcs"))
72    return ARMBaseTargetMachine::ARM_ABI_APCS;
73
74  assert(Options.MCOptions.getABIName().empty() &&
75         "Unknown target-abi option!");
76
77  ARMBaseTargetMachine::ARMABI TargetABI =
78      ARMBaseTargetMachine::ARM_ABI_UNKNOWN;
79
80  // FIXME: This is duplicated code from the front end and should be unified.
81  if (TT.isOSBinFormatMachO()) {
82    if (TT.getEnvironment() == llvm::Triple::EABI ||
83        (TT.getOS() == llvm::Triple::UnknownOS &&
84         TT.getObjectFormat() == llvm::Triple::MachO) ||
85        CPU.startswith("cortex-m")) {
86      TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS;
87    } else {
88      TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS;
89    }
90  } else if (TT.isOSWindows()) {
91    // FIXME: this is invalid for WindowsCE
92    TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS;
93  } else {
94    // Select the default based on the platform.
95    switch (TT.getEnvironment()) {
96    case llvm::Triple::Android:
97    case llvm::Triple::GNUEABI:
98    case llvm::Triple::GNUEABIHF:
99    case llvm::Triple::EABIHF:
100    case llvm::Triple::EABI:
101      TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS;
102      break;
103    case llvm::Triple::GNU:
104      TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS;
105      break;
106    default:
107      if (TT.getOS() == llvm::Triple::NetBSD)
108	TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS;
109      else
110	TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS;
111      break;
112    }
113  }
114
115  return TargetABI;
116}
117
118static std::string computeDataLayout(const Triple &TT, StringRef CPU,
119                                     const TargetOptions &Options,
120                                     bool isLittle) {
121  auto ABI = computeTargetABI(TT, CPU, Options);
122  std::string Ret = "";
123
124  if (isLittle)
125    // Little endian.
126    Ret += "e";
127  else
128    // Big endian.
129    Ret += "E";
130
131  Ret += DataLayout::getManglingComponent(TT);
132
133  // Pointers are 32 bits and aligned to 32 bits.
134  Ret += "-p:32:32";
135
136  // ABIs other than APCS have 64 bit integers with natural alignment.
137  if (ABI != ARMBaseTargetMachine::ARM_ABI_APCS)
138    Ret += "-i64:64";
139
140  // We have 64 bits floats. The APCS ABI requires them to be aligned to 32
141  // bits, others to 64 bits. We always try to align to 64 bits.
142  if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS)
143    Ret += "-f64:32:64";
144
145  // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others
146  // to 64. We always ty to give them natural alignment.
147  if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS)
148    Ret += "-v64:32:64-v128:32:128";
149  else
150    Ret += "-v128:64:128";
151
152  // Try to align aggregates to 32 bits (the default is 64 bits, which has no
153  // particular hardware support on 32-bit ARM).
154  Ret += "-a:0:32";
155
156  // Integer registers are 32 bits.
157  Ret += "-n32";
158
159  // The stack is 128 bit aligned on NaCl, 64 bit aligned on AAPCS and 32 bit
160  // aligned everywhere else.
161  if (TT.isOSNaCl())
162    Ret += "-S128";
163  else if (ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS)
164    Ret += "-S64";
165  else
166    Ret += "-S32";
167
168  return Ret;
169}
170
171/// TargetMachine ctor - Create an ARM architecture model.
172///
173ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT,
174                                           StringRef CPU, StringRef FS,
175                                           const TargetOptions &Options,
176                                           Reloc::Model RM, CodeModel::Model CM,
177                                           CodeGenOpt::Level OL, bool isLittle)
178    : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT,
179                        CPU, FS, Options, RM, CM, OL),
180      TargetABI(computeTargetABI(TT, CPU, Options)),
181      TLOF(createTLOF(Triple(getTargetTriple()))),
182      Subtarget(TT, CPU, FS, *this, isLittle), isLittle(isLittle) {
183
184  // Default to triple-appropriate float ABI
185  if (Options.FloatABIType == FloatABI::Default)
186    this->Options.FloatABIType =
187        Subtarget.isTargetHardFloat() ? FloatABI::Hard : FloatABI::Soft;
188}
189
190ARMBaseTargetMachine::~ARMBaseTargetMachine() {}
191
192const ARMSubtarget *
193ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
194  Attribute CPUAttr = F.getFnAttribute("target-cpu");
195  Attribute FSAttr = F.getFnAttribute("target-features");
196
197  std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
198                        ? CPUAttr.getValueAsString().str()
199                        : TargetCPU;
200  std::string FS = !FSAttr.hasAttribute(Attribute::None)
201                       ? FSAttr.getValueAsString().str()
202                       : TargetFS;
203
204  // FIXME: This is related to the code below to reset the target options,
205  // we need to know whether or not the soft float flag is set on the
206  // function before we can generate a subtarget. We also need to use
207  // it as a key for the subtarget since that can be the only difference
208  // between two functions.
209  bool SoftFloat =
210      F.hasFnAttribute("use-soft-float") &&
211      F.getFnAttribute("use-soft-float").getValueAsString() == "true";
212  // If the soft float attribute is set on the function turn on the soft float
213  // subtarget feature.
214  if (SoftFloat)
215    FS += FS.empty() ? "+soft-float" : ",+soft-float";
216
217  auto &I = SubtargetMap[CPU + FS];
218  if (!I) {
219    // This needs to be done before we create a new subtarget since any
220    // creation will depend on the TM and the code generation flags on the
221    // function that reside in TargetOptions.
222    resetTargetOptions(F);
223    I = llvm::make_unique<ARMSubtarget>(Triple(TargetTriple), CPU, FS, *this,
224                                        isLittle);
225  }
226  return I.get();
227}
228
229TargetIRAnalysis ARMBaseTargetMachine::getTargetIRAnalysis() {
230  return TargetIRAnalysis(
231      [this](Function &F) { return TargetTransformInfo(ARMTTIImpl(this, F)); });
232}
233
234
235void ARMTargetMachine::anchor() { }
236
237ARMTargetMachine::ARMTargetMachine(const Target &T, const Triple &TT,
238                                   StringRef CPU, StringRef FS,
239                                   const TargetOptions &Options,
240                                   Reloc::Model RM, CodeModel::Model CM,
241                                   CodeGenOpt::Level OL, bool isLittle)
242    : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, isLittle) {
243  initAsmInfo();
244  if (!Subtarget.hasARMOps())
245    report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not "
246                       "support ARM mode execution!");
247}
248
249void ARMLETargetMachine::anchor() { }
250
251ARMLETargetMachine::ARMLETargetMachine(const Target &T, const Triple &TT,
252                                       StringRef CPU, StringRef FS,
253                                       const TargetOptions &Options,
254                                       Reloc::Model RM, CodeModel::Model CM,
255                                       CodeGenOpt::Level OL)
256    : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
257
258void ARMBETargetMachine::anchor() { }
259
260ARMBETargetMachine::ARMBETargetMachine(const Target &T, const Triple &TT,
261                                       StringRef CPU, StringRef FS,
262                                       const TargetOptions &Options,
263                                       Reloc::Model RM, CodeModel::Model CM,
264                                       CodeGenOpt::Level OL)
265    : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
266
267void ThumbTargetMachine::anchor() { }
268
269ThumbTargetMachine::ThumbTargetMachine(const Target &T, const Triple &TT,
270                                       StringRef CPU, StringRef FS,
271                                       const TargetOptions &Options,
272                                       Reloc::Model RM, CodeModel::Model CM,
273                                       CodeGenOpt::Level OL, bool isLittle)
274    : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, isLittle) {
275  initAsmInfo();
276}
277
278void ThumbLETargetMachine::anchor() { }
279
280ThumbLETargetMachine::ThumbLETargetMachine(const Target &T, const Triple &TT,
281                                           StringRef CPU, StringRef FS,
282                                           const TargetOptions &Options,
283                                           Reloc::Model RM, CodeModel::Model CM,
284                                           CodeGenOpt::Level OL)
285    : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
286
287void ThumbBETargetMachine::anchor() { }
288
289ThumbBETargetMachine::ThumbBETargetMachine(const Target &T, const Triple &TT,
290                                           StringRef CPU, StringRef FS,
291                                           const TargetOptions &Options,
292                                           Reloc::Model RM, CodeModel::Model CM,
293                                           CodeGenOpt::Level OL)
294    : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
295
296namespace {
297/// ARM Code Generator Pass Configuration Options.
298class ARMPassConfig : public TargetPassConfig {
299public:
300  ARMPassConfig(ARMBaseTargetMachine *TM, PassManagerBase &PM)
301    : TargetPassConfig(TM, PM) {}
302
303  ARMBaseTargetMachine &getARMTargetMachine() const {
304    return getTM<ARMBaseTargetMachine>();
305  }
306
307  void addIRPasses() override;
308  bool addPreISel() override;
309  bool addInstSelector() override;
310  void addPreRegAlloc() override;
311  void addPreSched2() override;
312  void addPreEmitPass() override;
313};
314} // namespace
315
316TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) {
317  return new ARMPassConfig(this, PM);
318}
319
320void ARMPassConfig::addIRPasses() {
321  if (TM->Options.ThreadModel == ThreadModel::Single)
322    addPass(createLowerAtomicPass());
323  else
324    addPass(createAtomicExpandPass(TM));
325
326  // Cmpxchg instructions are often used with a subsequent comparison to
327  // determine whether it succeeded. We can exploit existing control-flow in
328  // ldrex/strex loops to simplify this, but it needs tidying up.
329  if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy)
330    addPass(createCFGSimplificationPass(-1, [this](const Function &F) {
331      const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F);
332      return ST.hasAnyDataBarrier() && !ST.isThumb1Only();
333    }));
334
335  TargetPassConfig::addIRPasses();
336}
337
338bool ARMPassConfig::addPreISel() {
339  if ((TM->getOptLevel() != CodeGenOpt::None &&
340       EnableGlobalMerge == cl::BOU_UNSET) ||
341      EnableGlobalMerge == cl::BOU_TRUE) {
342    // FIXME: This is using the thumb1 only constant value for
343    // maximal global offset for merging globals. We may want
344    // to look into using the old value for non-thumb1 code of
345    // 4095 based on the TargetMachine, but this starts to become
346    // tricky when doing code gen per function.
347    bool OnlyOptimizeForSize = (TM->getOptLevel() < CodeGenOpt::Aggressive) &&
348                               (EnableGlobalMerge == cl::BOU_UNSET);
349    addPass(createGlobalMergePass(TM, 127, OnlyOptimizeForSize));
350  }
351
352  return false;
353}
354
355bool ARMPassConfig::addInstSelector() {
356  addPass(createARMISelDag(getARMTargetMachine(), getOptLevel()));
357
358  if (Triple(TM->getTargetTriple()).isOSBinFormatELF() &&
359      TM->Options.EnableFastISel)
360    addPass(createARMGlobalBaseRegPass());
361  return false;
362}
363
364void ARMPassConfig::addPreRegAlloc() {
365  if (getOptLevel() != CodeGenOpt::None) {
366    addPass(createMLxExpansionPass());
367
368    if (EnableARMLoadStoreOpt)
369      addPass(createARMLoadStoreOptimizationPass(/* pre-register alloc */ true));
370
371    if (!DisableA15SDOptimization)
372      addPass(createA15SDOptimizerPass());
373  }
374}
375
376void ARMPassConfig::addPreSched2() {
377  if (getOptLevel() != CodeGenOpt::None) {
378    if (EnableARMLoadStoreOpt)
379      addPass(createARMLoadStoreOptimizationPass());
380
381    addPass(createExecutionDependencyFixPass(&ARM::DPRRegClass));
382  }
383
384  // Expand some pseudo instructions into multiple instructions to allow
385  // proper scheduling.
386  addPass(createARMExpandPseudoPass());
387
388  if (getOptLevel() != CodeGenOpt::None) {
389    // in v8, IfConversion depends on Thumb instruction widths
390    addPass(createThumb2SizeReductionPass([this](const Function &F) {
391      return this->TM->getSubtarget<ARMSubtarget>(F).restrictIT();
392    }));
393
394    addPass(createIfConverter([this](const Function &F) {
395      return !this->TM->getSubtarget<ARMSubtarget>(F).isThumb1Only();
396    }));
397  }
398  addPass(createThumb2ITBlockPass());
399}
400
401void ARMPassConfig::addPreEmitPass() {
402  addPass(createThumb2SizeReductionPass());
403
404  // Constant island pass work on unbundled instructions.
405  addPass(createUnpackMachineBundles([this](const Function &F) {
406    return this->TM->getSubtarget<ARMSubtarget>(F).isThumb2();
407  }));
408
409  // Don't optimize barriers at -O0.
410  if (getOptLevel() != CodeGenOpt::None)
411    addPass(createARMOptimizeBarriersPass());
412
413  addPass(createARMConstantIslandPass());
414}
415