]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
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 | ||
223e47cc | 13 | #include "ARM.h" |
970d7e83 | 14 | #include "ARMFrameLowering.h" |
85aaf69f SL |
15 | #include "ARMTargetMachine.h" |
16 | #include "ARMTargetObjectFile.h" | |
223e47cc | 17 | #include "llvm/CodeGen/Passes.h" |
85aaf69f | 18 | #include "llvm/IR/Function.h" |
223e47cc | 19 | #include "llvm/MC/MCAsmInfo.h" |
970d7e83 | 20 | #include "llvm/PassManager.h" |
223e47cc LB |
21 | #include "llvm/Support/CommandLine.h" |
22 | #include "llvm/Support/FormattedStream.h" | |
23 | #include "llvm/Support/TargetRegistry.h" | |
24 | #include "llvm/Target/TargetOptions.h" | |
25 | #include "llvm/Transforms/Scalar.h" | |
26 | using namespace llvm; | |
27 | ||
970d7e83 LB |
28 | static cl::opt<bool> |
29 | DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden, | |
30 | cl::desc("Inhibit optimization of S->D register accesses on A15"), | |
31 | cl::init(false)); | |
32 | ||
1a4d82fc JJ |
33 | static cl::opt<bool> |
34 | EnableAtomicTidy("arm-atomic-cfg-tidy", cl::Hidden, | |
35 | cl::desc("Run SimplifyCFG after expanding atomic operations" | |
36 | " to make use of cmpxchg flow-based information"), | |
37 | cl::init(true)); | |
38 | ||
223e47cc LB |
39 | extern "C" void LLVMInitializeARMTarget() { |
40 | // Register the target. | |
1a4d82fc JJ |
41 | RegisterTargetMachine<ARMLETargetMachine> X(TheARMLETarget); |
42 | RegisterTargetMachine<ARMBETargetMachine> Y(TheARMBETarget); | |
43 | RegisterTargetMachine<ThumbLETargetMachine> A(TheThumbLETarget); | |
44 | RegisterTargetMachine<ThumbBETargetMachine> B(TheThumbBETarget); | |
223e47cc LB |
45 | } |
46 | ||
85aaf69f SL |
47 | static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) { |
48 | if (TT.isOSBinFormatMachO()) | |
49 | return make_unique<TargetLoweringObjectFileMachO>(); | |
50 | if (TT.isOSWindows()) | |
51 | return make_unique<TargetLoweringObjectFileCOFF>(); | |
52 | return make_unique<ARMElfTargetObjectFile>(); | |
53 | } | |
54 | ||
55 | static ARMBaseTargetMachine::ARMABI | |
56 | computeTargetABI(const Triple &TT, StringRef CPU, | |
57 | const TargetOptions &Options) { | |
58 | if (Options.MCOptions.getABIName().startswith("aapcs")) | |
59 | return ARMBaseTargetMachine::ARM_ABI_AAPCS; | |
60 | else if (Options.MCOptions.getABIName().startswith("apcs")) | |
61 | return ARMBaseTargetMachine::ARM_ABI_APCS; | |
62 | ||
63 | assert(Options.MCOptions.getABIName().empty() && | |
64 | "Unknown target-abi option!"); | |
65 | ||
66 | ARMBaseTargetMachine::ARMABI TargetABI = | |
67 | ARMBaseTargetMachine::ARM_ABI_UNKNOWN; | |
68 | ||
69 | // FIXME: This is duplicated code from the front end and should be unified. | |
70 | if (TT.isOSBinFormatMachO()) { | |
71 | if (TT.getEnvironment() == llvm::Triple::EABI || | |
72 | (TT.getOS() == llvm::Triple::UnknownOS && | |
73 | TT.getObjectFormat() == llvm::Triple::MachO) || | |
74 | CPU.startswith("cortex-m")) { | |
75 | TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; | |
76 | } else { | |
77 | TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; | |
78 | } | |
79 | } else if (TT.isOSWindows()) { | |
80 | // FIXME: this is invalid for WindowsCE | |
81 | TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; | |
82 | } else { | |
83 | // Select the default based on the platform. | |
84 | switch (TT.getEnvironment()) { | |
85 | case llvm::Triple::Android: | |
86 | case llvm::Triple::GNUEABI: | |
87 | case llvm::Triple::GNUEABIHF: | |
88 | case llvm::Triple::EABIHF: | |
89 | case llvm::Triple::EABI: | |
90 | TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; | |
91 | break; | |
92 | case llvm::Triple::GNU: | |
93 | TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; | |
94 | break; | |
95 | default: | |
96 | if (TT.getOS() == llvm::Triple::NetBSD) | |
97 | TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; | |
98 | else | |
99 | TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; | |
100 | break; | |
101 | } | |
102 | } | |
103 | ||
104 | return TargetABI; | |
105 | } | |
223e47cc LB |
106 | |
107 | /// TargetMachine ctor - Create an ARM architecture model. | |
108 | /// | |
109 | ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, StringRef TT, | |
110 | StringRef CPU, StringRef FS, | |
111 | const TargetOptions &Options, | |
112 | Reloc::Model RM, CodeModel::Model CM, | |
1a4d82fc JJ |
113 | CodeGenOpt::Level OL, bool isLittle) |
114 | : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), | |
85aaf69f SL |
115 | TargetABI(computeTargetABI(Triple(TT), CPU, Options)), |
116 | TLOF(createTLOF(Triple(getTargetTriple()))), | |
117 | Subtarget(TT, CPU, FS, *this, isLittle), isLittle(isLittle) { | |
1a4d82fc JJ |
118 | |
119 | // Default to triple-appropriate float ABI | |
223e47cc | 120 | if (Options.FloatABIType == FloatABI::Default) |
1a4d82fc JJ |
121 | this->Options.FloatABIType = |
122 | Subtarget.isTargetHardFloat() ? FloatABI::Hard : FloatABI::Soft; | |
223e47cc LB |
123 | } |
124 | ||
85aaf69f SL |
125 | ARMBaseTargetMachine::~ARMBaseTargetMachine() {} |
126 | ||
127 | const ARMSubtarget * | |
128 | ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const { | |
129 | AttributeSet FnAttrs = F.getAttributes(); | |
130 | Attribute CPUAttr = | |
131 | FnAttrs.getAttribute(AttributeSet::FunctionIndex, "target-cpu"); | |
132 | Attribute FSAttr = | |
133 | FnAttrs.getAttribute(AttributeSet::FunctionIndex, "target-features"); | |
134 | ||
135 | std::string CPU = !CPUAttr.hasAttribute(Attribute::None) | |
136 | ? CPUAttr.getValueAsString().str() | |
137 | : TargetCPU; | |
138 | std::string FS = !FSAttr.hasAttribute(Attribute::None) | |
139 | ? FSAttr.getValueAsString().str() | |
140 | : TargetFS; | |
141 | ||
142 | // FIXME: This is related to the code below to reset the target options, | |
143 | // we need to know whether or not the soft float flag is set on the | |
144 | // function before we can generate a subtarget. We also need to use | |
145 | // it as a key for the subtarget since that can be the only difference | |
146 | // between two functions. | |
147 | Attribute SFAttr = | |
148 | FnAttrs.getAttribute(AttributeSet::FunctionIndex, "use-soft-float"); | |
149 | bool SoftFloat = !SFAttr.hasAttribute(Attribute::None) | |
150 | ? SFAttr.getValueAsString() == "true" | |
151 | : Options.UseSoftFloat; | |
152 | ||
153 | auto &I = SubtargetMap[CPU + FS + (SoftFloat ? "use-soft-float=true" | |
154 | : "use-soft-float=false")]; | |
155 | if (!I) { | |
156 | // This needs to be done before we create a new subtarget since any | |
157 | // creation will depend on the TM and the code generation flags on the | |
158 | // function that reside in TargetOptions. | |
159 | resetTargetOptions(F); | |
160 | I = llvm::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle); | |
161 | } | |
162 | return I.get(); | |
163 | } | |
164 | ||
970d7e83 LB |
165 | void ARMBaseTargetMachine::addAnalysisPasses(PassManagerBase &PM) { |
166 | // Add first the target-independent BasicTTI pass, then our ARM pass. This | |
167 | // allows the ARM pass to delegate to the target independent layer when | |
168 | // appropriate. | |
1a4d82fc | 169 | PM.add(createBasicTargetTransformInfoPass(this)); |
970d7e83 LB |
170 | PM.add(createARMTargetTransformInfoPass(this)); |
171 | } | |
172 | ||
173 | ||
223e47cc LB |
174 | void ARMTargetMachine::anchor() { } |
175 | ||
1a4d82fc JJ |
176 | ARMTargetMachine::ARMTargetMachine(const Target &T, StringRef TT, StringRef CPU, |
177 | StringRef FS, const TargetOptions &Options, | |
223e47cc | 178 | Reloc::Model RM, CodeModel::Model CM, |
1a4d82fc JJ |
179 | CodeGenOpt::Level OL, bool isLittle) |
180 | : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, isLittle) { | |
181 | initAsmInfo(); | |
223e47cc LB |
182 | if (!Subtarget.hasARMOps()) |
183 | report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not " | |
184 | "support ARM mode execution!"); | |
185 | } | |
186 | ||
1a4d82fc JJ |
187 | void ARMLETargetMachine::anchor() { } |
188 | ||
189 | ARMLETargetMachine::ARMLETargetMachine(const Target &T, StringRef TT, | |
190 | StringRef CPU, StringRef FS, | |
191 | const TargetOptions &Options, | |
192 | Reloc::Model RM, CodeModel::Model CM, | |
193 | CodeGenOpt::Level OL) | |
194 | : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} | |
195 | ||
196 | void ARMBETargetMachine::anchor() { } | |
197 | ||
198 | ARMBETargetMachine::ARMBETargetMachine(const Target &T, StringRef TT, | |
199 | StringRef CPU, StringRef FS, | |
200 | const TargetOptions &Options, | |
201 | Reloc::Model RM, CodeModel::Model CM, | |
202 | CodeGenOpt::Level OL) | |
203 | : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} | |
204 | ||
223e47cc LB |
205 | void ThumbTargetMachine::anchor() { } |
206 | ||
207 | ThumbTargetMachine::ThumbTargetMachine(const Target &T, StringRef TT, | |
208 | StringRef CPU, StringRef FS, | |
209 | const TargetOptions &Options, | |
210 | Reloc::Model RM, CodeModel::Model CM, | |
1a4d82fc JJ |
211 | CodeGenOpt::Level OL, bool isLittle) |
212 | : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, | |
213 | isLittle) { | |
214 | initAsmInfo(); | |
223e47cc LB |
215 | } |
216 | ||
1a4d82fc JJ |
217 | void ThumbLETargetMachine::anchor() { } |
218 | ||
219 | ThumbLETargetMachine::ThumbLETargetMachine(const Target &T, StringRef TT, | |
220 | StringRef CPU, StringRef FS, | |
221 | const TargetOptions &Options, | |
222 | Reloc::Model RM, CodeModel::Model CM, | |
223 | CodeGenOpt::Level OL) | |
224 | : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} | |
225 | ||
226 | void ThumbBETargetMachine::anchor() { } | |
227 | ||
228 | ThumbBETargetMachine::ThumbBETargetMachine(const Target &T, StringRef TT, | |
229 | StringRef CPU, StringRef FS, | |
230 | const TargetOptions &Options, | |
231 | Reloc::Model RM, CodeModel::Model CM, | |
232 | CodeGenOpt::Level OL) | |
233 | : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} | |
234 | ||
223e47cc LB |
235 | namespace { |
236 | /// ARM Code Generator Pass Configuration Options. | |
237 | class ARMPassConfig : public TargetPassConfig { | |
238 | public: | |
239 | ARMPassConfig(ARMBaseTargetMachine *TM, PassManagerBase &PM) | |
240 | : TargetPassConfig(TM, PM) {} | |
241 | ||
242 | ARMBaseTargetMachine &getARMTargetMachine() const { | |
243 | return getTM<ARMBaseTargetMachine>(); | |
244 | } | |
245 | ||
246 | const ARMSubtarget &getARMSubtarget() const { | |
247 | return *getARMTargetMachine().getSubtargetImpl(); | |
248 | } | |
249 | ||
1a4d82fc JJ |
250 | void addIRPasses() override; |
251 | bool addPreISel() override; | |
252 | bool addInstSelector() override; | |
85aaf69f SL |
253 | void addPreRegAlloc() override; |
254 | void addPreSched2() override; | |
255 | void addPreEmitPass() override; | |
223e47cc LB |
256 | }; |
257 | } // namespace | |
258 | ||
259 | TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) { | |
260 | return new ARMPassConfig(this, PM); | |
261 | } | |
262 | ||
1a4d82fc JJ |
263 | void ARMPassConfig::addIRPasses() { |
264 | if (TM->Options.ThreadModel == ThreadModel::Single) | |
265 | addPass(createLowerAtomicPass()); | |
266 | else | |
267 | addPass(createAtomicExpandPass(TM)); | |
268 | ||
269 | // Cmpxchg instructions are often used with a subsequent comparison to | |
270 | // determine whether it succeeded. We can exploit existing control-flow in | |
271 | // ldrex/strex loops to simplify this, but it needs tidying up. | |
272 | const ARMSubtarget *Subtarget = &getARMSubtarget(); | |
273 | if (Subtarget->hasAnyDataBarrier() && !Subtarget->isThumb1Only()) | |
274 | if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy) | |
275 | addPass(createCFGSimplificationPass()); | |
276 | ||
277 | TargetPassConfig::addIRPasses(); | |
278 | } | |
279 | ||
223e47cc | 280 | bool ARMPassConfig::addPreISel() { |
1a4d82fc JJ |
281 | if (TM->getOptLevel() != CodeGenOpt::None) |
282 | addPass(createGlobalMergePass(TM)); | |
223e47cc LB |
283 | |
284 | return false; | |
285 | } | |
286 | ||
287 | bool ARMPassConfig::addInstSelector() { | |
288 | addPass(createARMISelDag(getARMTargetMachine(), getOptLevel())); | |
289 | ||
290 | const ARMSubtarget *Subtarget = &getARMSubtarget(); | |
291 | if (Subtarget->isTargetELF() && !Subtarget->isThumb1Only() && | |
292 | TM->Options.EnableFastISel) | |
293 | addPass(createARMGlobalBaseRegPass()); | |
294 | return false; | |
295 | } | |
296 | ||
85aaf69f | 297 | void ARMPassConfig::addPreRegAlloc() { |
1a4d82fc | 298 | if (getOptLevel() != CodeGenOpt::None) |
223e47cc | 299 | addPass(createARMLoadStoreOptimizationPass(true)); |
1a4d82fc | 300 | if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA9()) |
223e47cc | 301 | addPass(createMLxExpansionPass()); |
970d7e83 LB |
302 | // Since the A15SDOptimizer pass can insert VDUP instructions, it can only be |
303 | // enabled when NEON is available. | |
304 | if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA15() && | |
305 | getARMSubtarget().hasNEON() && !DisableA15SDOptimization) { | |
306 | addPass(createA15SDOptimizerPass()); | |
307 | } | |
223e47cc LB |
308 | } |
309 | ||
85aaf69f | 310 | void ARMPassConfig::addPreSched2() { |
223e47cc | 311 | if (getOptLevel() != CodeGenOpt::None) { |
1a4d82fc | 312 | addPass(createARMLoadStoreOptimizationPass()); |
1a4d82fc JJ |
313 | |
314 | if (getARMSubtarget().hasNEON()) | |
223e47cc LB |
315 | addPass(createExecutionDependencyFixPass(&ARM::DPRRegClass)); |
316 | } | |
317 | ||
318 | // Expand some pseudo instructions into multiple instructions to allow | |
319 | // proper scheduling. | |
320 | addPass(createARMExpandPseudoPass()); | |
321 | ||
322 | if (getOptLevel() != CodeGenOpt::None) { | |
1a4d82fc JJ |
323 | if (!getARMSubtarget().isThumb1Only()) { |
324 | // in v8, IfConversion depends on Thumb instruction widths | |
325 | if (getARMSubtarget().restrictIT() && | |
326 | !getARMSubtarget().prefers32BitThumb()) | |
327 | addPass(createThumb2SizeReductionPass()); | |
223e47cc | 328 | addPass(&IfConverterID); |
1a4d82fc | 329 | } |
223e47cc LB |
330 | } |
331 | if (getARMSubtarget().isThumb2()) | |
332 | addPass(createThumb2ITBlockPass()); | |
223e47cc LB |
333 | } |
334 | ||
85aaf69f | 335 | void ARMPassConfig::addPreEmitPass() { |
223e47cc LB |
336 | if (getARMSubtarget().isThumb2()) { |
337 | if (!getARMSubtarget().prefers32BitThumb()) | |
338 | addPass(createThumb2SizeReductionPass()); | |
339 | ||
340 | // Constant island pass work on unbundled instructions. | |
341 | addPass(&UnpackMachineBundlesID); | |
342 | } | |
343 | ||
1a4d82fc | 344 | addPass(createARMOptimizeBarriersPass()); |
223e47cc | 345 | addPass(createARMConstantIslandPass()); |
223e47cc | 346 | } |