LLVM 24.0.0git
HexagonSubtarget.cpp
Go to the documentation of this file.
1//===- HexagonSubtarget.cpp - Hexagon Subtarget Information ---------------===//
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// This file implements the Hexagon specific subclass of TargetSubtarget.
10//
11//===----------------------------------------------------------------------===//
12
13#include "HexagonSubtarget.h"
14#include "HexagonInstrInfo.h"
15#include "HexagonRegisterInfo.h"
17#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringRef.h"
26#include "llvm/IR/IntrinsicsHexagon.h"
30#include <algorithm>
31#include <cassert>
32#include <optional>
33
34using namespace llvm;
35
36#define DEBUG_TYPE "hexagon-subtarget"
37
38#define GET_SUBTARGETINFO_CTOR
39#define GET_SUBTARGETINFO_TARGET_DESC
40#include "HexagonGenSubtargetInfo.inc"
41
42static cl::opt<bool> EnableBSBSched("enable-bsb-sched", cl::Hidden,
43 cl::init(true));
44
45static cl::opt<bool> EnableTCLatencySched("enable-tc-latency-sched", cl::Hidden,
46 cl::init(false));
47
48static cl::opt<bool>
49 EnableDotCurSched("enable-cur-sched", cl::Hidden, cl::init(true),
50 cl::desc("Enable the scheduler to generate .cur"));
51
52static cl::opt<bool>
53 DisableHexagonMISched("disable-hexagon-misched", cl::Hidden,
54 cl::desc("Disable Hexagon MI Scheduling"));
55
57 "hexagon-long-calls", cl::Hidden,
58 cl::desc("If present, forces/disables the use of long calls"));
59
60static cl::opt<bool>
61 EnablePredicatedCalls("hexagon-pred-calls", cl::Hidden,
62 cl::desc("Consider calls to be predicable"));
63
64static cl::opt<bool> SchedPredsCloser("sched-preds-closer", cl::Hidden,
65 cl::init(true));
66
67static cl::opt<bool> SchedRetvalOptimization("sched-retval-optimization",
68 cl::Hidden, cl::init(true));
69
71 "hexagon-check-bank-conflict", cl::Hidden, cl::init(true),
72 cl::desc("Enable checking for cache bank conflicts"));
73
75 StringRef FS, const TargetMachine &TM)
76 : HexagonGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
77 OptLevel(TM.getOptLevel()),
78 CPUString(std::string(Hexagon_MC::selectHexagonCPU(CPU))),
79 TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)),
80 TLInfo(TM, *this), InstrItins(getInstrItineraryForCPU(CPUString)) {
82 // Beware of the default constructor of InstrItineraryData: it will
83 // reset all members to 0.
84 assert(InstrItins.Itineraries != nullptr && "InstrItins not initialized");
85}
86
89 std::optional<Hexagon::ArchEnum> ArchVer = Hexagon::getCpu(CPUString);
90 if (ArchVer)
91 HexagonArchVersion = *ArchVer;
92 else
93 llvm_unreachable("Unrecognized Hexagon processor version");
94
95 UseHVX128BOps = false;
96 UseHVX64BOps = false;
97 UseAudioOps = false;
98 UseLongCalls = false;
99
100 SubtargetFeatures Features(FS);
101
102 // Turn on QFloat if the HVX version is v68+.
103 // The function ParseSubtargetFeatures will set feature bits and initialize
104 // subtarget's variables all in one, so there isn't a good way to preprocess
105 // the feature string, other than by tinkering with it directly.
106 auto IsQFloatFS = [](StringRef F) {
107 return F == "+hvx-qfloat" || F == "-hvx-qfloat";
108 };
109 if (!llvm::count_if(Features.getFeatures(), IsQFloatFS)) {
110 auto getHvxVersion = [&Features](StringRef FS) -> StringRef {
111 for (StringRef F : llvm::reverse(Features.getFeatures())) {
112 if (F.starts_with("+hvxv"))
113 return F;
114 }
115 for (StringRef F : llvm::reverse(Features.getFeatures())) {
116 if (F == "-hvx")
117 return StringRef();
118 if (F.starts_with("+hvx") || F == "-hvx")
119 return F.take_front(4); // Return "+hvx" or "-hvx".
120 }
121 return StringRef();
122 };
123
124 bool AddQFloat = false;
125 StringRef HvxVer = getHvxVersion(FS);
126 if (HvxVer.starts_with("+hvxv")) {
127 int Ver = 0;
128 if (!HvxVer.drop_front(5).consumeInteger(10, Ver) && Ver >= 68)
129 AddQFloat = true;
130 } else if (HvxVer == "+hvx") {
131 if (hasV68Ops())
132 AddQFloat = true;
133 }
134
135 if (AddQFloat)
136 Features.AddFeature("+hvx-qfloat");
137 }
138
139 std::string FeatureString = Features.getString();
140 ParseSubtargetFeatures(CPUString, /*TuneCPU*/ CPUString, FeatureString);
141
142 // Resolve the shadow call stack pointer register. At most one "scs-reg-rN"
143 // feature may be given; R18 is the default. R18 is chosen because it is the
144 // lowest callee-saved register that neither the Hexagon Linux kernel (which
145 // reserves R19 for the thread-info pointer) nor code that reserves the upper
146 // callee-saved range already claims.
147 static_assert(Hexagon::R27 - Hexagon::R16 == 11,
148 "Callee-saved R16-R27 are assumed to be consecutive");
149 SCSPReg = Hexagon::R18;
150 bool SCSRegSelected = false;
151 for (unsigned Reg = Hexagon::R16; Reg <= Hexagon::R27; ++Reg) {
152 if (!SCSPointerRegister[Reg])
153 continue;
154 if (SCSRegSelected)
156 "Only one shadow call stack pointer register may be selected");
157 SCSPReg = Reg;
158 SCSRegSelected = true;
159 }
160
161 if (useHVXV68Ops())
162 UseHVXFloatingPoint = UseHVXIEEEFPOps || UseHVXQFloatOps;
163
164 if (UseHVXQFloatOps && UseHVXIEEEFPOps && UseHVXFloatingPoint)
166 dbgs() << "Behavior is undefined for simultaneous qfloat and ieee hvx codegen...");
167
168 if (OverrideLongCalls.getPosition())
169 UseLongCalls = OverrideLongCalls;
170
172
173 if (isTinyCore()) {
174 // Tiny core has a single thread, so back-to-back scheduling is enabled by
175 // default.
176 if (!EnableBSBSched.getPosition())
177 UseBSBScheduling = false;
178 }
179
180 FeatureBitset FeatureBits = getFeatureBits();
182 setFeatureBits(FeatureBits.reset(Hexagon::FeatureDuplex));
183 setFeatureBits(Hexagon_MC::completeHVXFeatures(FeatureBits));
184
185 return *this;
186}
187
189 LibcallLoweringInfo &Info) const {
190 // The generic arithmetic/division helper routines (__adddf3, __divsi3, ...)
191 // exist in Hexagon's compiler-rt alongside the preferred __hexagon_*
192 // variants, so both are available. The __hexagon_* variant is the one that
193 // must be used; select it explicitly here.
194 static const struct {
195 const RTLIB::Libcall Op;
196 const RTLIB::LibcallImpl Impl;
197 } LibraryCalls[] = {
198 {RTLIB::SDIV_I32, RTLIB::impl___hexagon_divsi3},
199 {RTLIB::SDIV_I64, RTLIB::impl___hexagon_divdi3},
200 {RTLIB::UDIV_I32, RTLIB::impl___hexagon_udivsi3},
201 {RTLIB::UDIV_I64, RTLIB::impl___hexagon_udivdi3},
202 {RTLIB::SREM_I32, RTLIB::impl___hexagon_modsi3},
203 {RTLIB::SREM_I64, RTLIB::impl___hexagon_moddi3},
204 {RTLIB::UREM_I32, RTLIB::impl___hexagon_umodsi3},
205 {RTLIB::UREM_I64, RTLIB::impl___hexagon_umoddi3},
206 {RTLIB::ADD_F64, RTLIB::impl___hexagon_adddf3},
207 {RTLIB::SUB_F64, RTLIB::impl___hexagon_subdf3},
208 {RTLIB::MUL_F64, RTLIB::impl___hexagon_muldf3},
209 {RTLIB::DIV_F64, RTLIB::impl___hexagon_divdf3},
210 {RTLIB::DIV_F32, RTLIB::impl___hexagon_divsf3},
211 };
212 for (const auto &LC : LibraryCalls)
213 Info.setLibcallImpl(LC.Op, LC.Impl);
214}
215
216bool HexagonSubtarget::isHVXElementType(MVT Ty, bool IncludeBool) const {
217 if (!useHVXOps())
218 return false;
219 if (Ty.isVector())
220 Ty = Ty.getVectorElementType();
221 if (IncludeBool && Ty == MVT::i1)
222 return true;
223 ArrayRef<MVT> ElemTypes = getHVXElementTypes();
224 return llvm::is_contained(ElemTypes, Ty);
225}
226
227bool HexagonSubtarget::isHVXVectorType(EVT VecTy, bool IncludeBool) const {
228 if (!VecTy.isSimple())
229 return false;
230 if (!VecTy.isVector() || !useHVXOps() || VecTy.isScalableVector())
231 return false;
233 if (!IncludeBool && ElemTy == MVT::i1)
234 return false;
235
236 unsigned HwLen = getVectorLength();
237 unsigned NumElems = VecTy.getVectorNumElements();
238 ArrayRef<MVT> ElemTypes = getHVXElementTypes();
239
240 if (IncludeBool && ElemTy == MVT::i1) {
241 // Boolean HVX vector types are formed from regular HVX vector types
242 // by replacing the element type with i1.
243 for (MVT T : ElemTypes)
244 if (NumElems * T.getSizeInBits() == 8 * HwLen)
245 return true;
246 return false;
247 }
248
249 unsigned VecWidth = VecTy.getSizeInBits();
250 if (VecWidth != 8 * HwLen && VecWidth != 16 * HwLen)
251 return false;
252 return llvm::is_contained(ElemTypes, ElemTy);
253}
254
255bool HexagonSubtarget::isTypeForHVX(Type *VecTy, bool IncludeBool) const {
256 if (!VecTy->isVectorTy() || isa<ScalableVectorType>(VecTy))
257 return false;
258 // HLX types have their own legalization path and never go through HVX.
259 if (useHLXOps() && isTypeForHLX(VecTy))
260 return false;
261 // Avoid types like <2 x i32*>.
262 Type *ScalTy = VecTy->getScalarType();
263 if (!ScalTy->isIntegerTy() &&
264 !(ScalTy->isFloatingPointTy() && useHVXFloatingPoint()))
265 return false;
266 // The given type may be something like <17 x i32>, which is not MVT,
267 // but can be represented as (non-simple) EVT.
268 EVT Ty = EVT::getEVT(VecTy, /*HandleUnknown*/false);
269 if (!Ty.getVectorElementType().isSimple())
270 return false;
271
272 auto isHvxTy = [this, IncludeBool](MVT SimpleTy) {
273 if (isHVXVectorType(SimpleTy, IncludeBool))
274 return true;
275 auto Action = getTargetLowering()->getPreferredVectorAction(SimpleTy);
277 };
278
279 // Round up EVT to have power-of-2 elements, and keep checking if it
280 // qualifies for HVX, dividing it in half after each step.
281 MVT ElemTy = Ty.getVectorElementType().getSimpleVT();
282 unsigned VecLen = PowerOf2Ceil(Ty.getVectorNumElements());
283 while (VecLen > 1) {
284 MVT SimpleTy = MVT::getVectorVT(ElemTy, VecLen);
285 if (SimpleTy.isValid() && isHvxTy(SimpleTy))
286 return true;
287 VecLen /= 2;
288 }
289
290 return false;
291}
292
294 if (!useHLXOps())
295 return false;
296 if (Ty.isVector())
297 Ty = Ty.getVectorElementType();
298 ArrayRef<MVT> ElemTypes = getHLXElementTypes();
299 return llvm::is_contained(ElemTypes, Ty);
300}
301
303 if (!VecTy.isSimple())
304 return false;
305 if (!VecTy.isVector() || !useHLXOps() || VecTy.isScalableVector())
306 return false;
308
309 unsigned HwLen = getHLXVectorLength();
310 ArrayRef<MVT> ElemTypes = getHLXElementTypes();
311
312 unsigned VecWidth = VecTy.getSizeInBits();
313 if (VecWidth != 8 * HwLen && VecWidth != 16 * HwLen)
314 return false;
315 return llvm::is_contained(ElemTypes, ElemTy);
316}
317
319 if (!VecTy->isVectorTy() || isa<ScalableVectorType>(VecTy))
320 return false;
321 // Avoid types like <2 x i32*>.
322 Type *ScalTy = VecTy->getScalarType();
323 if (!ScalTy->isIntegerTy() && !ScalTy->isFloatingPointTy())
324 return false;
325 // The given type may be something like <17 x i32>, which is not MVT,
326 // but can be represented as (non-simple) EVT.
327 EVT Ty = EVT::getEVT(VecTy, /*HandleUnknown*/ false);
328 if (!Ty.getVectorElementType().isSimple())
329 return false;
330
331 auto isHLXTy = [this](MVT SimpleTy) {
332 if (isHLXVectorType(SimpleTy))
333 return true;
334 // No widening for now
335 return false;
336 };
337
338 // Round up EVT to have power-of-2 elements, and keep checking if it
339 // qualifies for HLX, dividing it in half after each step.
340 MVT ElemTy = Ty.getVectorElementType().getSimpleVT();
341 unsigned VecLen = PowerOf2Ceil(Ty.getVectorNumElements());
342 while (VecLen > 1) {
343 MVT SimpleTy = MVT::getVectorVT(ElemTy, VecLen);
344 if (SimpleTy.isValid() && isHLXTy(SimpleTy))
345 return true;
346 VecLen /= 2;
347 }
348
349 return false;
350}
351
353 for (SUnit &SU : DAG->SUnits) {
354 if (!SU.isInstr())
355 continue;
357 for (auto &D : SU.Preds)
358 if (D.getKind() == SDep::Output && D.getReg() == Hexagon::USR_OVF)
359 Erase.push_back(D);
360 for (auto &E : Erase)
361 SU.removePred(E);
362 }
363}
364
366 for (SUnit &SU : DAG->SUnits) {
367 // Update the latency of chain edges between v60 vector load or store
368 // instructions to be 1. These instruction cannot be scheduled in the
369 // same packet.
370 MachineInstr &MI1 = *SU.getInstr();
371 auto *QII = static_cast<const HexagonInstrInfo*>(DAG->TII);
372 bool IsStoreMI1 = MI1.mayStore();
373 bool IsLoadMI1 = MI1.mayLoad();
374 if (!QII->isHVXVec(MI1) || !(IsStoreMI1 || IsLoadMI1))
375 continue;
376 for (SDep &SI : SU.Succs) {
377 if (SI.getKind() != SDep::Order || SI.getLatency() != 0)
378 continue;
379 MachineInstr &MI2 = *SI.getSUnit()->getInstr();
380 if (!QII->isHVXVec(MI2))
381 continue;
382 if ((IsStoreMI1 && MI2.mayStore()) || (IsLoadMI1 && MI2.mayLoad())) {
383 SI.setLatency(1);
384 SU.setHeightDirty();
385 // Change the dependence in the opposite direction too.
386 for (SDep &PI : SI.getSUnit()->Preds) {
387 if (PI.getSUnit() != &SU || PI.getKind() != SDep::Order)
388 continue;
389 PI.setLatency(1);
390 SI.getSUnit()->setDepthDirty();
391 }
392 }
393 }
394 }
395}
396
397// Check if a call and subsequent A2_tfrpi instructions should maintain
398// scheduling affinity. We are looking for the TFRI to be consumed in
399// the next instruction. This should help reduce the instances of
400// double register pairs being allocated and scheduled before a call
401// when not used until after the call. This situation is exacerbated
402// by the fact that we allocate the pair from the callee saves list,
403// leading to excess spills and restores.
404bool HexagonSubtarget::CallMutation::shouldTFRICallBind(
405 const HexagonInstrInfo &HII, const SUnit &Inst1,
406 const SUnit &Inst2) const {
407 if (Inst1.getInstr()->getOpcode() != Hexagon::A2_tfrpi)
408 return false;
409
410 // TypeXTYPE are 64 bit operations.
411 unsigned Type = HII.getType(*Inst2.getInstr());
414}
415
417 ScheduleDAGMI *DAG = static_cast<ScheduleDAGMI*>(DAGInstrs);
418 SUnit* LastSequentialCall = nullptr;
419 // Map from virtual register to physical register from the copy.
420 DenseMap<unsigned, unsigned> VRegHoldingReg;
421 // Map from the physical register to the instruction that uses virtual
422 // register. This is used to create the barrier edge.
423 DenseMap<unsigned, SUnit *> LastVRegUse;
424 auto &TRI = *DAG->MF.getSubtarget().getRegisterInfo();
425 auto &HII = *DAG->MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
426
427 // Currently we only catch the situation when compare gets scheduled
428 // before preceding call.
429 for (unsigned su = 0, e = DAG->SUnits.size(); su != e; ++su) {
430 // Remember the call.
431 if (DAG->SUnits[su].getInstr()->isCall())
432 LastSequentialCall = &DAG->SUnits[su];
433 // Look for a compare that defines a predicate.
434 else if (DAG->SUnits[su].getInstr()->isCompare() && LastSequentialCall)
435 DAG->addEdge(&DAG->SUnits[su], SDep(LastSequentialCall, SDep::Barrier));
436 // Look for call and tfri* instructions.
437 else if (SchedPredsCloser && LastSequentialCall && su > 1 && su < e-1 &&
438 shouldTFRICallBind(HII, DAG->SUnits[su], DAG->SUnits[su+1]))
439 DAG->addEdge(&DAG->SUnits[su], SDep(&DAG->SUnits[su-1], SDep::Barrier));
440 // Prevent redundant register copies due to reads and writes of physical
441 // registers. The original motivation for this was the code generated
442 // between two calls, which are caused both the return value and the
443 // argument for the next call being in %r0.
444 // Example:
445 // 1: <call1>
446 // 2: %vreg = COPY %r0
447 // 3: <use of %vreg>
448 // 4: %r0 = ...
449 // 5: <call2>
450 // The scheduler would often swap 3 and 4, so an additional register is
451 // needed. This code inserts a Barrier dependence between 3 & 4 to prevent
452 // this.
453 // The code below checks for all the physical registers, not just R0/D0/V0.
454 else if (SchedRetvalOptimization) {
455 const MachineInstr *MI = DAG->SUnits[su].getInstr();
456 if (MI->isCopy() && MI->getOperand(1).getReg().isPhysical()) {
457 // %vregX = COPY %r0
458 VRegHoldingReg[MI->getOperand(0).getReg()] = MI->getOperand(1).getReg();
459 LastVRegUse.erase(MI->getOperand(1).getReg());
460 } else {
461 for (const MachineOperand &MO : MI->operands()) {
462 if (!MO.isReg())
463 continue;
464 if (MO.isUse() && !MI->isCopy() &&
465 VRegHoldingReg.count(MO.getReg())) {
466 // <use of %vregX>
467 LastVRegUse[VRegHoldingReg[MO.getReg()]] = &DAG->SUnits[su];
468 } else if (MO.isDef() && MO.getReg().isPhysical()) {
469 for (MCRegAliasIterator AI(MO.getReg(), &TRI, true); AI.isValid();
470 ++AI) {
471 if (auto It = LastVRegUse.find(*AI); It != LastVRegUse.end()) {
472 if (It->second != &DAG->SUnits[su])
473 // %r0 = ...
474 DAG->addEdge(&DAG->SUnits[su],
475 SDep(It->second, SDep::Barrier));
476 LastVRegUse.erase(It);
477 }
478 }
479 }
480 }
481 }
482 }
483 }
484}
485
488 return;
489
490 const auto &HII = static_cast<const HexagonInstrInfo&>(*DAG->TII);
491
492 // Create artificial edges between loads that could likely cause a bank
493 // conflict. Since such loads would normally not have any dependency
494 // between them, we cannot rely on existing edges.
495 for (unsigned i = 0, e = DAG->SUnits.size(); i != e; ++i) {
496 SUnit &S0 = DAG->SUnits[i];
497 MachineInstr &L0 = *S0.getInstr();
498 if (!L0.mayLoad() || L0.mayStore() ||
500 continue;
501 int64_t Offset0;
503 MachineOperand *BaseOp0 = HII.getBaseAndOffset(L0, Offset0, Size0);
504 // Is the access size is longer than the L1 cache line, skip the check.
505 if (BaseOp0 == nullptr || !BaseOp0->isReg() || !Size0.hasValue() ||
506 Size0.getValue() >= 32)
507 continue;
508 // Scan only up to 32 instructions ahead (to avoid n^2 complexity).
509 for (unsigned j = i+1, m = std::min(i+32, e); j != m; ++j) {
510 SUnit &S1 = DAG->SUnits[j];
511 MachineInstr &L1 = *S1.getInstr();
512 if (!L1.mayLoad() || L1.mayStore() ||
514 continue;
515 int64_t Offset1;
517 MachineOperand *BaseOp1 = HII.getBaseAndOffset(L1, Offset1, Size1);
518 if (BaseOp1 == nullptr || !BaseOp1->isReg() || !Size0.hasValue() ||
519 Size1.getValue() >= 32 || BaseOp0->getReg() != BaseOp1->getReg())
520 continue;
521 // Check bits 3 and 4 of the offset: if they differ, a bank conflict
522 // is unlikely.
523 if (((Offset0 ^ Offset1) & 0x18) != 0)
524 continue;
525 // Bits 3 and 4 are the same, add an artificial edge and set extra
526 // latency.
527 SDep A(&S0, SDep::Artificial);
528 A.setLatency(1);
529 S1.addPred(A, true);
530 }
531 }
532}
533
535 const auto &HII = static_cast<const HexagonInstrInfo &>(*DAG->TII);
536 const auto &HST = DAG->MF.getSubtarget<HexagonSubtarget>();
537 if (!HST.useHLXOps())
538 return;
539
540 auto setLatency = [](SUnit &From, SUnit &To) {
541 for (SDep &Dep : From.Succs)
542 if (Dep.getSUnit() == &To && Dep.getKind() == SDep::Data)
543 Dep.setLatency(0);
544 for (SDep &Dep : To.Preds)
545 if (Dep.getSUnit() == &From && Dep.getKind() == SDep::Data)
546 Dep.setLatency(0);
547 };
548
549 for (SUnit &SU : DAG->SUnits) {
550 if (!SU.isInstr())
551 continue;
552
553 MachineInstr &MI = *SU.getInstr();
554 if (HII.isTmpLoadPseudo(MI)) {
555 for (SDep &Dep : SU.Succs)
556 if (Dep.getKind() == SDep::Data)
557 setLatency(SU, *Dep.getSUnit());
558 } else if (HII.isNewStorePseudo(MI)) {
559 for (SDep &Dep : SU.Preds)
560 if (Dep.getKind() == SDep::Data)
561 setLatency(*Dep.getSUnit(), SU);
562 }
563 }
564}
565
566/// Enable use of alias analysis during code generation (during MI
567/// scheduling, DAGCombine, etc.).
570 return true;
571 return false;
572}
573
574/// Perform target specific adjustments to the latency of a schedule
575/// dependency.
577 SUnit *Src, int SrcOpIdx, SUnit *Dst, int DstOpIdx, SDep &Dep,
578 const TargetSchedModel *SchedModel) const {
579 if (!Src->isInstr() || !Dst->isInstr())
580 return;
581
582 MachineInstr *SrcInst = Src->getInstr();
583 MachineInstr *DstInst = Dst->getInstr();
584 const HexagonInstrInfo *QII = getInstrInfo();
585
586 // Instructions with .new operands have zero latency.
589 if (QII->canExecuteInBundle(*SrcInst, *DstInst) &&
590 isBestZeroLatency(Src, Dst, QII, ExclSrc, ExclDst)) {
591 Dep.setLatency(0);
592 return;
593 }
594
595 // Set the latency for a copy to zero since we hope that is will get
596 // removed.
597 if (DstInst->isCopy())
598 Dep.setLatency(0);
599
600 // If it's a REG_SEQUENCE/COPY, use its destination instruction to determine
601 // the correct latency.
602 // If there are multiple uses of the def of COPY/REG_SEQUENCE, set the latency
603 // only if the latencies on all the uses are equal, otherwise set it to
604 // default.
605 if ((DstInst->isRegSequence() || DstInst->isCopy())) {
606 Register DReg = DstInst->getOperand(0).getReg();
607 std::optional<unsigned> DLatency;
608 for (const auto &DDep : Dst->Succs) {
609 MachineInstr *DDst = DDep.getSUnit()->getInstr();
610 int UseIdx = -1;
611 for (unsigned OpNum = 0; OpNum < DDst->getNumOperands(); OpNum++) {
612 const MachineOperand &MO = DDst->getOperand(OpNum);
613 if (MO.isReg() && MO.getReg() && MO.isUse() && MO.getReg() == DReg) {
614 UseIdx = OpNum;
615 break;
616 }
617 }
618
619 if (UseIdx == -1)
620 continue;
621
622 std::optional<unsigned> Latency =
623 InstrInfo.getOperandLatency(&InstrItins, *SrcInst, 0, *DDst, UseIdx);
624
625 // Set DLatency for the first time.
626 if (!DLatency)
627 DLatency = Latency;
628
629 // For multiple uses, if the Latency is different across uses, reset
630 // DLatency.
631 if (DLatency != Latency) {
632 DLatency = std::nullopt;
633 break;
634 }
635 }
636 Dep.setLatency(DLatency.value_or(0));
637 }
638
639 // Try to schedule uses near definitions to generate .cur.
640 ExclSrc.clear();
641 ExclDst.clear();
642 if (EnableDotCurSched && QII->isToBeScheduledASAP(*SrcInst, *DstInst) &&
643 isBestZeroLatency(Src, Dst, QII, ExclSrc, ExclDst)) {
644 Dep.setLatency(0);
645 return;
646 }
647 int Latency = Dep.getLatency();
648 bool IsArtificial = Dep.isArtificial();
649 Latency = updateLatency(*SrcInst, *DstInst, IsArtificial, Latency);
650 Dep.setLatency(Latency);
651}
652
654 std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const {
655 Mutations.push_back(std::make_unique<UsrOverflowMutation>());
656 Mutations.push_back(std::make_unique<HVXMemLatencyMutation>());
657 Mutations.push_back(std::make_unique<BankConflictMutation>());
658 Mutations.push_back(std::make_unique<HLXPseudoMutation>());
659}
660
662 std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const {
663 Mutations.push_back(std::make_unique<UsrOverflowMutation>());
664 Mutations.push_back(std::make_unique<HVXMemLatencyMutation>());
665}
666
667// Pin the vtable to this file.
668void HexagonSubtarget::anchor() {}
669
671 if (DisableHexagonMISched.getNumOccurrences())
672 return !DisableHexagonMISched;
673 return true;
674}
675
679
680int HexagonSubtarget::updateLatency(MachineInstr &SrcInst,
681 MachineInstr &DstInst, bool IsArtificial,
682 int Latency) const {
683 if (IsArtificial)
684 return 1;
685 if (!hasV60Ops())
686 return Latency;
687
688 const HexagonInstrInfo &QII = *getInstrInfo();
689 // BSB scheduling.
690 if (QII.isHVXVec(SrcInst) || useBSBScheduling())
691 Latency = (Latency + 1) >> 1;
692 return Latency;
693}
694
695void HexagonSubtarget::restoreLatency(SUnit *Src, SUnit *Dst) const {
696 MachineInstr *SrcI = Src->getInstr();
697 for (auto &I : Src->Succs) {
698 if (!I.isAssignedRegDep() || I.getSUnit() != Dst)
699 continue;
700 Register DepR = I.getReg();
701 int DefIdx = -1;
702 for (unsigned OpNum = 0; OpNum < SrcI->getNumOperands(); OpNum++) {
703 const MachineOperand &MO = SrcI->getOperand(OpNum);
704 bool IsSameOrSubReg = false;
705 if (MO.isReg()) {
706 Register MOReg = MO.getReg();
707 if (DepR.isVirtual()) {
708 IsSameOrSubReg = (MOReg == DepR);
709 } else {
710 IsSameOrSubReg = getRegisterInfo()->isSubRegisterEq(DepR, MOReg);
711 }
712 if (MO.isDef() && IsSameOrSubReg)
713 DefIdx = OpNum;
714 }
715 }
716 assert(DefIdx >= 0 && "Def Reg not found in Src MI");
717 MachineInstr *DstI = Dst->getInstr();
718 SDep T = I;
719 for (unsigned OpNum = 0; OpNum < DstI->getNumOperands(); OpNum++) {
720 const MachineOperand &MO = DstI->getOperand(OpNum);
721 if (MO.isReg() && MO.isUse() && MO.getReg() == DepR) {
722 std::optional<unsigned> Latency = InstrInfo.getOperandLatency(
723 &InstrItins, *SrcI, DefIdx, *DstI, OpNum);
724
725 // For some instructions (ex: COPY), we might end up with < 0 latency
726 // as they don't have any Itinerary class associated with them.
727 if (!Latency)
728 Latency = 0;
729 bool IsArtificial = I.isArtificial();
730 Latency = updateLatency(*SrcI, *DstI, IsArtificial, *Latency);
731 I.setLatency(*Latency);
732 }
733 }
734
735 // Update the latency of opposite edge too.
736 T.setSUnit(Src);
737 auto F = find(Dst->Preds, T);
738 assert(F != Dst->Preds.end());
739 F->setLatency(I.getLatency());
740 }
741}
742
743/// Change the latency between the two SUnits.
744void HexagonSubtarget::changeLatency(SUnit *Src, SUnit *Dst, unsigned Lat)
745 const {
746 for (auto &I : Src->Succs) {
747 if (!I.isAssignedRegDep() || I.getSUnit() != Dst)
748 continue;
749 SDep T = I;
750 I.setLatency(Lat);
751
752 // Update the latency of opposite edge too.
753 T.setSUnit(Src);
754 auto F = find(Dst->Preds, T);
755 assert(F != Dst->Preds.end());
756 F->setLatency(Lat);
757 }
758}
759
760/// If the SUnit has a zero latency edge, return the other SUnit.
762 for (auto &I : Deps)
763 if (I.isAssignedRegDep() && I.getLatency() == 0 &&
764 !I.getSUnit()->getInstr()->isPseudo())
765 return I.getSUnit();
766 return nullptr;
767}
768
769// Return true if these are the best two instructions to schedule
770// together with a zero latency. Only one dependence should have a zero
771// latency. If there are multiple choices, choose the best, and change
772// the others, if needed.
773bool HexagonSubtarget::isBestZeroLatency(
774 SUnit *Src, SUnit *Dst, const HexagonInstrInfo *TII,
775 SmallPtrSet<SUnit *, 4> &ExclSrc, SmallPtrSet<SUnit *, 4> &ExclDst) const {
776 MachineInstr &SrcInst = *Src->getInstr();
777 MachineInstr &DstInst = *Dst->getInstr();
778
779 // Ignore Boundary SU nodes as these have null instructions.
780 if (Dst->isBoundaryNode())
781 return false;
782
783 if (SrcInst.isPHI() || DstInst.isPHI())
784 return false;
785
786 if (!TII->isToBeScheduledASAP(SrcInst, DstInst) &&
787 !TII->canExecuteInBundle(SrcInst, DstInst))
788 return false;
789
790 // The architecture doesn't allow three dependent instructions in the same
791 // packet. So, if the destination has a zero latency successor, then it's
792 // not a candidate for a zero latency predecessor.
793 if (getZeroLatency(Dst, Dst->Succs) != nullptr)
794 return false;
795
796 // Check if the Dst instruction is the best candidate first.
797 SUnit *Best = nullptr;
798 SUnit *DstBest = nullptr;
799 SUnit *SrcBest = getZeroLatency(Dst, Dst->Preds);
800 if (SrcBest == nullptr || Src->NodeNum >= SrcBest->NodeNum) {
801 // Check that Src doesn't have a better candidate.
802 DstBest = getZeroLatency(Src, Src->Succs);
803 if (DstBest == nullptr || Dst->NodeNum <= DstBest->NodeNum)
804 Best = Dst;
805 }
806 if (Best != Dst)
807 return false;
808
809 // The caller frequently adds the same dependence twice. If so, then
810 // return true for this case too.
811 if ((Src == SrcBest && Dst == DstBest ) ||
812 (SrcBest == nullptr && Dst == DstBest) ||
813 (Src == SrcBest && Dst == nullptr))
814 return true;
815
816 // Reassign the latency for the previous bests, which requires setting
817 // the dependence edge in both directions.
818 if (SrcBest != nullptr) {
819 if (!hasV60Ops())
820 changeLatency(SrcBest, Dst, 1);
821 else
822 restoreLatency(SrcBest, Dst);
823 }
824 if (DstBest != nullptr) {
825 if (!hasV60Ops())
826 changeLatency(Src, DstBest, 1);
827 else
828 restoreLatency(Src, DstBest);
829 }
830
831 // Attempt to find another opportunity for zero latency in a different
832 // dependence.
833 if (SrcBest && DstBest)
834 // If there is an edge from SrcBest to DstBst, then try to change that
835 // to 0 now.
836 changeLatency(SrcBest, DstBest, 0);
837 else if (DstBest) {
838 // Check if the previous best destination instruction has a new zero
839 // latency dependence opportunity.
840 ExclSrc.insert(Src);
841 for (auto &I : DstBest->Preds)
842 if (ExclSrc.count(I.getSUnit()) == 0 &&
843 isBestZeroLatency(I.getSUnit(), DstBest, TII, ExclSrc, ExclDst))
844 changeLatency(I.getSUnit(), DstBest, 0);
845 } else if (SrcBest) {
846 // Check if previous best source instruction has a new zero latency
847 // dependence opportunity.
848 ExclDst.insert(Dst);
849 for (auto &I : SrcBest->Succs)
850 if (ExclDst.count(I.getSUnit()) == 0 &&
851 isBestZeroLatency(SrcBest, I.getSUnit(), TII, ExclSrc, ExclDst))
852 changeLatency(SrcBest, I.getSUnit(), 0);
853 }
854
855 return true;
856}
857
859 return 32;
860}
861
863 return 32;
864}
865
866bool HexagonSubtarget::enableSubRegLiveness() const { return true; }
867
869 struct Scalar {
870 unsigned Opcode;
871 Intrinsic::ID IntId;
872 };
873 struct Hvx {
874 unsigned Opcode;
875 Intrinsic::ID Int64Id, Int128Id;
876 };
877
878 static Scalar ScalarInts[] = {
879#define GET_SCALAR_INTRINSICS
881#undef GET_SCALAR_INTRINSICS
882 };
883
884 static Hvx HvxInts[] = {
885#define GET_HVX_INTRINSICS
887#undef GET_HVX_INTRINSICS
888 };
889
890 const auto CmpOpcode = [](auto A, auto B) { return A.Opcode < B.Opcode; };
891 [[maybe_unused]] static bool SortedScalar =
892 (llvm::sort(ScalarInts, CmpOpcode), true);
893 [[maybe_unused]] static bool SortedHvx =
894 (llvm::sort(HvxInts, CmpOpcode), true);
895
896 auto [BS, ES] = std::make_pair(std::begin(ScalarInts), std::end(ScalarInts));
897 auto [BH, EH] = std::make_pair(std::begin(HvxInts), std::end(HvxInts));
898
899 auto FoundScalar = std::lower_bound(BS, ES, Scalar{Opc, 0}, CmpOpcode);
900 if (FoundScalar != ES && FoundScalar->Opcode == Opc)
901 return FoundScalar->IntId;
902
903 auto FoundHvx = std::lower_bound(BH, EH, Hvx{Opc, 0, 0}, CmpOpcode);
904 if (FoundHvx != EH && FoundHvx->Opcode == Opc) {
905 unsigned HwLen = getVectorLength();
906 if (HwLen == 64)
907 return FoundHvx->Int64Id;
908 if (HwLen == 128)
909 return FoundHvx->Int128Id;
910 }
911
912 std::string error = "Invalid opcode (" + std::to_string(Opc) + ")";
913 llvm_unreachable(error.c_str());
914 return 0;
915}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT S1
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static cl::opt< bool > DisableHexagonMISched("disable-hexagon-misched", cl::Hidden, cl::desc("Disable Hexagon MI Scheduling"))
static cl::opt< bool > EnableDotCurSched("enable-cur-sched", cl::Hidden, cl::init(true), cl::desc("Enable the scheduler to generate .cur"))
static cl::opt< bool > EnableCheckBankConflict("hexagon-check-bank-conflict", cl::Hidden, cl::init(true), cl::desc("Enable checking for cache bank conflicts"))
static cl::opt< bool > OverrideLongCalls("hexagon-long-calls", cl::Hidden, cl::desc("If present, forces/disables the use of long calls"))
static cl::opt< bool > SchedPredsCloser("sched-preds-closer", cl::Hidden, cl::init(true))
static cl::opt< bool > SchedRetvalOptimization("sched-retval-optimization", cl::Hidden, cl::init(true))
static cl::opt< bool > EnableTCLatencySched("enable-tc-latency-sched", cl::Hidden, cl::init(false))
static cl::opt< bool > EnableBSBSched("enable-bsb-sched", cl::Hidden, cl::init(true))
static SUnit * getZeroLatency(SUnit *N, SmallVector< SDep, 4 > &Deps)
If the SUnit has a zero latency edge, return the other SUnit.
static cl::opt< bool > EnablePredicatedCalls("hexagon-pred-calls", cl::Hidden, cl::desc("Consider calls to be predicable"))
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
#define T
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define error(X)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:762
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
bool erase(const KeyT &Val)
Definition DenseMap.h:930
Container class for subtarget features.
constexpr FeatureBitset & reset(unsigned I)
bool isTmpLoadPseudo(const MachineInstr &MI) const
unsigned getAddrMode(const MachineInstr &MI) const
bool canExecuteInBundle(const MachineInstr &First, const MachineInstr &Second) const
Can these instructions execute at the same time in a bundle.
bool isNewStorePseudo(const MachineInstr &MI) const
bool isHVXVec(const MachineInstr &MI) const
bool isToBeScheduledASAP(const MachineInstr &MI1, const MachineInstr &MI2) const
MachineOperand * getBaseAndOffset(const MachineInstr &MI, int64_t &Offset, LocationSize &AccessSize) const
uint64_t getType(const MachineInstr &MI) const
Hexagon::ArchEnum HexagonArchVersion
void adjustSchedDependency(SUnit *Def, int DefOpIdx, SUnit *Use, int UseOpIdx, SDep &Dep, const TargetSchedModel *SchedModel) const override
Perform target specific adjustments to the latency of a schedule dependency.
bool isTypeForHLX(Type *VecTy) const
const HexagonInstrInfo * getInstrInfo() const override
unsigned getHLXVectorLength() const
const HexagonRegisterInfo * getRegisterInfo() const override
void getSMSMutations(std::vector< std::unique_ptr< ScheduleDAGMutation > > &Mutations) const override
HexagonSubtarget(const Triple &TT, StringRef CPU, StringRef FS, const TargetMachine &TM)
bool isHVXVectorType(EVT VecTy, bool IncludeBool=false) const
ArrayRef< MVT > getHLXElementTypes() const
void getPostRAMutations(std::vector< std::unique_ptr< ScheduleDAGMutation > > &Mutations) const override
const HexagonTargetLowering * getTargetLowering() const override
bool UseBSBScheduling
True if the target should use Back-Skip-Back scheduling.
unsigned getL1PrefetchDistance() const
ArrayRef< MVT > getHVXElementTypes() const
bool enableSubRegLiveness() const override
unsigned getVectorLength() const
void initLibcallLoweringInfo(LibcallLoweringInfo &Info) const override
bool isHLXElementType(MVT Ty) const
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS)
ParseSubtargetFeatures - Parses features string setting specified subtarget options.
unsigned getL1CacheLineSize() const
bool isTypeForHVX(Type *VecTy, bool IncludeBool=false) const
Intrinsic::ID getIntrinsicId(unsigned Opc) const
HexagonSubtarget & initializeSubtargetDependencies(StringRef CPU, StringRef FS)
bool enableMachineScheduler() const override
bool isHLXVectorType(EVT VecTy) const
bool isHVXElementType(MVT Ty, bool IncludeBool=false) const
bool useAA() const override
Enable use of alias analysis during code generation (during MI scheduling, DAGCombine,...
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
Tracks which library functions to use for a particular subtarget or function.
bool hasValue() const
static LocationSize precise(uint64_t Value)
TypeSize getValue() const
MCRegAliasIterator enumerates all registers aliasing Reg.
Machine Value Type.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isValid() const
Return true if this is a valid simple valuetype.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isCopy() const
unsigned getNumOperands() const
Retuns the total number of operands.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool isRegSequence() const
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Scheduling dependency.
Definition ScheduleDAG.h:54
SUnit * getSUnit() const
Kind getKind() const
Returns an enum value representing the kind of the dependence.
@ Output
A register output-dependence (aka WAW).
Definition ScheduleDAG.h:60
@ Order
Any other ordering dependency.
Definition ScheduleDAG.h:61
@ Data
Regular data dependence (aka true-dependence).
Definition ScheduleDAG.h:58
void setLatency(unsigned Lat)
Sets the latency for this edge.
@ Barrier
An unknown scheduling barrier.
Definition ScheduleDAG.h:74
@ Artificial
Arbitrary strong DAG edge (no real dependence).
Definition ScheduleDAG.h:77
unsigned getLatency() const
Returns the latency value for this edge, which roughly means the minimum number of cycles that must e...
bool isArtificial() const
Tests if this is an Order dependence that is marked as "artificial", meaning it isn't necessary for c...
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
unsigned NodeNum
Entry # of node in the node vector.
LLVM_ABI void setHeightDirty()
Sets a flag in this node to indicate that its stored Height value will require recomputation the next...
LLVM_ABI void removePred(const SDep &D)
Removes the specified edge as a pred of the current node if it exists.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
A ScheduleDAG for scheduling lists of MachineInstr.
bool addEdge(SUnit *SuccSU, const SDep &PredDep)
Add a DAG edge to the given SU with the given predecessor dependence data.
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
const TargetInstrInfo * TII
Target instruction information.
std::vector< SUnit > SUnits
The scheduling units.
MachineFunction & MF
Machine function.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
Definition StringRef.h:519
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:635
Manages the enabling and disabling of subtarget specific features.
const std::vector< std::string > & getFeatures() const
Returns the vector of individual subtarget features.
LLVM_ABI std::string getString() const
Returns features as a string.
LLVM_ABI void AddFeature(StringRef String, bool Enable=true)
Adds Features.
Primary interface to the complete machine description for the target machine.
Provide an instruction scheduling machine model to CodeGen passes.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:283
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:363
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS)
FeatureBitset completeHVXFeatures(const FeatureBitset &FB)
std::optional< Hexagon::ArchEnum > getCpu(StringRef CPU)
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1781
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
Definition STLExtras.h:2035
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
cl::opt< bool > HexagonDisableDuplex
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:879
#define N
Extended Value Type.
Definition ValueTypes.h:35
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:160
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:411
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:354
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:191
bool isScalableVector() const
Return true if this is a vector type where the runtime length is machine dependent.
Definition ValueTypes.h:202
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:374
void apply(ScheduleDAGInstrs *DAG) override
void apply(ScheduleDAGInstrs *DAG) override
void apply(ScheduleDAGInstrs *DAG) override
void apply(ScheduleDAGInstrs *DAG) override
void apply(ScheduleDAGInstrs *DAG) override