LLVM 24.0.0git
SIPeepholeSDWA.cpp
Go to the documentation of this file.
1//===- SIPeepholeSDWA.cpp - Peephole optimization for SDWA instructions ---===//
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/// \file This pass tries to apply several peephole SDWA patterns.
10///
11/// E.g. original:
12/// V_LSHRREV_B32_e32 %0, 16, %1
13/// V_ADD_CO_U32_e32 %2, %0, %3
14/// V_LSHLREV_B32_e32 %4, 16, %2
15///
16/// Replace:
17/// V_ADD_CO_U32_sdwa %4, %1, %3
18/// dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
19///
20//===----------------------------------------------------------------------===//
21
22#include "SIPeepholeSDWA.h"
23#include "AMDGPU.h"
24#include "GCNSubtarget.h"
26#include "llvm/ADT/MapVector.h"
27#include "llvm/ADT/Statistic.h"
30#include <optional>
31
32using namespace llvm;
33
34#define DEBUG_TYPE "si-peephole-sdwa"
35
36STATISTIC(NumSDWAPatternsFound, "Number of SDWA patterns found.");
37STATISTIC(NumSDWAInstructionsPeepholed,
38 "Number of instruction converted to SDWA.");
39
40namespace {
41
42bool isConvertibleToSDWA(MachineInstr &MI, const GCNSubtarget &ST,
43 const SIInstrInfo *TII);
44class SDWAOperand;
45class SDWADstOperand;
46
47using SDWAOperandsVector = SmallVector<SDWAOperand *, 4>;
49
50class SIPeepholeSDWA {
51private:
53 const SIRegisterInfo *TRI;
54 const SIInstrInfo *TII;
55
57 SDWAOperandsMap PotentialMatches;
58 SmallVector<MachineInstr *, 8> ConvertedInstructions;
59
60 std::optional<int64_t> foldToImm(const MachineOperand &Op) const;
61
62 void matchSDWAOperands(MachineBasicBlock &MBB);
63 std::unique_ptr<SDWAOperand> matchSDWAOperand(MachineInstr &MI);
64 void pseudoOpConvertToVOP2(MachineInstr &MI,
65 const GCNSubtarget &ST) const;
66 void convertVcndmaskToVOP2(MachineInstr &MI, const GCNSubtarget &ST) const;
67 MachineInstr *createSDWAVersion(MachineInstr &MI);
68 bool convertToSDWA(MachineInstr &MI, const SDWAOperandsVector &SDWAOperands);
69 void legalizeScalarOperands(MachineInstr &MI, const GCNSubtarget &ST) const;
70
71public:
72 bool run(MachineFunction &MF);
73};
74
75class SIPeepholeSDWALegacy : public MachineFunctionPass {
76public:
77 static char ID;
78
79 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
80
81 StringRef getPassName() const override { return "SI Peephole SDWA"; }
82
83 bool runOnMachineFunction(MachineFunction &MF) override;
84
85 void getAnalysisUsage(AnalysisUsage &AU) const override {
86 AU.setPreservesCFG();
87 AU.addPreserved<MachineRegisterClassInfoWrapperPass>();
89 }
90};
91
92using namespace AMDGPU::SDWA;
93
94class SDWAOperand {
95private:
96 MachineOperand *Target; // Operand that would be used in converted instruction
97 MachineOperand *Replaced; // Operand that would be replace by Target
98
99 /// Returns true iff the SDWA selection of this SDWAOperand can be combined
100 /// with the SDWA selections of its uses in \p MI.
101 virtual bool canCombineSelections(const MachineInstr &MI,
102 const SIInstrInfo *TII) = 0;
103
104public:
105 SDWAOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp)
106 : Target(TargetOp), Replaced(ReplacedOp) {
107 assert(Target->isReg());
108 assert(Replaced->isReg());
109 }
110
111 virtual ~SDWAOperand() = default;
112
113 virtual MachineInstr *potentialToConvert(const SIInstrInfo *TII,
114 const GCNSubtarget &ST,
115 SDWAOperandsMap *PotentialMatches = nullptr) = 0;
116 virtual bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) = 0;
117
118 MachineOperand *getTargetOperand() const { return Target; }
119 MachineOperand *getReplacedOperand() const { return Replaced; }
120 MachineInstr *getParentInst() const { return Target->getParent(); }
121
122 MachineRegisterInfo *getMRI() const {
123 return &getParentInst()->getMF()->getRegInfo();
124 }
125
126#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
127 virtual void print(raw_ostream& OS) const = 0;
128 void dump() const { print(dbgs()); }
129#endif
130};
131
132class SDWASrcOperand : public SDWAOperand {
133private:
134 SdwaSel SrcSel;
135 bool Abs;
136 bool Neg;
137 bool Sext;
138
139public:
140 SDWASrcOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
141 SdwaSel SrcSel_ = DWORD, bool Abs_ = false, bool Neg_ = false,
142 bool Sext_ = false)
143 : SDWAOperand(TargetOp, ReplacedOp), SrcSel(SrcSel_), Abs(Abs_),
144 Neg(Neg_), Sext(Sext_) {}
145
146 MachineInstr *potentialToConvert(const SIInstrInfo *TII,
147 const GCNSubtarget &ST,
148 SDWAOperandsMap *PotentialMatches = nullptr) override;
149 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
150 bool canCombineSelections(const MachineInstr &MI,
151 const SIInstrInfo *TII) override;
152
153 SdwaSel getSrcSel() const { return SrcSel; }
154 bool getAbs() const { return Abs; }
155 bool getNeg() const { return Neg; }
156 bool getSext() const { return Sext; }
157
158 uint64_t getSrcMods(const SIInstrInfo *TII,
159 const MachineOperand *SrcOp) const;
160
161#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
162 void print(raw_ostream& OS) const override;
163#endif
164};
165
166class SDWADstOperand : public SDWAOperand {
167private:
168 SdwaSel DstSel;
169 DstUnused DstUn;
170
171public:
172 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
173 SdwaSel DstSel_ = DWORD, DstUnused DstUn_ = UNUSED_PAD)
174 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
175
176 MachineInstr *potentialToConvert(const SIInstrInfo *TII,
177 const GCNSubtarget &ST,
178 SDWAOperandsMap *PotentialMatches = nullptr) override;
179 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
180 bool canCombineSelections(const MachineInstr &MI,
181 const SIInstrInfo *TII) override;
182
183 SdwaSel getDstSel() const { return DstSel; }
184 DstUnused getDstUnused() const { return DstUn; }
185
186#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
187 void print(raw_ostream& OS) const override;
188#endif
189};
190
191class SDWADstPreserveOperand : public SDWADstOperand {
192private:
193 MachineOperand *Preserve;
194
195public:
196 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
197 MachineOperand *PreserveOp, SdwaSel DstSel_ = DWORD)
198 : SDWADstOperand(TargetOp, ReplacedOp, DstSel_, UNUSED_PRESERVE),
199 Preserve(PreserveOp) {}
200
201 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
202 bool canCombineSelections(const MachineInstr &MI,
203 const SIInstrInfo *TII) override;
204
205 MachineOperand *getPreservedOperand() const { return Preserve; }
206
207#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
208 void print(raw_ostream& OS) const override;
209#endif
210};
211
212} // end anonymous namespace
213
214INITIALIZE_PASS(SIPeepholeSDWALegacy, DEBUG_TYPE, "SI Peephole SDWA", false,
215 false)
216
217char SIPeepholeSDWALegacy::ID = 0;
218
219char &llvm::SIPeepholeSDWALegacyID = SIPeepholeSDWALegacy::ID;
220
222 return new SIPeepholeSDWALegacy();
223}
224
225#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
227 switch(Sel) {
228 case BYTE_0: OS << "BYTE_0"; break;
229 case BYTE_1: OS << "BYTE_1"; break;
230 case BYTE_2: OS << "BYTE_2"; break;
231 case BYTE_3: OS << "BYTE_3"; break;
232 case WORD_0: OS << "WORD_0"; break;
233 case WORD_1: OS << "WORD_1"; break;
234 case DWORD: OS << "DWORD"; break;
235 }
236 return OS;
237}
238
240 switch(Un) {
241 case UNUSED_PAD: OS << "UNUSED_PAD"; break;
242 case UNUSED_SEXT: OS << "UNUSED_SEXT"; break;
243 case UNUSED_PRESERVE: OS << "UNUSED_PRESERVE"; break;
244 }
245 return OS;
246}
247
249void SDWASrcOperand::print(raw_ostream& OS) const {
250 OS << "SDWA src: " << *getTargetOperand()
251 << " src_sel:" << getSrcSel()
252 << " abs:" << getAbs() << " neg:" << getNeg()
253 << " sext:" << getSext() << '\n';
254}
255
257void SDWADstOperand::print(raw_ostream& OS) const {
258 OS << "SDWA dst: " << *getTargetOperand()
259 << " dst_sel:" << getDstSel()
260 << " dst_unused:" << getDstUnused() << '\n';
261}
262
264void SDWADstPreserveOperand::print(raw_ostream& OS) const {
265 OS << "SDWA preserve dst: " << *getTargetOperand()
266 << " dst_sel:" << getDstSel()
267 << " preserve:" << *getPreservedOperand() << '\n';
268}
269
270#endif
271
272static void copyRegOperand(MachineOperand &To, const MachineOperand &From) {
273 assert(To.isReg() && From.isReg());
274 To.setReg(From.getReg());
275 To.setSubReg(From.getSubReg());
276 To.setIsUndef(From.isUndef());
277 if (To.isUse()) {
278 To.setIsKill(From.isKill());
279 } else {
280 To.setIsDead(From.isDead());
281 }
282}
283
284static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS) {
285 return LHS.isReg() &&
286 RHS.isReg() &&
287 LHS.getReg() == RHS.getReg() &&
288 LHS.getSubReg() == RHS.getSubReg();
289}
290
292 const MachineRegisterInfo *MRI) {
293 if (!Reg->isReg() || !Reg->isDef())
294 return nullptr;
295
296 return MRI->getOneNonDBGUse(Reg->getReg());
297}
298
300 const MachineRegisterInfo *MRI) {
301 if (!Reg->isReg())
302 return nullptr;
303
304 return MRI->getOneDef(Reg->getReg());
305}
306
307/// Combine an SDWA instruction's existing SDWA selection \p Sel with
308/// the SDWA selection \p OperandSel of its operand. If the selections
309/// are compatible, return the combined selection, otherwise return a
310/// nullopt.
311/// For example, if we have Sel = BYTE_0 Sel and OperandSel = WORD_1:
312/// BYTE_0 Sel (WORD_1 Sel (%X)) -> BYTE_2 Sel (%X)
313static std::optional<SdwaSel> combineSdwaSel(SdwaSel Sel, SdwaSel OperandSel) {
314 if (Sel == SdwaSel::DWORD)
315 return OperandSel;
316
317 if (Sel == OperandSel || OperandSel == SdwaSel::DWORD)
318 return Sel;
319
320 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
321 Sel == SdwaSel::BYTE_3)
322 return {};
323
324 if (OperandSel == SdwaSel::WORD_0)
325 return Sel;
326
327 if (OperandSel == SdwaSel::WORD_1) {
328 if (Sel == SdwaSel::BYTE_0)
329 return SdwaSel::BYTE_2;
330 if (Sel == SdwaSel::BYTE_1)
331 return SdwaSel::BYTE_3;
332 if (Sel == SdwaSel::WORD_0)
333 return SdwaSel::WORD_1;
334 }
335
336 return {};
337}
338
339uint64_t SDWASrcOperand::getSrcMods(const SIInstrInfo *TII,
340 const MachineOperand *SrcOp) const {
341 uint64_t Mods = 0;
342 const auto *MI = SrcOp->getParent();
343 if (TII->getNamedOperand(*MI, AMDGPU::OpName::src0) == SrcOp) {
344 if (auto *Mod = TII->getNamedOperand(*MI, AMDGPU::OpName::src0_modifiers)) {
345 Mods = Mod->getImm();
346 }
347 } else if (TII->getNamedOperand(*MI, AMDGPU::OpName::src1) == SrcOp) {
348 if (auto *Mod = TII->getNamedOperand(*MI, AMDGPU::OpName::src1_modifiers)) {
349 Mods = Mod->getImm();
350 }
351 }
352 if (Abs || Neg) {
353 assert(!Sext &&
354 "Float and integer src modifiers can't be set simultaneously");
355 Mods |= Abs ? SISrcMods::ABS : 0u;
356 Mods ^= Neg ? SISrcMods::NEG : 0u;
357 } else if (Sext) {
358 Mods |= SISrcMods::SEXT;
359 }
360
361 return Mods;
362}
363
364MachineInstr *SDWASrcOperand::potentialToConvert(const SIInstrInfo *TII,
365 const GCNSubtarget &ST,
366 SDWAOperandsMap *PotentialMatches) {
367 if (PotentialMatches != nullptr) {
368 // Fill out the map for all uses if all can be converted
369 MachineOperand *Reg = getReplacedOperand();
370 if (!Reg->isReg() || !Reg->isDef())
371 return nullptr;
372
373 for (MachineInstr &UseMI : getMRI()->use_nodbg_instructions(Reg->getReg()))
374 // Check that all instructions that use Reg can be converted
375 if (!isConvertibleToSDWA(UseMI, ST, TII) ||
376 !canCombineSelections(UseMI, TII))
377 return nullptr;
378
379 // Now that it's guaranteed all uses are legal, iterate over the uses again
380 // to add them for later conversion.
381 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(Reg->getReg())) {
382 // Should not get a subregister here
383 assert(isSameReg(UseMO, *Reg));
384
385 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
386 MachineInstr *UseMI = UseMO.getParent();
387 potentialMatchesMap[UseMI].push_back(this);
388 }
389 return nullptr;
390 }
391
392 // For SDWA src operand potential instruction is one that use register
393 // defined by parent instruction
394 MachineOperand *PotentialMO = findSingleRegUse(getReplacedOperand(), getMRI());
395 if (!PotentialMO)
396 return nullptr;
397
398 MachineInstr *Parent = PotentialMO->getParent();
399
400 return canCombineSelections(*Parent, TII) ? Parent : nullptr;
401}
402
403bool SDWASrcOperand::convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) {
404 assert((!Sext || !TII->getSubtarget().zeroesHigh16BitsOfDest(
405 getParentInst()->getOpcode())) &&
406 "Cannot use sign-extension with instruction that zeroes high bits");
407 switch (MI.getOpcode()) {
408 case AMDGPU::V_CVT_F32_FP8_sdwa:
409 case AMDGPU::V_CVT_F32_BF8_sdwa:
410 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
411 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
412 // Does not support input modifiers: noabs, noneg, nosext.
413 return false;
414 case AMDGPU::V_CNDMASK_B32_sdwa:
415 // SISrcMods uses the same bitmask for SEXT and NEG modifiers and
416 // hence the compiler can only support one type of modifier for
417 // each SDWA instruction. For V_CNDMASK_B32_sdwa, this is NEG
418 // since its operands get printed using
419 // AMDGPUInstPrinter::printOperandAndFPInputMods which produces
420 // the output intended for NEG if SEXT is set.
421 //
422 // The ISA does actually support both modifiers on most SDWA
423 // instructions.
424 //
425 // FIXME Accept SEXT here after fixing this issue.
426 if (Sext)
427 return false;
428 break;
429 }
430
431 // Find operand in instruction that matches source operand and replace it with
432 // target operand. Set corresponding src_sel
433 bool IsPreserveSrc = false;
434 MachineOperand *Src = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
435 MachineOperand *SrcSel = TII->getNamedOperand(MI, AMDGPU::OpName::src0_sel);
436 MachineOperand *SrcMods =
437 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
438 assert(Src && (Src->isReg() || Src->isImm()));
439 if (!isSameReg(*Src, *getReplacedOperand())) {
440 // If this is not src0 then it could be src1
441 Src = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
442 SrcSel = TII->getNamedOperand(MI, AMDGPU::OpName::src1_sel);
443 SrcMods = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
444
445 if (!Src ||
446 !isSameReg(*Src, *getReplacedOperand())) {
447 // It's possible this Src is a tied operand for
448 // UNUSED_PRESERVE, in which case we can either
449 // abandon the peephole attempt, or if legal we can
450 // copy the target operand into the tied slot
451 // if the preserve operation will effectively cause the same
452 // result by overwriting the rest of the dst.
453 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
454 MachineOperand *DstUnused =
455 TII->getNamedOperand(MI, AMDGPU::OpName::dst_unused);
456
457 if (Dst &&
458 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
459 // This will work if the tied src is accessing WORD_0, and the dst is
460 // writing WORD_1. Modifiers don't matter because all the bits that
461 // would be impacted are being overwritten by the dst.
462 // Any other case will not work.
463 SdwaSel DstSel = static_cast<SdwaSel>(
464 TII->getNamedImmOperand(MI, AMDGPU::OpName::dst_sel));
465 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
466 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
467 IsPreserveSrc = true;
468 auto DstIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
469 AMDGPU::OpName::vdst);
470 auto TiedIdx = MI.findTiedOperandIdx(DstIdx);
471 Src = &MI.getOperand(TiedIdx);
472 SrcSel = nullptr;
473 SrcMods = nullptr;
474 } else {
475 // Not legal to convert this src
476 return false;
477 }
478 }
479 }
480 assert(Src && Src->isReg());
481
482 if ((MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
483 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
484 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
485 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
486 !isSameReg(*Src, *getReplacedOperand())) {
487 // In case of v_mac_f16/32_sdwa this pass can try to apply src operand to
488 // src2. This is not allowed.
489 return false;
490 }
491
492 assert(isSameReg(*Src, *getReplacedOperand()) &&
493 (IsPreserveSrc || (SrcSel && SrcMods)));
494 }
495 copyRegOperand(*Src, *getTargetOperand());
496 if (!IsPreserveSrc) {
497 SdwaSel ExistingSel = static_cast<SdwaSel>(SrcSel->getImm());
498 SrcSel->setImm(*combineSdwaSel(ExistingSel, getSrcSel()));
499 SrcMods->setImm(getSrcMods(TII, Src));
500 }
501 getTargetOperand()->setIsKill(false);
502 return true;
503}
504
505/// Verify that the SDWA selection operand \p SrcSelOpName of the SDWA
506/// instruction \p MI can be combined with the selection \p OpSel.
507static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII,
508 AMDGPU::OpName SrcSelOpName, SdwaSel OpSel) {
509 assert(TII->isSDWA(MI.getOpcode()));
510
511 const MachineOperand *SrcSelOp = TII->getNamedOperand(MI, SrcSelOpName);
512 SdwaSel SrcSel = static_cast<SdwaSel>(SrcSelOp->getImm());
513
514 return combineSdwaSel(SrcSel, OpSel).has_value();
515}
516
517/// Verify that \p Op is the same register as the operand of the SDWA
518/// instruction \p MI named by \p SrcOpName and that the SDWA
519/// selection \p SrcSelOpName can be combined with the \p OpSel.
520static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII,
521 AMDGPU::OpName SrcOpName,
522 AMDGPU::OpName SrcSelOpName, MachineOperand *Op,
523 SdwaSel OpSel) {
524 assert(TII->isSDWA(MI.getOpcode()));
525
526 const MachineOperand *Src = TII->getNamedOperand(MI, SrcOpName);
527 if (!Src || !isSameReg(*Src, *Op))
528 return true;
529
530 return canCombineOpSel(MI, TII, SrcSelOpName, OpSel);
531}
532
533bool SDWASrcOperand::canCombineSelections(const MachineInstr &MI,
534 const SIInstrInfo *TII) {
535 if (!TII->isSDWA(MI.getOpcode()))
536 return true;
537
538 using namespace AMDGPU;
539
540 return canCombineOpSel(MI, TII, OpName::src0, OpName::src0_sel,
541 getReplacedOperand(), getSrcSel()) &&
542 canCombineOpSel(MI, TII, OpName::src1, OpName::src1_sel,
543 getReplacedOperand(), getSrcSel());
544}
545
546MachineInstr *SDWADstOperand::potentialToConvert(const SIInstrInfo *TII,
547 const GCNSubtarget &ST,
548 SDWAOperandsMap *PotentialMatches) {
549 // For SDWA dst operand potential instruction is one that defines register
550 // that this operand uses
551 MachineRegisterInfo *MRI = getMRI();
552 MachineInstr *ParentMI = getParentInst();
553
554 MachineOperand *PotentialMO = findSingleRegDef(getReplacedOperand(), MRI);
555 if (!PotentialMO)
556 return nullptr;
557
558 // Check that ParentMI is the only instruction that uses replaced register
559 for (MachineInstr &UseInst : MRI->use_nodbg_instructions(PotentialMO->getReg())) {
560 if (&UseInst != ParentMI)
561 return nullptr;
562 }
563
564 MachineInstr *Parent = PotentialMO->getParent();
565 return canCombineSelections(*Parent, TII) ? Parent : nullptr;
566}
567
568bool SDWADstOperand::convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) {
569 // Replace vdst operand in MI with target operand. Set dst_sel and dst_unused
570
571 if ((MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
572 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
573 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
574 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
575 getDstSel() != AMDGPU::SDWA::DWORD) {
576 // v_mac_f16/32_sdwa allow dst_sel to be equal only to DWORD
577 return false;
578 }
579
580 MachineOperand *Operand = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
581 assert(Operand &&
582 Operand->isReg() &&
583 isSameReg(*Operand, *getReplacedOperand()));
584 copyRegOperand(*Operand, *getTargetOperand());
585 MachineOperand *DstSel= TII->getNamedOperand(MI, AMDGPU::OpName::dst_sel);
586 assert(DstSel);
587
588 SdwaSel ExistingSel = static_cast<SdwaSel>(DstSel->getImm());
589 DstSel->setImm(combineSdwaSel(ExistingSel, getDstSel()).value());
590
591 MachineOperand *DstUnused= TII->getNamedOperand(MI, AMDGPU::OpName::dst_unused);
593 DstUnused->setImm(getDstUnused());
594
595 // Remove original instruction because it would conflict with our new
596 // instruction by register definition
597 getParentInst()->eraseFromParent();
598 return true;
599}
600
601bool SDWADstOperand::canCombineSelections(const MachineInstr &MI,
602 const SIInstrInfo *TII) {
603 if (!TII->isSDWA(MI.getOpcode()))
604 return true;
605
606 return canCombineOpSel(MI, TII, AMDGPU::OpName::dst_sel, getDstSel());
607}
608
609bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &MI,
610 const SIInstrInfo *TII) {
611 // MI should be moved right before v_or_b32.
612 // For this we should clear all kill flags on uses of MI src-operands or else
613 // we can encounter problem with use of killed operand.
614 for (MachineOperand &MO : MI.uses()) {
615 if (!MO.isReg())
616 continue;
617 getMRI()->clearKillFlags(MO.getReg());
618 }
619
620 // Move MI before v_or_b32
621 MI.getParent()->remove(&MI);
622 getParentInst()->getParent()->insert(getParentInst(), &MI);
623
624 // Add Implicit use of preserved register
625 MachineInstrBuilder MIB(*MI.getMF(), MI);
626 MIB.addReg(getPreservedOperand()->getReg(),
627 RegState::ImplicitKill,
628 getPreservedOperand()->getSubReg());
629
630 // Tie dst to implicit use
631 MI.tieOperands(AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vdst),
632 MI.getNumOperands() - 1);
633
634 // Convert MI as any other SDWADstOperand and remove v_or_b32
635 return SDWADstOperand::convertToSDWA(MI, TII);
636}
637
638bool SDWADstPreserveOperand::canCombineSelections(const MachineInstr &MI,
639 const SIInstrInfo *TII) {
640 return SDWADstOperand::canCombineSelections(MI, TII);
641}
642
643std::optional<int64_t>
644SIPeepholeSDWA::foldToImm(const MachineOperand &Op) const {
645 if (Op.isImm()) {
646 return Op.getImm();
647 }
648
649 // If this is not immediate then it can be copy of immediate value, e.g.:
650 // %1 = S_MOV_B32 255;
651 if (Op.isReg()) {
652 for (const MachineOperand &Def : MRI->def_operands(Op.getReg())) {
653 if (!isSameReg(Op, Def))
654 continue;
655
656 const MachineInstr *DefInst = Def.getParent();
657 if (!TII->isFoldableCopy(*DefInst))
658 return std::nullopt;
659
660 const MachineOperand &Copied = DefInst->getOperand(1);
661 if (!Copied.isImm())
662 return std::nullopt;
663
664 return Copied.getImm();
665 }
666 }
667
668 return std::nullopt;
669}
670
671std::unique_ptr<SDWAOperand>
672SIPeepholeSDWA::matchSDWAOperand(MachineInstr &MI) {
673 unsigned Opcode = MI.getOpcode();
674 switch (Opcode) {
675 case AMDGPU::V_LSHRREV_B32_e32:
676 case AMDGPU::V_ASHRREV_I32_e32:
677 case AMDGPU::V_LSHLREV_B32_e32:
678 case AMDGPU::V_LSHRREV_B32_e64:
679 case AMDGPU::V_ASHRREV_I32_e64:
680 case AMDGPU::V_LSHLREV_B32_e64: {
681 // from: v_lshrrev_b32_e32 v1, 16/24, v0
682 // to SDWA src:v0 src_sel:WORD_1/BYTE_3
683
684 // from: v_ashrrev_i32_e32 v1, 16/24, v0
685 // to SDWA src:v0 src_sel:WORD_1/BYTE_3 sext:1
686
687 // from: v_lshlrev_b32_e32 v1, 16/24, v0
688 // to SDWA dst:v1 dst_sel:WORD_1/BYTE_3 dst_unused:UNUSED_PAD
689 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
690 auto Imm = foldToImm(*Src0);
691 if (!Imm)
692 break;
693
694 if (*Imm != 16 && *Imm != 24)
695 break;
696
697 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
698 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
699 if (!Src1->isReg() || Src1->getReg().isPhysical() ||
700 Dst->getReg().isPhysical())
701 break;
702
703 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
704 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
705 return std::make_unique<SDWADstOperand>(
706 Dst, Src1, *Imm == 16 ? WORD_1 : BYTE_3, UNUSED_PAD);
707 }
708 return std::make_unique<SDWASrcOperand>(
709 Src1, Dst, *Imm == 16 ? WORD_1 : BYTE_3, false, false,
710 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
711 Opcode != AMDGPU::V_LSHRREV_B32_e64);
712 break;
713 }
714
715 case AMDGPU::V_LSHRREV_B16_e32:
716 case AMDGPU::V_LSHLREV_B16_e32:
717 case AMDGPU::V_LSHRREV_B16_e64:
718 case AMDGPU::V_LSHRREV_B16_opsel_e64:
719 case AMDGPU::V_LSHLREV_B16_opsel_e64:
720 case AMDGPU::V_LSHLREV_B16_e64: {
721 // V_ASHRREV_I16_e32 and V_ASHRREV_I16_e64 are
722 // not included here because they zero-fill the high 16-bits.
723
724 // from: v_lshrrev_b16_e32 v1, 8, v0
725 // to SDWA src:v0 src_sel:BYTE_1
726
727 // from: v_lshlrev_b16_e32 v1, 8, v0
728 // to SDWA dst:v1 dst_sel:BYTE_1 dst_unused:UNUSED_PAD
729 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
730 auto Imm = foldToImm(*Src0);
731 if (!Imm || *Imm != 8)
732 break;
733
734 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
735 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
736
737 if (!Src1->isReg() || Src1->getReg().isPhysical() ||
738 Dst->getReg().isPhysical())
739 break;
740
741 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
742 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
743 Opcode == AMDGPU::V_LSHLREV_B16_e64)
744 return std::make_unique<SDWADstOperand>(Dst, Src1, BYTE_1, UNUSED_PAD);
745 return std::make_unique<SDWASrcOperand>(Src1, Dst, BYTE_1, false, false,
746 false);
747 break;
748 }
749
750 case AMDGPU::V_BFE_I32_e64:
751 case AMDGPU::V_BFE_U32_e64: {
752 // e.g.:
753 // from: v_bfe_u32 v1, v0, 8, 8
754 // to SDWA src:v0 src_sel:BYTE_1
755
756 // offset | width | src_sel
757 // ------------------------
758 // 0 | 8 | BYTE_0
759 // 0 | 16 | WORD_0
760 // 0 | 32 | DWORD ?
761 // 8 | 8 | BYTE_1
762 // 16 | 8 | BYTE_2
763 // 16 | 16 | WORD_1
764 // 24 | 8 | BYTE_3
765
766 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
767 auto Offset = foldToImm(*Src1);
768 if (!Offset)
769 break;
770
771 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
772 auto Width = foldToImm(*Src2);
773 if (!Width)
774 break;
775
776 SdwaSel SrcSel = DWORD;
777
778 if (*Offset == 0 && *Width == 8)
779 SrcSel = BYTE_0;
780 else if (*Offset == 0 && *Width == 16)
781 SrcSel = WORD_0;
782 else if (*Offset == 0 && *Width == 32)
783 SrcSel = DWORD;
784 else if (*Offset == 8 && *Width == 8)
785 SrcSel = BYTE_1;
786 else if (*Offset == 16 && *Width == 8)
787 SrcSel = BYTE_2;
788 else if (*Offset == 16 && *Width == 16)
789 SrcSel = WORD_1;
790 else if (*Offset == 24 && *Width == 8)
791 SrcSel = BYTE_3;
792 else
793 break;
794
795 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
796 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
797
798 if (!Src0->isReg() || Src0->getReg().isPhysical() ||
799 Dst->getReg().isPhysical())
800 break;
801
802 return std::make_unique<SDWASrcOperand>(
803 Src0, Dst, SrcSel, false, false, Opcode != AMDGPU::V_BFE_U32_e64);
804 }
805
806 case AMDGPU::V_AND_B32_e32:
807 case AMDGPU::V_AND_B32_e64: {
808 // e.g.:
809 // from: v_and_b32_e32 v1, 0x0000ffff/0x000000ff, v0
810 // to SDWA src:v0 src_sel:WORD_0/BYTE_0
811
812 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
813 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
814 auto *ValSrc = Src1;
815 auto Imm = foldToImm(*Src0);
816
817 if (!Imm) {
818 Imm = foldToImm(*Src1);
819 ValSrc = Src0;
820 }
821
822 if (!Imm || (*Imm != 0x0000ffff && *Imm != 0x000000ff))
823 break;
824
825 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
826
827 if (!ValSrc->isReg() || ValSrc->getReg().isPhysical() ||
828 Dst->getReg().isPhysical())
829 break;
830
831 return std::make_unique<SDWASrcOperand>(
832 ValSrc, Dst, *Imm == 0x0000ffff ? WORD_0 : BYTE_0);
833 }
834
835 case AMDGPU::V_OR_B32_e32:
836 case AMDGPU::V_OR_B32_e64: {
837 // Patterns for dst_unused:UNUSED_PRESERVE.
838 // e.g., from:
839 // v_add_f16_sdwa v0, v1, v2 dst_sel:WORD_1 dst_unused:UNUSED_PAD
840 // src1_sel:WORD_1 src2_sel:WORD1
841 // v_add_f16_e32 v3, v1, v2
842 // v_or_b32_e32 v4, v0, v3
843 // to SDWA preserve dst:v4 dst_sel:WORD_1 dst_unused:UNUSED_PRESERVE preserve:v3
844
845 // Check if one of operands of v_or_b32 is SDWA instruction
846 using CheckRetType =
847 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
848 auto CheckOROperandsForSDWA =
849 [&](const MachineOperand *Op1, const MachineOperand *Op2) -> CheckRetType {
850 if (!Op1 || !Op1->isReg() || !Op2 || !Op2->isReg())
851 return CheckRetType(std::nullopt);
852
853 MachineOperand *Op1Def = findSingleRegDef(Op1, MRI);
854 if (!Op1Def)
855 return CheckRetType(std::nullopt);
856
857 MachineInstr *Op1Inst = Op1Def->getParent();
858 if (!TII->isSDWA(*Op1Inst))
859 return CheckRetType(std::nullopt);
860
861 MachineOperand *Op2Def = findSingleRegDef(Op2, MRI);
862 if (!Op2Def)
863 return CheckRetType(std::nullopt);
864
865 return CheckRetType(std::pair(Op1Def, Op2Def));
866 };
867
868 MachineOperand *OrSDWA = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
869 MachineOperand *OrOther = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
870 assert(OrSDWA && OrOther);
871 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
872 if (!Res) {
873 OrSDWA = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
874 OrOther = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
875 assert(OrSDWA && OrOther);
876 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
877 if (!Res)
878 break;
879 }
880
881 MachineOperand *OrSDWADef = Res->first;
882 MachineOperand *OrOtherDef = Res->second;
883 assert(OrSDWADef && OrOtherDef);
884
885 MachineInstr *SDWAInst = OrSDWADef->getParent();
886 MachineInstr *OtherInst = OrOtherDef->getParent();
887
888 // Check that OtherInstr is actually bitwise compatible with SDWAInst = their
889 // destination patterns don't overlap. Compatible instruction can be either
890 // regular instruction with compatible bitness or SDWA instruction with
891 // correct dst_sel
892 // SDWAInst | OtherInst bitness / OtherInst dst_sel
893 // -----------------------------------------------------
894 // DWORD | no / no
895 // WORD_0 | no / BYTE_2/3, WORD_1
896 // WORD_1 | 8/16-bit instructions / BYTE_0/1, WORD_0
897 // BYTE_0 | no / BYTE_1/2/3, WORD_1
898 // BYTE_1 | 8-bit / BYTE_0/2/3, WORD_1
899 // BYTE_2 | 8/16-bit / BYTE_0/1/3. WORD_0
900 // BYTE_3 | 8/16/24-bit / BYTE_0/1/2, WORD_0
901 // E.g. if SDWAInst is v_add_f16_sdwa dst_sel:WORD_1 then v_add_f16 is OK
902 // but v_add_f32 is not.
903
904 // TODO: add support for non-SDWA instructions as OtherInst.
905 // For now this only works with SDWA instructions. For regular instructions
906 // there is no way to determine if the instruction writes only 8/16/24-bit
907 // out of full register size and all registers are at min 32-bit wide.
908 if (!TII->isSDWA(*OtherInst))
909 break;
910
911 SdwaSel DstSel = static_cast<SdwaSel>(
912 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
913 SdwaSel OtherDstSel = static_cast<SdwaSel>(
914 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
915
916 bool DstSelAgree = false;
917 switch (DstSel) {
918 case WORD_0: DstSelAgree = ((OtherDstSel == BYTE_2) ||
919 (OtherDstSel == BYTE_3) ||
920 (OtherDstSel == WORD_1));
921 break;
922 case WORD_1: DstSelAgree = ((OtherDstSel == BYTE_0) ||
923 (OtherDstSel == BYTE_1) ||
924 (OtherDstSel == WORD_0));
925 break;
926 case BYTE_0: DstSelAgree = ((OtherDstSel == BYTE_1) ||
927 (OtherDstSel == BYTE_2) ||
928 (OtherDstSel == BYTE_3) ||
929 (OtherDstSel == WORD_1));
930 break;
931 case BYTE_1: DstSelAgree = ((OtherDstSel == BYTE_0) ||
932 (OtherDstSel == BYTE_2) ||
933 (OtherDstSel == BYTE_3) ||
934 (OtherDstSel == WORD_1));
935 break;
936 case BYTE_2: DstSelAgree = ((OtherDstSel == BYTE_0) ||
937 (OtherDstSel == BYTE_1) ||
938 (OtherDstSel == BYTE_3) ||
939 (OtherDstSel == WORD_0));
940 break;
941 case BYTE_3: DstSelAgree = ((OtherDstSel == BYTE_0) ||
942 (OtherDstSel == BYTE_1) ||
943 (OtherDstSel == BYTE_2) ||
944 (OtherDstSel == WORD_0));
945 break;
946 default: DstSelAgree = false;
947 }
948
949 if (!DstSelAgree)
950 break;
951
952 // Also OtherInst dst_unused should be UNUSED_PAD
953 DstUnused OtherDstUnused = static_cast<DstUnused>(
954 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
955 if (OtherDstUnused != DstUnused::UNUSED_PAD)
956 break;
957
958 // Create DstPreserveOperand
959 MachineOperand *OrDst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
960 assert(OrDst && OrDst->isReg());
961
962 return std::make_unique<SDWADstPreserveOperand>(
963 OrDst, OrSDWADef, OrOtherDef, DstSel);
964
965 }
966 }
967
968 return std::unique_ptr<SDWAOperand>(nullptr);
969}
970
971#if !defined(NDEBUG)
972static raw_ostream& operator<<(raw_ostream &OS, const SDWAOperand &Operand) {
973 Operand.print(OS);
974 return OS;
975}
976#endif
977
978void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &MBB) {
979 for (MachineInstr &MI : MBB) {
980 if (auto Operand = matchSDWAOperand(MI)) {
981 LLVM_DEBUG(dbgs() << "Match: " << MI << "To: " << *Operand << '\n');
982 SDWAOperands[&MI] = std::move(Operand);
983 ++NumSDWAPatternsFound;
984 }
985 }
986}
987
988// Convert the V_ADD_CO_U32_e64 into V_ADD_CO_U32_e32. This allows
989// isConvertibleToSDWA to perform its transformation on V_ADD_CO_U32_e32 into
990// V_ADD_CO_U32_sdwa.
991//
992// We are transforming from a VOP3 into a VOP2 form of the instruction.
993// %19:vgpr_32 = V_AND_B32_e32 255,
994// killed %16:vgpr_32, implicit $exec
995// %47:vgpr_32, %49:sreg_64_xexec = V_ADD_CO_U32_e64
996// %26.sub0:vreg_64, %19:vgpr_32, implicit $exec
997// %48:vgpr_32, dead %50:sreg_64_xexec = V_ADDC_U32_e64
998// %26.sub1:vreg_64, %54:vgpr_32, killed %49:sreg_64_xexec, implicit $exec
999//
1000// becomes
1001// %47:vgpr_32 = V_ADD_CO_U32_sdwa
1002// 0, %26.sub0:vreg_64, 0, killed %16:vgpr_32, 0, 6, 0, 6, 0,
1003// implicit-def $vcc, implicit $exec
1004// %48:vgpr_32, dead %50:sreg_64_xexec = V_ADDC_U32_e64
1005// %26.sub1:vreg_64, %54:vgpr_32, killed $vcc, implicit $exec
1006void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &MI,
1007 const GCNSubtarget &ST) const {
1008 int Opc = MI.getOpcode();
1009 assert((Opc == AMDGPU::V_ADD_CO_U32_e64 || Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1010 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1011
1012 // Can the candidate MI be shrunk?
1013 if (!TII->canShrink(MI, *MRI))
1014 return;
1016 // Find the related ADD instruction.
1017 const MachineOperand *Sdst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst);
1018 if (!Sdst)
1019 return;
1020 MachineOperand *NextOp = findSingleRegUse(Sdst, MRI);
1021 if (!NextOp)
1022 return;
1023 MachineInstr &MISucc = *NextOp->getParent();
1024
1025 // Make sure the carry in/out are subsequently unused.
1026 MachineOperand *CarryIn = TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1027 if (!CarryIn)
1028 return;
1029 MachineOperand *CarryOut = TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1030 if (!CarryOut)
1031 return;
1032 if (!MRI->hasOneNonDBGUse(CarryIn->getReg()) ||
1033 !MRI->use_nodbg_empty(CarryOut->getReg()))
1034 return;
1035 // Make sure VCC or its subregs are dead before MI.
1036 MachineBasicBlock &MBB = *MI.getParent();
1038 MBB.computeRegisterLiveness(TRI, AMDGPU::VCC, MI, 25);
1039 if (Liveness != MachineBasicBlock::LQR_Dead)
1040 return;
1041 // Check if VCC is referenced in range of (MI,MISucc].
1042 for (auto I = std::next(MI.getIterator()), E = MISucc.getIterator();
1043 I != E; ++I) {
1044 if (I->modifiesRegister(AMDGPU::VCC, TRI))
1045 return;
1046 }
1047
1048 // Replace MI with V_{SUB|ADD}_I32_e32
1049 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(Opc))
1050 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::vdst))
1051 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src0))
1052 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src1))
1053 .setMIFlags(MI.getFlags());
1054
1055 MI.eraseFromParent();
1056
1057 // Since the carry output of MI is now VCC, update its use in MISucc.
1058
1059 MISucc.substituteRegister(CarryIn->getReg(), TRI->getVCC(), 0, *TRI);
1060}
1061
1062/// Try to convert an \p MI in VOP3 which takes an src2 carry-in
1063/// operand into the corresponding VOP2 form which expects the
1064/// argument in VCC. To this end, add an copy from the carry-in to
1065/// VCC. The conversion will only be applied if \p MI can be shrunk
1066/// to VOP2 and if VCC can be proven to be dead before \p MI.
1067void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &MI,
1068 const GCNSubtarget &ST) const {
1069 assert(MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1070
1071 LLVM_DEBUG(dbgs() << "Attempting VOP2 conversion: " << MI);
1072 if (!TII->canShrink(MI, *MRI)) {
1073 LLVM_DEBUG(dbgs() << "Cannot shrink instruction\n");
1074 return;
1075 }
1076
1077 const MachineOperand &CarryIn =
1078 *TII->getNamedOperand(MI, AMDGPU::OpName::src2);
1079 Register CarryReg = CarryIn.getReg();
1080 MachineInstr *CarryDef = MRI->getVRegDef(CarryReg);
1081 if (!CarryDef) {
1082 LLVM_DEBUG(dbgs() << "Missing carry-in operand definition\n");
1083 return;
1084 }
1085
1086 // Make sure VCC or its subregs are dead before MI.
1087 MCRegister Vcc = TRI->getVCC();
1088 MachineBasicBlock &MBB = *MI.getParent();
1091 if (Liveness != MachineBasicBlock::LQR_Dead) {
1092 LLVM_DEBUG(dbgs() << "VCC not known to be dead before instruction\n");
1093 return;
1094 }
1095
1096 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY), Vcc).add(CarryIn);
1097
1098 auto Converted = BuildMI(MBB, MI, MI.getDebugLoc(),
1099 TII->get(AMDGPU::getVOPe32(MI.getOpcode())))
1100 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::vdst))
1101 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src0))
1102 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src1))
1103 .setMIFlags(MI.getFlags());
1104 TII->fixImplicitOperands(*Converted);
1105 LLVM_DEBUG(dbgs() << "Converted to VOP2: " << *Converted);
1106 (void)Converted;
1107 MI.eraseFromParent();
1108}
1109
1110namespace {
1111bool isConvertibleToSDWA(MachineInstr &MI,
1112 const GCNSubtarget &ST,
1113 const SIInstrInfo* TII) {
1114 // Check if this is already an SDWA instruction
1115 unsigned Opc = MI.getOpcode();
1116 if (TII->isSDWA(Opc))
1117 return true;
1118
1119 // Can only be handled after ealier conversion to
1120 // AMDGPU::V_CNDMASK_B32_e32 which is not always possible.
1121 if (Opc == AMDGPU::V_CNDMASK_B32_e64)
1122 return false;
1123
1124 // Check if this instruction has opcode that supports SDWA
1125 if (AMDGPU::getSDWAOp(Opc) == -1)
1127
1128 if (AMDGPU::getSDWAOp(Opc) == -1)
1129 return false;
1130
1131 if (!ST.hasSDWAOmod() && TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
1132 return false;
1133
1134 if (TII->isVOPC(Opc)) {
1135 if (!ST.hasSDWASdst()) {
1136 const MachineOperand *SDst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst);
1137 if (SDst && (SDst->getReg() != AMDGPU::VCC &&
1138 SDst->getReg() != AMDGPU::VCC_LO))
1139 return false;
1140 }
1141
1142 if (!ST.hasSDWAOutModsVOPC() &&
1143 (TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) ||
1144 TII->hasModifiersSet(MI, AMDGPU::OpName::omod)))
1145 return false;
1146
1147 } else if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst) ||
1148 !TII->getNamedOperand(MI, AMDGPU::OpName::vdst)) {
1149 return false;
1150 }
1151
1152 if (!ST.hasSDWAMac() && (Opc == AMDGPU::V_FMAC_F16_e32 ||
1153 Opc == AMDGPU::V_FMAC_F32_e32 ||
1154 Opc == AMDGPU::V_MAC_F16_e32 ||
1155 Opc == AMDGPU::V_MAC_F32_e32))
1156 return false;
1157
1158 // Check if target supports this SDWA opcode
1159 if (TII->pseudoToMCOpcode(Opc) == -1)
1160 return false;
1161
1162 if (MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0)) {
1163 if (!Src0->isReg() && !Src0->isImm())
1164 return false;
1165 }
1166
1167 if (MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1)) {
1168 if (!Src1->isReg() && !Src1->isImm())
1169 return false;
1170 }
1171
1172 return true;
1173}
1174} // namespace
1175
1176MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &MI) {
1177 unsigned Opcode = MI.getOpcode();
1178 assert(!TII->isSDWA(Opcode));
1179
1180 int SDWAOpcode = AMDGPU::getSDWAOp(Opcode);
1181 if (SDWAOpcode == -1)
1182 SDWAOpcode = AMDGPU::getSDWAOp(AMDGPU::getVOPe32(Opcode));
1183 assert(SDWAOpcode != -1);
1184
1185 const MCInstrDesc &SDWADesc = TII->get(SDWAOpcode);
1186
1187 // Create SDWA version of instruction MI and initialize its operands
1188 MachineInstrBuilder SDWAInst =
1189 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), SDWADesc)
1190 .setMIFlags(MI.getFlags());
1191
1192 // Copy dst, if it is present in original then should also be present in SDWA
1193 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1194 if (Dst) {
1195 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::vdst));
1196 SDWAInst.add(*Dst);
1197 } else if ((Dst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst))) {
1198 assert(Dst && AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::sdst));
1199 SDWAInst.add(*Dst);
1200 } else {
1201 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::sdst));
1202 SDWAInst.addReg(TRI->getVCC(), RegState::Define);
1203 }
1204
1205 // Copy src0, initialize src0_modifiers. All sdwa instructions has src0 and
1206 // src0_modifiers (except for v_nop_sdwa, but it can't get here)
1207 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1208 assert(Src0 && AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0) &&
1209 AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0_modifiers));
1210 if (auto *Mod = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers))
1211 SDWAInst.addImm(Mod->getImm());
1212 else
1213 SDWAInst.addImm(0);
1214 SDWAInst.add(*Src0);
1215
1216 // Copy src1 if present, initialize src1_modifiers.
1217 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1218 if (Src1) {
1219 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1) &&
1220 AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1_modifiers));
1221 if (auto *Mod = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers))
1222 SDWAInst.addImm(Mod->getImm());
1223 else
1224 SDWAInst.addImm(0);
1225 SDWAInst.add(*Src1);
1226 }
1227
1228 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1229 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1230 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1231 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1232 // v_mac_f16/32 has additional src2 operand tied to vdst
1233 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
1234 assert(Src2);
1235 SDWAInst.add(*Src2);
1236 }
1237
1238 // Copy clamp if present, initialize otherwise
1239 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::clamp));
1240 MachineOperand *Clamp = TII->getNamedOperand(MI, AMDGPU::OpName::clamp);
1241 if (Clamp) {
1242 SDWAInst.add(*Clamp);
1243 } else {
1244 SDWAInst.addImm(0);
1245 }
1246
1247 // Copy omod if present, initialize otherwise if needed
1248 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::omod)) {
1249 MachineOperand *OMod = TII->getNamedOperand(MI, AMDGPU::OpName::omod);
1250 if (OMod) {
1251 SDWAInst.add(*OMod);
1252 } else {
1253 SDWAInst.addImm(0);
1254 }
1255 }
1256
1257 // Initialize SDWA specific operands
1258 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::dst_sel))
1259 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1260
1261 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::dst_unused))
1262 SDWAInst.addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1263
1264 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0_sel));
1265 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1266
1267 if (Src1) {
1268 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1_sel));
1269 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1270 }
1271
1272 // Check for a preserved register that needs to be copied.
1273 MachineInstr *Ret = SDWAInst.getInstr();
1274 TII->fixImplicitOperands(*Ret);
1275 return Ret;
1276}
1277
1278bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI,
1279 const SDWAOperandsVector &SDWAOperands) {
1280 LLVM_DEBUG(dbgs() << "Convert instruction:" << MI);
1281
1282 MachineInstr *SDWAInst;
1283 if (TII->isSDWA(MI.getOpcode())) {
1284 // Clone the instruction to allow revoking changes
1285 // made to MI during the processing of the operands
1286 // if the conversion fails.
1287 SDWAInst = MI.getMF()->CloneMachineInstr(&MI);
1288 MI.getParent()->insert(MI.getIterator(), SDWAInst);
1289 } else {
1290 SDWAInst = createSDWAVersion(MI);
1291 }
1292
1293 // Apply all sdwa operand patterns.
1294 bool Converted = false;
1295 for (auto &Operand : SDWAOperands) {
1296 LLVM_DEBUG(dbgs() << *SDWAInst << "\nOperand: " << *Operand);
1297 // There should be no intersection between SDWA operands and potential MIs
1298 // e.g.:
1299 // v_and_b32 v0, 0xff, v1 -> src:v1 sel:BYTE_0
1300 // v_and_b32 v2, 0xff, v0 -> src:v0 sel:BYTE_0
1301 // v_add_u32 v3, v4, v2
1302 //
1303 // In that example it is possible that we would fold 2nd instruction into
1304 // 3rd (v_add_u32_sdwa) and then try to fold 1st instruction into 2nd (that
1305 // was already destroyed). So if SDWAOperand is also a potential MI then do
1306 // not apply it.
1307 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1308 Converted |= Operand->convertToSDWA(*SDWAInst, TII);
1309 }
1310
1311 if (!Converted) {
1312 SDWAInst->eraseFromParent();
1313 return false;
1314 }
1315
1316 ConvertedInstructions.push_back(SDWAInst);
1317 for (MachineOperand &MO : SDWAInst->uses()) {
1318 if (!MO.isReg())
1319 continue;
1320
1321 MRI->clearKillFlags(MO.getReg());
1322 }
1323 LLVM_DEBUG(dbgs() << "\nInto:" << *SDWAInst << '\n');
1324 ++NumSDWAInstructionsPeepholed;
1325
1326 MI.eraseFromParent();
1327 return true;
1328}
1329
1330// If an instruction was converted to SDWA it should not have immediates or SGPR
1331// operands (allowed one SGPR on GFX9). Copy its scalar operands into VGPRs.
1332void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI,
1333 const GCNSubtarget &ST) const {
1334 const MCInstrDesc &Desc = TII->get(MI.getOpcode());
1335 unsigned ConstantBusCount = 0;
1336 for (MachineOperand &Op : MI.explicit_uses()) {
1337 if (Op.isReg()) {
1338 if (TRI->isVGPR(*MRI, Op.getReg()))
1339 continue;
1340
1341 if (ST.hasSDWAScalar() && ConstantBusCount == 0) {
1342 ++ConstantBusCount;
1343 continue;
1344 }
1345 } else if (!Op.isImm())
1346 continue;
1347
1348 unsigned I = Op.getOperandNo();
1349 const TargetRegisterClass *OpRC = TII->getRegClass(Desc, I);
1350 if (!OpRC || !TRI->isVSSuperClass(OpRC))
1351 continue;
1352
1353 Register VGPR = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
1354 auto Copy = BuildMI(*MI.getParent(), MI.getIterator(), MI.getDebugLoc(),
1355 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1356 if (Op.isImm())
1357 Copy.addImm(Op.getImm());
1358 else if (Op.isReg())
1359 Copy.addReg(Op.getReg(), getKillRegState(Op.isKill()), Op.getSubReg());
1360 Op.ChangeToRegister(VGPR, false);
1361 }
1362}
1363
1364bool SIPeepholeSDWALegacy::runOnMachineFunction(MachineFunction &MF) {
1365 if (skipFunction(MF.getFunction()))
1366 return false;
1367
1368 return SIPeepholeSDWA().run(MF);
1369}
1370
1371bool SIPeepholeSDWA::run(MachineFunction &MF) {
1372 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1373
1374 if (!ST.hasSDWA())
1375 return false;
1376
1377 MRI = &MF.getRegInfo();
1378 TRI = ST.getRegisterInfo();
1379 TII = ST.getInstrInfo();
1380
1381 // Find all SDWA operands in MF.
1382 bool Ret = false;
1383 for (MachineBasicBlock &MBB : MF) {
1384 bool Changed = false;
1385 do {
1386 // Preprocess the ADD/SUB pairs so they could be SDWA'ed.
1387 // Look for a possible ADD or SUB that resulted from a previously lowered
1388 // V_{ADD|SUB}_U64_PSEUDO. The function pseudoOpConvertToVOP2
1389 // lowers the pair of instructions into e32 form.
1390 matchSDWAOperands(MBB);
1391 for (const auto &OperandPair : SDWAOperands) {
1392 const auto &Operand = OperandPair.second;
1393 MachineInstr *PotentialMI = Operand->potentialToConvert(TII, ST);
1394 if (!PotentialMI)
1395 continue;
1396
1397 switch (PotentialMI->getOpcode()) {
1398 case AMDGPU::V_ADD_CO_U32_e64:
1399 case AMDGPU::V_SUB_CO_U32_e64:
1400 pseudoOpConvertToVOP2(*PotentialMI, ST);
1401 break;
1402 case AMDGPU::V_CNDMASK_B32_e64:
1403 convertVcndmaskToVOP2(*PotentialMI, ST);
1404 break;
1405 };
1406 }
1407 SDWAOperands.clear();
1408
1409 // Generate potential match list.
1410 matchSDWAOperands(MBB);
1411
1412 for (const auto &OperandPair : SDWAOperands) {
1413 const auto &Operand = OperandPair.second;
1414 MachineInstr *PotentialMI =
1415 Operand->potentialToConvert(TII, ST, &PotentialMatches);
1416
1417 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST, TII))
1418 PotentialMatches[PotentialMI].push_back(Operand.get());
1419 }
1420
1421 for (auto &PotentialPair : PotentialMatches) {
1422 MachineInstr &PotentialMI = *PotentialPair.first;
1423 convertToSDWA(PotentialMI, PotentialPair.second);
1424 }
1425
1426 PotentialMatches.clear();
1427 SDWAOperands.clear();
1428
1429 Changed = !ConvertedInstructions.empty();
1430
1431 if (Changed)
1432 Ret = true;
1433 while (!ConvertedInstructions.empty())
1434 legalizeScalarOperands(*ConvertedInstructions.pop_back_val(), ST);
1435 } while (Changed);
1436 }
1437
1438 return Ret;
1439}
1440
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Provides AMDGPU specific target descriptions.
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:672
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
This file implements a map that provides insertion order iteration.
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static MachineOperand * findSingleRegDef(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static void copyRegOperand(MachineOperand &To, const MachineOperand &From)
static MachineOperand * findSingleRegUse(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static std::optional< SdwaSel > combineSdwaSel(SdwaSel Sel, SdwaSel OperandSel)
Combine an SDWA instruction's existing SDWA selection Sel with the SDWA selection OperandSel of its o...
static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS)
static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII, AMDGPU::OpName SrcSelOpName, SdwaSel OpSel)
Verify that the SDWA selection operand SrcSelOpName of the SDWA instruction MI can be combined with t...
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
Value * RHS
Value * LHS
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool hasOptNone() const
Do not optimize this function (-O0).
Definition Function.h:682
LLVM_ABI LivenessQueryResult computeRegisterLiveness(const TargetRegisterInfo *TRI, MCRegister Reg, const_iterator Before, unsigned Neighborhood=10) const
Return whether (physical) register Reg has been defined and not killed as of just before Before.
LivenessQueryResult
Possible outcome of a register liveness query to computeRegisterLiveness()
@ LQR_Dead
Register is known to be fully dead.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void substituteRegister(Register FromReg, Register ToReg, unsigned SubIdx, const TargetRegisterInfo &RegInfo)
Replace all occurrences of FromReg with ToReg:SubIdx, properly composing subreg indices where necessa...
mop_range uses()
Returns all operands which may be register uses.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
void setImm(int64_t immVal)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI MachineOperand * getOneNonDBGUse(Register RegNo) const
If the register has a single non-Debug use, returns it; otherwise returns nullptr.
MachineOperand * getOneDef(Register Reg) const
Returns the defining operand if there is exactly one operand defining the specified register,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
iterator_range< def_iterator > def_operands(Register Reg) const
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
self_iterator getIterator()
Definition ilist_node.h:123
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Changed
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
LLVM_READONLY int32_t getSDWAOp(uint32_t Opcode)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition DWP.cpp:578
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Op::Description Desc
FunctionPass * createSIPeepholeSDWALegacyPass()
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
char & SIPeepholeSDWALegacyID
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58