1 | //===-- HexagonTargetMachine.cpp - Define TargetMachine for Hexagon -------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Implements the info about Hexagon target spec. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "HexagonTargetMachine.h" |
14 | #include "Hexagon.h" |
15 | #include "HexagonISelLowering.h" |
16 | #include "HexagonLoopIdiomRecognition.h" |
17 | #include "HexagonMachineFunctionInfo.h" |
18 | #include "HexagonMachineScheduler.h" |
19 | #include "HexagonTargetObjectFile.h" |
20 | #include "HexagonTargetTransformInfo.h" |
21 | #include "HexagonVectorLoopCarriedReuse.h" |
22 | #include "TargetInfo/HexagonTargetInfo.h" |
23 | #include "llvm/CodeGen/Passes.h" |
24 | #include "llvm/CodeGen/TargetPassConfig.h" |
25 | #include "llvm/CodeGen/VLIWMachineScheduler.h" |
26 | #include "llvm/MC/TargetRegistry.h" |
27 | #include "llvm/Passes/PassBuilder.h" |
28 | #include "llvm/Support/CommandLine.h" |
29 | #include "llvm/Support/Compiler.h" |
30 | #include "llvm/Transforms/Scalar.h" |
31 | #include <optional> |
32 | |
33 | using namespace llvm; |
34 | |
35 | static cl::opt<bool> |
36 | EnableCExtOpt("hexagon-cext" , cl::Hidden, cl::init(Val: true), |
37 | cl::desc("Enable Hexagon constant-extender optimization" )); |
38 | |
39 | static cl::opt<bool> EnableRDFOpt("rdf-opt" , cl::Hidden, cl::init(Val: true), |
40 | cl::desc("Enable RDF-based optimizations" )); |
41 | |
42 | cl::opt<unsigned> RDFFuncBlockLimit( |
43 | "rdf-bb-limit" , cl::Hidden, cl::init(Val: 1000), |
44 | cl::desc("Basic block limit for a function for RDF optimizations" )); |
45 | |
46 | static cl::opt<bool> |
47 | DisableHardwareLoops("disable-hexagon-hwloops" , cl::Hidden, |
48 | cl::desc("Disable Hardware Loops for Hexagon target" )); |
49 | |
50 | static cl::opt<bool> |
51 | DisableAModeOpt("disable-hexagon-amodeopt" , cl::Hidden, |
52 | cl::desc("Disable Hexagon Addressing Mode Optimization" )); |
53 | |
54 | static cl::opt<bool> |
55 | DisableHexagonCFGOpt("disable-hexagon-cfgopt" , cl::Hidden, |
56 | cl::desc("Disable Hexagon CFG Optimization" )); |
57 | |
58 | static cl::opt<bool> |
59 | DisableHCP("disable-hcp" , cl::Hidden, |
60 | cl::desc("Disable Hexagon constant propagation" )); |
61 | |
62 | static cl::opt<bool> DisableHexagonMask( |
63 | "disable-mask" , cl::Hidden, |
64 | cl::desc("Disable Hexagon specific Mask generation pass" )); |
65 | |
66 | static cl::opt<bool> DisableStoreWidening("disable-store-widen" , cl::Hidden, |
67 | cl::init(Val: false), |
68 | cl::desc("Disable store widening" )); |
69 | |
70 | static cl::opt<bool> DisableLoadWidening("disable-load-widen" , cl::Hidden, |
71 | cl::desc("Disable load widening" )); |
72 | |
73 | static cl::opt<bool> EnableExpandCondsets("hexagon-expand-condsets" , |
74 | cl::init(Val: true), cl::Hidden, |
75 | cl::desc("Early expansion of MUX" )); |
76 | |
77 | static cl::opt<bool> EnableTfrCleanup("hexagon-tfr-cleanup" , cl::init(Val: true), |
78 | cl::Hidden, |
79 | cl::desc("Cleanup of TFRs/COPYs" )); |
80 | |
81 | static cl::opt<bool> EnableEarlyIf("hexagon-eif" , cl::init(Val: true), cl::Hidden, |
82 | cl::desc("Enable early if-conversion" )); |
83 | |
84 | static cl::opt<bool> EnableCopyHoist("hexagon-copy-hoist" , cl::init(Val: true), |
85 | cl::Hidden, cl::ZeroOrMore, |
86 | cl::desc("Enable Hexagon copy hoisting" )); |
87 | |
88 | static cl::opt<bool> |
89 | EnableGenInsert("hexagon-insert" , cl::init(Val: true), cl::Hidden, |
90 | cl::desc("Generate \"insert\" instructions" )); |
91 | |
92 | static cl::opt<bool> |
93 | EnableCommGEP("hexagon-commgep" , cl::init(Val: true), cl::Hidden, |
94 | cl::desc("Enable commoning of GEP instructions" )); |
95 | |
96 | static cl::opt<bool> |
97 | ("hexagon-extract" , cl::init(Val: true), cl::Hidden, |
98 | cl::desc("Generate \"extract\" instructions" )); |
99 | |
100 | static cl::opt<bool> EnableGenMux( |
101 | "hexagon-mux" , cl::init(Val: true), cl::Hidden, |
102 | cl::desc("Enable converting conditional transfers into MUX instructions" )); |
103 | |
104 | static cl::opt<bool> |
105 | EnableGenPred("hexagon-gen-pred" , cl::init(Val: true), cl::Hidden, |
106 | cl::desc("Enable conversion of arithmetic operations to " |
107 | "predicate instructions" )); |
108 | |
109 | static cl::opt<bool> |
110 | EnableLoopPrefetch("hexagon-loop-prefetch" , cl::Hidden, |
111 | cl::desc("Enable loop data prefetch on Hexagon" )); |
112 | |
113 | static cl::opt<bool> |
114 | DisableHSDR("disable-hsdr" , cl::init(Val: false), cl::Hidden, |
115 | cl::desc("Disable splitting double registers" )); |
116 | |
117 | static cl::opt<bool> |
118 | EnableGenMemAbs("hexagon-mem-abs" , cl::init(Val: true), cl::Hidden, |
119 | cl::desc("Generate absolute set instructions" )); |
120 | |
121 | static cl::opt<bool> EnableBitSimplify("hexagon-bit" , cl::init(Val: true), |
122 | cl::Hidden, |
123 | cl::desc("Bit simplification" )); |
124 | |
125 | static cl::opt<bool> EnableLoopResched("hexagon-loop-resched" , cl::init(Val: true), |
126 | cl::Hidden, |
127 | cl::desc("Loop rescheduling" )); |
128 | |
129 | static cl::opt<bool> HexagonNoOpt("hexagon-noopt" , cl::init(Val: false), cl::Hidden, |
130 | cl::desc("Disable backend optimizations" )); |
131 | |
132 | static cl::opt<bool> |
133 | EnableVectorPrint("enable-hexagon-vector-print" , cl::Hidden, |
134 | cl::desc("Enable Hexagon Vector print instr pass" )); |
135 | |
136 | static cl::opt<bool> |
137 | ("hexagon-opt-vextract" , cl::Hidden, cl::init(Val: true), |
138 | cl::desc("Enable vextract optimization" )); |
139 | |
140 | static cl::opt<bool> |
141 | EnableVectorCombine("hexagon-vector-combine" , cl::Hidden, cl::init(Val: true), |
142 | cl::desc("Enable HVX vector combining" )); |
143 | |
144 | static cl::opt<bool> EnableInitialCFGCleanup( |
145 | "hexagon-initial-cfg-cleanup" , cl::Hidden, cl::init(Val: true), |
146 | cl::desc("Simplify the CFG after atomic expansion pass" )); |
147 | |
148 | static cl::opt<bool> EnableInstSimplify("hexagon-instsimplify" , cl::Hidden, |
149 | cl::init(Val: true), |
150 | cl::desc("Enable instsimplify" )); |
151 | |
152 | /// HexagonTargetMachineModule - Note that this is used on hosts that |
153 | /// cannot link in a library unless there are references into the |
154 | /// library. In particular, it seems that it is not possible to get |
155 | /// things to work on Win32 without this. Though it is unused, do not |
156 | /// remove it. |
157 | extern "C" int HexagonTargetMachineModule; |
158 | int HexagonTargetMachineModule = 0; |
159 | |
160 | static ScheduleDAGInstrs *createVLIWMachineSched(MachineSchedContext *C) { |
161 | ScheduleDAGMILive *DAG = new VLIWMachineScheduler( |
162 | C, std::make_unique<HexagonConvergingVLIWScheduler>()); |
163 | DAG->addMutation(Mutation: std::make_unique<HexagonSubtarget::UsrOverflowMutation>()); |
164 | DAG->addMutation(Mutation: std::make_unique<HexagonSubtarget::HVXMemLatencyMutation>()); |
165 | DAG->addMutation(Mutation: std::make_unique<HexagonSubtarget::CallMutation>()); |
166 | DAG->addMutation(Mutation: createCopyConstrainDAGMutation(TII: DAG->TII, TRI: DAG->TRI)); |
167 | return DAG; |
168 | } |
169 | |
170 | static MachineSchedRegistry |
171 | SchedCustomRegistry("hexagon" , "Run Hexagon's custom scheduler" , |
172 | createVLIWMachineSched); |
173 | |
174 | static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { |
175 | return RM.value_or(u: Reloc::Static); |
176 | } |
177 | |
178 | extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void |
179 | LLVMInitializeHexagonTarget() { |
180 | // Register the target. |
181 | RegisterTargetMachine<HexagonTargetMachine> X(getTheHexagonTarget()); |
182 | |
183 | PassRegistry &PR = *PassRegistry::getPassRegistry(); |
184 | initializeHexagonAsmPrinterPass(PR); |
185 | initializeHexagonBitSimplifyPass(PR); |
186 | initializeHexagonConstExtendersPass(PR); |
187 | initializeHexagonConstPropagationPass(PR); |
188 | initializeHexagonCopyToCombinePass(PR); |
189 | initializeHexagonEarlyIfConversionPass(PR); |
190 | initializeHexagonGenMemAbsolutePass(PR); |
191 | initializeHexagonGenMuxPass(PR); |
192 | initializeHexagonHardwareLoopsPass(PR); |
193 | initializeHexagonLoopIdiomRecognizeLegacyPassPass(PR); |
194 | initializeHexagonNewValueJumpPass(PR); |
195 | initializeHexagonOptAddrModePass(PR); |
196 | initializeHexagonPacketizerPass(PR); |
197 | initializeHexagonRDFOptPass(PR); |
198 | initializeHexagonSplitDoubleRegsPass(PR); |
199 | initializeHexagonVectorCombineLegacyPass(PR); |
200 | initializeHexagonVectorLoopCarriedReuseLegacyPassPass(PR); |
201 | initializeHexagonVExtractPass(PR); |
202 | initializeHexagonDAGToDAGISelLegacyPass(PR); |
203 | initializeHexagonLoopReschedulingPass(PR); |
204 | initializeHexagonBranchRelaxationPass(PR); |
205 | initializeHexagonCFGOptimizerPass(PR); |
206 | initializeHexagonCommonGEPPass(PR); |
207 | initializeHexagonCopyHoistingPass(PR); |
208 | initializeHexagonExpandCondsetsPass(PR); |
209 | initializeHexagonLoopAlignPass(PR); |
210 | initializeHexagonTfrCleanupPass(PR); |
211 | initializeHexagonFixupHwLoopsPass(PR); |
212 | initializeHexagonCallFrameInformationPass(PR); |
213 | initializeHexagonGenExtractPass(PR); |
214 | initializeHexagonGenInsertPass(PR); |
215 | initializeHexagonGenPredicatePass(PR); |
216 | initializeHexagonLoadWideningPass(PR); |
217 | initializeHexagonStoreWideningPass(PR); |
218 | initializeHexagonMaskPass(PR); |
219 | initializeHexagonOptimizeSZextendsPass(PR); |
220 | initializeHexagonPeepholePass(PR); |
221 | initializeHexagonSplitConst32AndConst64Pass(PR); |
222 | initializeHexagonVectorPrintPass(PR); |
223 | } |
224 | |
225 | HexagonTargetMachine::HexagonTargetMachine(const Target &T, const Triple &TT, |
226 | StringRef CPU, StringRef FS, |
227 | const TargetOptions &Options, |
228 | std::optional<Reloc::Model> RM, |
229 | std::optional<CodeModel::Model> CM, |
230 | CodeGenOptLevel OL, bool JIT) |
231 | // Specify the vector alignment explicitly. For v512x1, the calculated |
232 | // alignment would be 512*alignment(i1), which is 512 bytes, instead of |
233 | // the required minimum of 64 bytes. |
234 | : CodeGenTargetMachineImpl( |
235 | T, |
236 | "e-m:e-p:32:32:32-a:0-n16:32-" |
237 | "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-" |
238 | "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048" , |
239 | TT, CPU, FS, Options, getEffectiveRelocModel(RM), |
240 | getEffectiveCodeModel(CM, Default: CodeModel::Small), |
241 | (HexagonNoOpt ? CodeGenOptLevel::None : OL)), |
242 | TLOF(std::make_unique<HexagonTargetObjectFile>()), |
243 | Subtarget(Triple(TT), CPU, FS, *this) { |
244 | initAsmInfo(); |
245 | } |
246 | |
247 | const HexagonSubtarget * |
248 | HexagonTargetMachine::getSubtargetImpl(const Function &F) const { |
249 | AttributeList FnAttrs = F.getAttributes(); |
250 | Attribute CPUAttr = FnAttrs.getFnAttr(Kind: "target-cpu" ); |
251 | Attribute FSAttr = FnAttrs.getFnAttr(Kind: "target-features" ); |
252 | |
253 | std::string CPU = |
254 | CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; |
255 | std::string FS = |
256 | FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; |
257 | // Append the preexisting target features last, so that +mattr overrides |
258 | // the "unsafe-fp-math" function attribute. |
259 | // Creating a separate target feature is not strictly necessary, it only |
260 | // exists to make "unsafe-fp-math" force creating a new subtarget. |
261 | |
262 | if (F.getFnAttribute(Kind: "unsafe-fp-math" ).getValueAsBool()) |
263 | FS = FS.empty() ? "+unsafe-fp" : "+unsafe-fp," + FS; |
264 | |
265 | auto &I = SubtargetMap[CPU + FS]; |
266 | if (!I) { |
267 | // This needs to be done before we create a new subtarget since any |
268 | // creation will depend on the TM and the code generation flags on the |
269 | // function that reside in TargetOptions. |
270 | resetTargetOptions(F); |
271 | I = std::make_unique<HexagonSubtarget>(args: TargetTriple, args&: CPU, args&: FS, args: *this); |
272 | } |
273 | return I.get(); |
274 | } |
275 | |
276 | void HexagonTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { |
277 | #define GET_PASS_REGISTRY "HexagonPassRegistry.def" |
278 | #include "llvm/Passes/TargetPassRegistry.inc" |
279 | |
280 | PB.registerLateLoopOptimizationsEPCallback( |
281 | C: [=](LoopPassManager &LPM, OptimizationLevel Level) { |
282 | LPM.addPass(Pass: HexagonLoopIdiomRecognitionPass()); |
283 | }); |
284 | PB.registerLoopOptimizerEndEPCallback( |
285 | C: [=](LoopPassManager &LPM, OptimizationLevel Level) { |
286 | LPM.addPass(Pass: HexagonVectorLoopCarriedReusePass()); |
287 | }); |
288 | } |
289 | |
290 | TargetTransformInfo |
291 | HexagonTargetMachine::getTargetTransformInfo(const Function &F) const { |
292 | return TargetTransformInfo(std::make_unique<HexagonTTIImpl>(args: this, args: F)); |
293 | } |
294 | |
295 | MachineFunctionInfo *HexagonTargetMachine::createMachineFunctionInfo( |
296 | BumpPtrAllocator &Allocator, const Function &F, |
297 | const TargetSubtargetInfo *STI) const { |
298 | return HexagonMachineFunctionInfo::create<HexagonMachineFunctionInfo>( |
299 | Allocator, F, STI); |
300 | } |
301 | |
302 | HexagonTargetMachine::~HexagonTargetMachine() = default; |
303 | |
304 | ScheduleDAGInstrs * |
305 | HexagonTargetMachine::createMachineScheduler(MachineSchedContext *C) const { |
306 | return createVLIWMachineSched(C); |
307 | } |
308 | |
309 | namespace { |
310 | /// Hexagon Code Generator Pass Configuration Options. |
311 | class HexagonPassConfig : public TargetPassConfig { |
312 | public: |
313 | HexagonPassConfig(HexagonTargetMachine &TM, PassManagerBase &PM) |
314 | : TargetPassConfig(TM, PM) {} |
315 | |
316 | HexagonTargetMachine &getHexagonTargetMachine() const { |
317 | return getTM<HexagonTargetMachine>(); |
318 | } |
319 | |
320 | void addIRPasses() override; |
321 | bool addInstSelector() override; |
322 | void addPreRegAlloc() override; |
323 | void addPostRegAlloc() override; |
324 | void addPreSched2() override; |
325 | void addPreEmitPass() override; |
326 | }; |
327 | } // namespace |
328 | |
329 | TargetPassConfig *HexagonTargetMachine::createPassConfig(PassManagerBase &PM) { |
330 | return new HexagonPassConfig(*this, PM); |
331 | } |
332 | |
333 | void HexagonPassConfig::addIRPasses() { |
334 | TargetPassConfig::addIRPasses(); |
335 | bool NoOpt = (getOptLevel() == CodeGenOptLevel::None); |
336 | |
337 | if (!NoOpt) { |
338 | if (EnableInstSimplify) |
339 | addPass(P: createInstSimplifyLegacyPass()); |
340 | addPass(P: createDeadCodeEliminationPass()); |
341 | } |
342 | |
343 | addPass(P: createAtomicExpandLegacyPass()); |
344 | |
345 | if (!NoOpt) { |
346 | if (EnableInitialCFGCleanup) |
347 | addPass(P: createCFGSimplificationPass(Options: SimplifyCFGOptions() |
348 | .forwardSwitchCondToPhi(B: true) |
349 | .convertSwitchRangeToICmp(B: true) |
350 | .convertSwitchToLookupTable(B: true) |
351 | .needCanonicalLoops(B: false) |
352 | .hoistCommonInsts(B: true) |
353 | .sinkCommonInsts(B: true))); |
354 | if (EnableLoopPrefetch) |
355 | addPass(P: createLoopDataPrefetchPass()); |
356 | if (EnableVectorCombine) |
357 | addPass(P: createHexagonVectorCombineLegacyPass()); |
358 | if (EnableCommGEP) |
359 | addPass(P: createHexagonCommonGEP()); |
360 | // Replace certain combinations of shifts and ands with extracts. |
361 | if (EnableGenExtract) |
362 | addPass(P: createHexagonGenExtract()); |
363 | } |
364 | } |
365 | |
366 | bool HexagonPassConfig::addInstSelector() { |
367 | HexagonTargetMachine &TM = getHexagonTargetMachine(); |
368 | bool NoOpt = (getOptLevel() == CodeGenOptLevel::None); |
369 | |
370 | if (!NoOpt) |
371 | addPass(P: createHexagonOptimizeSZextends()); |
372 | |
373 | addPass(P: createHexagonISelDag(TM, OptLevel: getOptLevel())); |
374 | |
375 | if (!NoOpt) { |
376 | if (EnableVExtractOpt) |
377 | addPass(P: createHexagonVExtract()); |
378 | // Create logical operations on predicate registers. |
379 | if (EnableGenPred) |
380 | addPass(P: createHexagonGenPredicate()); |
381 | // Rotate loops to expose bit-simplification opportunities. |
382 | if (EnableLoopResched) |
383 | addPass(P: createHexagonLoopRescheduling()); |
384 | // Split double registers. |
385 | if (!DisableHSDR) |
386 | addPass(P: createHexagonSplitDoubleRegs()); |
387 | // Bit simplification. |
388 | if (EnableBitSimplify) |
389 | addPass(P: createHexagonBitSimplify()); |
390 | addPass(P: createHexagonPeephole()); |
391 | // Constant propagation. |
392 | if (!DisableHCP) { |
393 | addPass(P: createHexagonConstPropagationPass()); |
394 | addPass(PassID: &UnreachableMachineBlockElimID); |
395 | } |
396 | if (EnableGenInsert) |
397 | addPass(P: createHexagonGenInsert()); |
398 | if (EnableEarlyIf) |
399 | addPass(P: createHexagonEarlyIfConversion()); |
400 | } |
401 | |
402 | return false; |
403 | } |
404 | |
405 | void HexagonPassConfig::addPreRegAlloc() { |
406 | if (getOptLevel() != CodeGenOptLevel::None) { |
407 | if (EnableCExtOpt) |
408 | addPass(P: createHexagonConstExtenders()); |
409 | if (EnableExpandCondsets) |
410 | insertPass(TargetPassID: &RegisterCoalescerID, InsertedPassID: &HexagonExpandCondsetsID); |
411 | if (EnableCopyHoist) |
412 | insertPass(TargetPassID: &RegisterCoalescerID, InsertedPassID: &HexagonCopyHoistingID); |
413 | if (EnableTfrCleanup) |
414 | insertPass(TargetPassID: &VirtRegRewriterID, InsertedPassID: &HexagonTfrCleanupID); |
415 | if (!DisableStoreWidening) |
416 | addPass(P: createHexagonStoreWidening()); |
417 | if (!DisableLoadWidening) |
418 | addPass(P: createHexagonLoadWidening()); |
419 | if (EnableGenMemAbs) |
420 | addPass(P: createHexagonGenMemAbsolute()); |
421 | if (!DisableHardwareLoops) |
422 | addPass(P: createHexagonHardwareLoops()); |
423 | } |
424 | if (TM->getOptLevel() >= CodeGenOptLevel::Default) |
425 | addPass(PassID: &MachinePipelinerID); |
426 | } |
427 | |
428 | void HexagonPassConfig::addPostRegAlloc() { |
429 | if (getOptLevel() != CodeGenOptLevel::None) { |
430 | if (EnableRDFOpt) |
431 | addPass(P: createHexagonRDFOpt()); |
432 | if (!DisableHexagonCFGOpt) |
433 | addPass(P: createHexagonCFGOptimizer()); |
434 | if (!DisableAModeOpt) |
435 | addPass(P: createHexagonOptAddrMode()); |
436 | } |
437 | } |
438 | |
439 | void HexagonPassConfig::addPreSched2() { |
440 | bool NoOpt = (getOptLevel() == CodeGenOptLevel::None); |
441 | addPass(P: createHexagonCopyToCombine()); |
442 | if (getOptLevel() != CodeGenOptLevel::None) |
443 | addPass(PassID: &IfConverterID); |
444 | addPass(P: createHexagonSplitConst32AndConst64()); |
445 | if (!NoOpt && !DisableHexagonMask) |
446 | addPass(P: createHexagonMask()); |
447 | } |
448 | |
449 | void HexagonPassConfig::addPreEmitPass() { |
450 | bool NoOpt = (getOptLevel() == CodeGenOptLevel::None); |
451 | |
452 | if (!NoOpt) |
453 | addPass(P: createHexagonNewValueJump()); |
454 | |
455 | addPass(P: createHexagonBranchRelaxation()); |
456 | |
457 | if (!NoOpt) { |
458 | if (!DisableHardwareLoops) |
459 | addPass(P: createHexagonFixupHwLoops()); |
460 | // Generate MUX from pairs of conditional transfers. |
461 | if (EnableGenMux) |
462 | addPass(P: createHexagonGenMux()); |
463 | } |
464 | |
465 | // Packetization is mandatory: it handles gather/scatter at all opt levels. |
466 | addPass(P: createHexagonPacketizer(Minimal: NoOpt)); |
467 | |
468 | if (!NoOpt) |
469 | addPass(P: createHexagonLoopAlign()); |
470 | |
471 | if (EnableVectorPrint) |
472 | addPass(P: createHexagonVectorPrint()); |
473 | |
474 | // Add CFI instructions if necessary. |
475 | addPass(P: createHexagonCallFrameInformation()); |
476 | } |
477 | |