LLVM 23.0.0git
SIFoldOperands.cpp
Go to the documentation of this file.
1//===-- SIFoldOperands.cpp - Fold operands --- ----------------------------===//
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/// \file
8//===----------------------------------------------------------------------===//
9//
10
11#include "SIFoldOperands.h"
12#include "AMDGPU.h"
13#include "GCNSubtarget.h"
15#include "SIInstrInfo.h"
17#include "SIRegisterInfo.h"
22
23#define DEBUG_TYPE "si-fold-operands"
24using namespace llvm;
25
26namespace {
27
28/// Track a value we may want to fold into downstream users, applying
29/// subregister extracts along the way.
30struct FoldableDef {
31 union {
32 MachineOperand *OpToFold = nullptr;
33 uint64_t ImmToFold;
34 int FrameIndexToFold;
35 };
36
37 /// Register class of the originally defined value.
38 const TargetRegisterClass *DefRC = nullptr;
39
40 /// Track the original defining instruction for the value.
41 const MachineInstr *DefMI = nullptr;
42
43 /// Subregister to apply to the value at the use point.
44 unsigned DefSubReg = AMDGPU::NoSubRegister;
45
46 /// Kind of value stored in the union.
48
49 FoldableDef() = delete;
50 FoldableDef(MachineOperand &FoldOp, const TargetRegisterClass *DefRC,
51 unsigned DefSubReg = AMDGPU::NoSubRegister)
52 : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.getType()) {
53
54 if (FoldOp.isImm()) {
55 ImmToFold = FoldOp.getImm();
56 } else if (FoldOp.isFI()) {
57 FrameIndexToFold = FoldOp.getIndex();
58 } else {
59 assert(FoldOp.isReg() || FoldOp.isGlobal());
60 OpToFold = &FoldOp;
61 }
62
63 DefMI = FoldOp.getParent();
64 }
65
66 FoldableDef(int64_t FoldImm, const TargetRegisterClass *DefRC,
67 unsigned DefSubReg = AMDGPU::NoSubRegister)
68 : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg),
70
71 /// Copy the current def and apply \p SubReg to the value.
72 FoldableDef getWithSubReg(const SIRegisterInfo &TRI, unsigned SubReg) const {
73 FoldableDef Copy(*this);
74 Copy.DefSubReg = TRI.composeSubRegIndices(DefSubReg, SubReg);
75 return Copy;
76 }
77
78 bool isReg() const { return Kind == MachineOperand::MO_Register; }
79
80 Register getReg() const {
81 assert(isReg());
82 return OpToFold->getReg();
83 }
84
85 unsigned getSubReg() const {
86 assert(isReg());
87 return OpToFold->getSubReg();
88 }
89
90 bool isImm() const { return Kind == MachineOperand::MO_Immediate; }
91
92 bool isFI() const {
93 return Kind == MachineOperand::MO_FrameIndex;
94 }
95
96 int getFI() const {
97 assert(isFI());
98 return FrameIndexToFold;
99 }
100
101 bool isGlobal() const { return Kind == MachineOperand::MO_GlobalAddress; }
102
103 /// Return the effective immediate value defined by this instruction, after
104 /// application of any subregister extracts which may exist between the use
105 /// and def instruction.
106 std::optional<int64_t> getEffectiveImmVal() const {
107 assert(isImm());
108 return SIInstrInfo::extractSubregFromImm(ImmToFold, DefSubReg);
109 }
110
111 /// Check if it is legal to fold this effective value into \p MI's \p OpNo
112 /// operand.
113 bool isOperandLegal(const SIInstrInfo &TII, const MachineInstr &MI,
114 unsigned OpIdx) const {
115 switch (Kind) {
117 std::optional<int64_t> ImmToFold = getEffectiveImmVal();
118 if (!ImmToFold)
119 return false;
120
121 // TODO: Should verify the subregister index is supported by the class
122 // TODO: Avoid the temporary MachineOperand
123 MachineOperand TmpOp = MachineOperand::CreateImm(*ImmToFold);
124 return TII.isOperandLegal(MI, OpIdx, &TmpOp);
125 }
127 if (DefSubReg != AMDGPU::NoSubRegister)
128 return false;
129 MachineOperand TmpOp = MachineOperand::CreateFI(FrameIndexToFold);
130 return TII.isOperandLegal(MI, OpIdx, &TmpOp);
131 }
132 default:
133 // TODO: Try to apply DefSubReg, for global address we can extract
134 // low/high.
135 if (DefSubReg != AMDGPU::NoSubRegister)
136 return false;
137 return TII.isOperandLegal(MI, OpIdx, OpToFold);
138 }
139
140 llvm_unreachable("covered MachineOperand kind switch");
141 }
142};
143
144struct FoldCandidate {
146 FoldableDef Def;
147 int ShrinkOpcode;
148 unsigned UseOpNo;
149 bool Commuted;
150
151 FoldCandidate(MachineInstr *MI, unsigned OpNo, FoldableDef Def,
152 bool Commuted = false, int ShrinkOp = -1)
153 : UseMI(MI), Def(Def), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo),
154 Commuted(Commuted) {}
155
156 bool isFI() const { return Def.isFI(); }
157
158 int getFI() const {
159 assert(isFI());
160 return Def.FrameIndexToFold;
161 }
162
163 bool isImm() const { return Def.isImm(); }
164
165 bool isReg() const { return Def.isReg(); }
166
167 Register getReg() const { return Def.getReg(); }
168
169 bool isGlobal() const { return Def.isGlobal(); }
170
171 bool needsShrink() const { return ShrinkOpcode != -1; }
172};
173
174class SIFoldOperandsImpl {
175public:
176 MachineFunction *MF;
178 const SIInstrInfo *TII;
179 const SIRegisterInfo *TRI;
180 const GCNSubtarget *ST;
181 const SIMachineFunctionInfo *MFI;
182
183 bool frameIndexMayFold(const MachineInstr &UseMI, int OpNo,
184 const FoldableDef &OpToFold) const;
185
186 // TODO: Just use TII::getVALUOp
187 unsigned convertToVALUOp(unsigned Opc, bool UseVOP3 = false) const {
188 switch (Opc) {
189 case AMDGPU::S_ADD_I32: {
190 if (ST->hasAddNoCarryInsts())
191 return UseVOP3 ? AMDGPU::V_ADD_U32_e64 : AMDGPU::V_ADD_U32_e32;
192 return UseVOP3 ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_ADD_CO_U32_e32;
193 }
194 case AMDGPU::S_OR_B32:
195 return UseVOP3 ? AMDGPU::V_OR_B32_e64 : AMDGPU::V_OR_B32_e32;
196 case AMDGPU::S_AND_B32:
197 return UseVOP3 ? AMDGPU::V_AND_B32_e64 : AMDGPU::V_AND_B32_e32;
198 case AMDGPU::S_MUL_I32:
199 return AMDGPU::V_MUL_LO_U32_e64;
200 default:
201 return AMDGPU::INSTRUCTION_LIST_END;
202 }
203 }
204
205 bool foldCopyToVGPROfScalarAddOfFrameIndex(Register DstReg, Register SrcReg,
206 MachineInstr &MI) const;
207
208 bool updateOperand(FoldCandidate &Fold) const;
209
210 bool canUseImmWithOpSel(const MachineInstr *MI, unsigned UseOpNo,
211 int64_t ImmVal) const;
212
213 /// Try to fold immediate \p ImmVal into \p MI's operand at index \p UseOpNo.
214 bool tryFoldImmWithOpSel(MachineInstr *MI, unsigned UseOpNo,
215 int64_t ImmVal) const;
216
217 bool tryAddToFoldList(SmallVectorImpl<FoldCandidate> &FoldList,
218 MachineInstr *MI, unsigned OpNo,
219 const FoldableDef &OpToFold) const;
220 bool isUseSafeToFold(const MachineInstr &MI,
221 const MachineOperand &UseMO) const;
222
223 const TargetRegisterClass *getRegSeqInit(
224 MachineInstr &RegSeq,
225 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs) const;
226
227 const TargetRegisterClass *
228 getRegSeqInit(SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
229 Register UseReg) const;
230
231 std::pair<int64_t, const TargetRegisterClass *>
232 isRegSeqSplat(MachineInstr &RegSeg) const;
233
234 bool tryFoldRegSeqSplat(MachineInstr *UseMI, unsigned UseOpIdx,
235 int64_t SplatVal,
236 const TargetRegisterClass *SplatRC) const;
237
238 bool tryToFoldACImm(const FoldableDef &OpToFold, MachineInstr *UseMI,
239 unsigned UseOpIdx,
240 SmallVectorImpl<FoldCandidate> &FoldList) const;
241 bool foldOperand(FoldableDef OpToFold, MachineInstr *UseMI, int UseOpIdx,
243 SmallVectorImpl<MachineInstr *> &CopiesToReplace) const;
244
245 bool tryConstantFoldOp(MachineInstr *MI) const;
246 bool tryFoldCndMask(MachineInstr &MI) const;
247 bool tryFoldZeroHighBits(MachineInstr &MI) const;
248 bool foldInstOperand(MachineInstr &MI, const FoldableDef &OpToFold) const;
249
250 bool foldCopyToAGPRRegSequence(MachineInstr *CopyMI) const;
251 bool tryFoldFoldableCopy(MachineInstr &MI,
252 MachineOperand *&CurrentKnownM0Val) const;
253
254 const MachineOperand *isClamp(const MachineInstr &MI) const;
255 bool tryFoldClamp(MachineInstr &MI);
256
257 std::pair<const MachineOperand *, int> isOMod(const MachineInstr &MI) const;
258 bool tryFoldOMod(MachineInstr &MI);
259 bool tryFoldRegSequence(MachineInstr &MI);
260 bool tryFoldPhiAGPR(MachineInstr &MI);
261 bool tryFoldLoad(MachineInstr &MI);
262
263 bool tryOptimizeAGPRPhis(MachineBasicBlock &MBB);
264
265public:
266 SIFoldOperandsImpl() = default;
267
268 bool run(MachineFunction &MF);
269};
270
271class SIFoldOperandsLegacy : public MachineFunctionPass {
272public:
273 static char ID;
274
275 SIFoldOperandsLegacy() : MachineFunctionPass(ID) {}
276
277 bool runOnMachineFunction(MachineFunction &MF) override {
278 if (skipFunction(MF.getFunction()))
279 return false;
280 return SIFoldOperandsImpl().run(MF);
281 }
282
283 StringRef getPassName() const override { return "SI Fold Operands"; }
284
285 void getAnalysisUsage(AnalysisUsage &AU) const override {
286 AU.setPreservesCFG();
288 }
289
290 MachineFunctionProperties getRequiredProperties() const override {
291 return MachineFunctionProperties().setIsSSA();
292 }
293};
294
295} // End anonymous namespace.
296
297INITIALIZE_PASS(SIFoldOperandsLegacy, DEBUG_TYPE, "SI Fold Operands", false,
298 false)
299
300char SIFoldOperandsLegacy::ID = 0;
301
302char &llvm::SIFoldOperandsLegacyID = SIFoldOperandsLegacy::ID;
303
306 const MachineOperand &MO) {
307 const TargetRegisterClass *RC = MRI.getRegClass(MO.getReg());
308 if (const TargetRegisterClass *SubRC =
309 TRI.getSubRegisterClass(RC, MO.getSubReg()))
310 RC = SubRC;
311 return RC;
312}
313
314// Map multiply-accumulate opcode to corresponding multiply-add opcode if any.
315static unsigned macToMad(unsigned Opc) {
316 switch (Opc) {
317 case AMDGPU::V_MAC_F32_e64:
318 return AMDGPU::V_MAD_F32_e64;
319 case AMDGPU::V_MAC_F16_e64:
320 return AMDGPU::V_MAD_F16_e64;
321 case AMDGPU::V_FMAC_F32_e64:
322 return AMDGPU::V_FMA_F32_e64;
323 case AMDGPU::V_FMAC_F16_e64:
324 return AMDGPU::V_FMA_F16_gfx9_e64;
325 case AMDGPU::V_FMAC_F16_t16_e64:
326 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
327 case AMDGPU::V_FMAC_F16_fake16_e64:
328 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
329 case AMDGPU::V_FMAC_LEGACY_F32_e64:
330 return AMDGPU::V_FMA_LEGACY_F32_e64;
331 case AMDGPU::V_FMAC_F64_e64:
332 return AMDGPU::V_FMA_F64_e64;
333 }
334 return AMDGPU::INSTRUCTION_LIST_END;
335}
336
337// TODO: Add heuristic that the frame index might not fit in the addressing mode
338// immediate offset to avoid materializing in loops.
339bool SIFoldOperandsImpl::frameIndexMayFold(const MachineInstr &UseMI, int OpNo,
340 const FoldableDef &OpToFold) const {
341 if (!OpToFold.isFI())
342 return false;
343
344 const unsigned Opc = UseMI.getOpcode();
345 switch (Opc) {
346 case AMDGPU::S_ADD_I32:
347 case AMDGPU::S_ADD_U32:
348 case AMDGPU::V_ADD_U32_e32:
349 case AMDGPU::V_ADD_CO_U32_e32:
350 // TODO: Possibly relax hasOneUse. It matters more for mubuf, since we have
351 // to insert the wave size shift at every point we use the index.
352 // TODO: Fix depending on visit order to fold immediates into the operand
353 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
354 MRI->hasOneNonDBGUse(UseMI.getOperand(OpNo).getReg());
355 case AMDGPU::V_ADD_U32_e64:
356 case AMDGPU::V_ADD_CO_U32_e64:
357 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
358 MRI->hasOneNonDBGUse(UseMI.getOperand(OpNo).getReg());
359 default:
360 break;
361 }
362
363 if (TII->isMUBUF(UseMI))
364 return OpNo == AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr);
365 if (!TII->isFLATScratch(UseMI))
366 return false;
367
368 int SIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::saddr);
369 if (OpNo == SIdx)
370 return true;
371
372 int VIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr);
373 return OpNo == VIdx && SIdx == -1;
374}
375
376/// Fold %vgpr = COPY (S_ADD_I32 x, frameindex)
377///
378/// => %vgpr = V_ADD_U32 x, frameindex
379bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
380 Register DstReg, Register SrcReg, MachineInstr &MI) const {
381 if (TRI->isVGPR(*MRI, DstReg) && TRI->isSGPRReg(*MRI, SrcReg) &&
382 MRI->hasOneNonDBGUse(SrcReg)) {
383 MachineInstr *Def = MRI->getVRegDef(SrcReg);
384 if (!Def || Def->getNumOperands() != 4)
385 return false;
386
387 MachineOperand *Src0 = &Def->getOperand(1);
388 MachineOperand *Src1 = &Def->getOperand(2);
389
390 // TODO: This is profitable with more operand types, and for more
391 // opcodes. But ultimately this is working around poor / nonexistent
392 // regbankselect.
393 if (!Src0->isFI() && !Src1->isFI())
394 return false;
395
396 if (Src0->isFI())
397 std::swap(Src0, Src1);
398
399 const bool UseVOP3 = !Src0->isImm() || TII->isInlineConstant(*Src0);
400 unsigned NewOp = convertToVALUOp(Def->getOpcode(), UseVOP3);
401 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
402 !Def->getOperand(3).isDead()) // Check if scc is dead
403 return false;
404
405 MachineBasicBlock *MBB = Def->getParent();
406 const DebugLoc &DL = Def->getDebugLoc();
407 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
408 MachineInstrBuilder Add =
409 BuildMI(*MBB, *Def, DL, TII->get(NewOp), DstReg);
410
411 if (Add->getDesc().getNumDefs() == 2) {
412 Register CarryOutReg = MRI->createVirtualRegister(TRI->getBoolRC());
413 Add.addDef(CarryOutReg, RegState::Dead);
414 MRI->setRegAllocationHint(CarryOutReg, 0, TRI->getVCC());
415 }
416
417 Add.add(*Src0).add(*Src1).setMIFlags(Def->getFlags());
418 if (AMDGPU::hasNamedOperand(NewOp, AMDGPU::OpName::clamp))
419 Add.addImm(0);
420
421 Def->eraseFromParent();
422 MI.eraseFromParent();
423 return true;
424 }
425
426 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
427
429 MBB->computeRegisterLiveness(TRI, AMDGPU::VCC, *Def, 16);
430 if (Liveness == MachineBasicBlock::LQR_Dead) {
431 // TODO: If src1 satisfies operand constraints, use vop3 version.
432 BuildMI(*MBB, *Def, DL, TII->get(NewOp), DstReg)
433 .add(*Src0)
434 .add(*Src1)
435 .setOperandDead(3) // implicit-def $vcc
436 .setMIFlags(Def->getFlags());
437 Def->eraseFromParent();
438 MI.eraseFromParent();
439 return true;
440 }
441 }
442
443 return false;
444}
445
447 return new SIFoldOperandsLegacy();
448}
449
450bool SIFoldOperandsImpl::canUseImmWithOpSel(const MachineInstr *MI,
451 unsigned UseOpNo,
452 int64_t ImmVal) const {
456 return false;
457
458 const MachineOperand &Old = MI->getOperand(UseOpNo);
459 int OpNo = MI->getOperandNo(&Old);
460
461 unsigned Opcode = MI->getOpcode();
462 uint8_t OpType = TII->get(Opcode).operands()[OpNo].OperandType;
463 switch (OpType) {
464 default:
465 return false;
473 // VOP3 packed instructions ignore op_sel source modifiers, we cannot encode
474 // two different constants.
476 static_cast<uint16_t>(ImmVal) != static_cast<uint16_t>(ImmVal >> 16))
477 return false;
478 break;
479 }
480
481 return true;
482}
483
484bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *MI, unsigned UseOpNo,
485 int64_t ImmVal) const {
486 MachineOperand &Old = MI->getOperand(UseOpNo);
487 unsigned Opcode = MI->getOpcode();
488 int OpNo = MI->getOperandNo(&Old);
489 uint8_t OpType = TII->get(Opcode).operands()[OpNo].OperandType;
490
491 // If the literal can be inlined as-is, apply it and short-circuit the
492 // tests below. The main motivation for this is to avoid unintuitive
493 // uses of opsel.
494 if (AMDGPU::isInlinableLiteralV216(ImmVal, OpType)) {
495 Old.ChangeToImmediate(ImmVal);
496 return true;
497 }
498
499 // Refer to op_sel/op_sel_hi and check if we can change the immediate and
500 // op_sel in a way that allows an inline constant.
501 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
502 unsigned SrcIdx = ~0;
503 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
504 ModName = AMDGPU::OpName::src0_modifiers;
505 SrcIdx = 0;
506 } else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
507 ModName = AMDGPU::OpName::src1_modifiers;
508 SrcIdx = 1;
509 } else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
510 ModName = AMDGPU::OpName::src2_modifiers;
511 SrcIdx = 2;
512 }
513 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
514 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
515 MachineOperand &Mod = MI->getOperand(ModIdx);
516 unsigned ModVal = Mod.getImm();
517
518 uint16_t ImmLo =
519 static_cast<uint16_t>(ImmVal >> (ModVal & SISrcMods::OP_SEL_0 ? 16 : 0));
520 uint16_t ImmHi =
521 static_cast<uint16_t>(ImmVal >> (ModVal & SISrcMods::OP_SEL_1 ? 16 : 0));
522 uint32_t Imm = (static_cast<uint32_t>(ImmHi) << 16) | ImmLo;
523 unsigned NewModVal = ModVal & ~(SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1);
524
525 // Helper function that attempts to inline the given value with a newly
526 // chosen opsel pattern.
527 auto tryFoldToInline = [&](uint32_t Imm) -> bool {
528 if (AMDGPU::isInlinableLiteralV216(Imm, OpType)) {
529 Mod.setImm(NewModVal | SISrcMods::OP_SEL_1);
530 Old.ChangeToImmediate(Imm);
531 return true;
532 }
533
534 // Try to shuffle the halves around and leverage opsel to get an inline
535 // constant.
536 uint16_t Lo = static_cast<uint16_t>(Imm);
537 uint16_t Hi = static_cast<uint16_t>(Imm >> 16);
538 if (Lo == Hi) {
539 if (AMDGPU::isInlinableLiteralV216(Lo, OpType)) {
540 Mod.setImm(NewModVal);
542 return true;
543 }
544
545 if (static_cast<int16_t>(Lo) < 0) {
546 int32_t SExt = static_cast<int16_t>(Lo);
547 if (AMDGPU::isInlinableLiteralV216(SExt, OpType)) {
548 Mod.setImm(NewModVal);
549 Old.ChangeToImmediate(SExt);
550 return true;
551 }
552 }
553
554 // This check is only useful for integer instructions
555 if (OpType == AMDGPU::OPERAND_REG_IMM_V2INT16) {
556 if (AMDGPU::isInlinableLiteralV216(Lo << 16, OpType)) {
557 Mod.setImm(NewModVal | SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1);
558 Old.ChangeToImmediate(static_cast<uint32_t>(Lo) << 16);
559 return true;
560 }
561 }
562 } else {
563 uint32_t Swapped = (static_cast<uint32_t>(Lo) << 16) | Hi;
564 if (AMDGPU::isInlinableLiteralV216(Swapped, OpType)) {
565 Mod.setImm(NewModVal | SISrcMods::OP_SEL_0);
566 Old.ChangeToImmediate(Swapped);
567 return true;
568 }
569 }
570
571 return false;
572 };
573
574 if (tryFoldToInline(Imm))
575 return true;
576
577 // Replace integer addition by subtraction and vice versa if it allows
578 // folding the immediate to an inline constant.
579 //
580 // We should only ever get here for SrcIdx == 1 due to canonicalization
581 // earlier in the pipeline, but we double-check here to be safe / fully
582 // general.
583 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
584 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
585 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
586 unsigned ClampIdx =
587 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
588 bool Clamp = MI->getOperand(ClampIdx).getImm() != 0;
589
590 if (!Clamp) {
591 uint16_t NegLo = -static_cast<uint16_t>(Imm);
592 uint16_t NegHi = -static_cast<uint16_t>(Imm >> 16);
593 uint32_t NegImm = (static_cast<uint32_t>(NegHi) << 16) | NegLo;
594
595 if (tryFoldToInline(NegImm)) {
596 unsigned NegOpcode =
597 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
598 MI->setDesc(TII->get(NegOpcode));
599 return true;
600 }
601 }
602 }
603
604 return false;
605}
606
607bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold) const {
608 MachineInstr *MI = Fold.UseMI;
609 MachineOperand &Old = MI->getOperand(Fold.UseOpNo);
610 assert(Old.isReg());
611
612 std::optional<int64_t> ImmVal;
613 if (Fold.isImm())
614 ImmVal = Fold.Def.getEffectiveImmVal();
615
616 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
617 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
618 return true;
619
620 // We can't represent the candidate as an inline constant. Try as a literal
621 // with the original opsel, checking constant bus limitations.
622 MachineOperand New = MachineOperand::CreateImm(*ImmVal);
623 int OpNo = MI->getOperandNo(&Old);
624 if (!TII->isOperandLegal(*MI, OpNo, &New))
625 return false;
626 Old.ChangeToImmediate(*ImmVal);
627 return true;
628 }
629
630 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
631 MachineBasicBlock *MBB = MI->getParent();
632 auto Liveness = MBB->computeRegisterLiveness(TRI, AMDGPU::VCC, MI, 16);
633 if (Liveness != MachineBasicBlock::LQR_Dead) {
634 LLVM_DEBUG(dbgs() << "Not shrinking due to live vcc: " << *MI);
635 return false;
636 }
637
638 int Op32 = Fold.ShrinkOpcode;
639 MachineOperand &Dst0 = MI->getOperand(0);
640 MachineOperand &Dst1 = MI->getOperand(1);
641 assert(Dst0.isDef() && Dst1.isDef());
642
643 bool HaveNonDbgCarryUse = !MRI->use_nodbg_empty(Dst1.getReg());
644
645 const TargetRegisterClass *Dst0RC = MRI->getRegClass(Dst0.getReg());
646 Register NewReg0 = MRI->createVirtualRegister(Dst0RC);
647
648 MachineInstr *Inst32 = TII->buildShrunkInst(*MI, Op32);
649
650 if (HaveNonDbgCarryUse) {
651 BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(AMDGPU::COPY),
652 Dst1.getReg())
653 .addReg(AMDGPU::VCC, RegState::Kill);
654 }
655
656 // Keep the old instruction around to avoid breaking iterators, but
657 // replace it with a dummy instruction to remove uses.
658 //
659 // FIXME: We should not invert how this pass looks at operands to avoid
660 // this. Should track set of foldable movs instead of looking for uses
661 // when looking at a use.
662 Dst0.setReg(NewReg0);
663 for (unsigned I = MI->getNumOperands() - 1; I > 0; --I)
664 MI->removeOperand(I);
665 MI->setDesc(TII->get(AMDGPU::IMPLICIT_DEF));
666
667 if (Fold.Commuted)
668 TII->commuteInstruction(*Inst32, false);
669 return true;
670 }
671
672 assert(!Fold.needsShrink() && "not handled");
673
674 if (ImmVal) {
675 if (Old.isTied()) {
676 int NewMFMAOpc = AMDGPU::getMFMAEarlyClobberOp(MI->getOpcode());
677 if (NewMFMAOpc == -1)
678 return false;
679 MI->setDesc(TII->get(NewMFMAOpc));
680 MI->untieRegOperand(0);
681 const MCInstrDesc &MCID = MI->getDesc();
682 for (unsigned I = 0; I < MI->getNumDefs(); ++I)
684 MI->getOperand(I).setIsEarlyClobber(true);
685 }
686
687 // TODO: Should we try to avoid adding this to the candidate list?
688 MachineOperand New = MachineOperand::CreateImm(*ImmVal);
689 int OpNo = MI->getOperandNo(&Old);
690 if (!TII->isOperandLegal(*MI, OpNo, &New))
691 return false;
692
693 Old.ChangeToImmediate(*ImmVal);
694 return true;
695 }
696
697 if (Fold.isGlobal()) {
698 Old.ChangeToGA(Fold.Def.OpToFold->getGlobal(),
699 Fold.Def.OpToFold->getOffset(),
700 Fold.Def.OpToFold->getTargetFlags());
701 return true;
702 }
703
704 if (Fold.isFI()) {
705 Old.ChangeToFrameIndex(Fold.getFI());
706 return true;
707 }
708
709 MachineOperand *New = Fold.Def.OpToFold;
710
711 // Verify the register is compatible with the operand.
712 if (const TargetRegisterClass *OpRC =
713 TII->getRegClass(MI->getDesc(), Fold.UseOpNo)) {
714 const TargetRegisterClass *NewRC =
715 TRI->getRegClassForReg(*MRI, New->getReg());
716
717 const TargetRegisterClass *ConstrainRC = OpRC;
718 if (New->getSubReg()) {
719 ConstrainRC =
720 TRI->getMatchingSuperRegClass(NewRC, OpRC, New->getSubReg());
721
722 if (!ConstrainRC)
723 return false;
724 }
725
726 if (New->getReg().isVirtual() &&
727 !MRI->constrainRegClass(New->getReg(), ConstrainRC)) {
728 LLVM_DEBUG(dbgs() << "Cannot constrain " << printReg(New->getReg(), TRI)
729 << TRI->getRegClassName(ConstrainRC) << '\n');
730 return false;
731 }
732 }
733
734 // Rework once the VS_16 register class is updated to include proper
735 // 16-bit SGPRs instead of 32-bit ones.
736 if (Old.getSubReg() == AMDGPU::lo16 && TRI->isSGPRReg(*MRI, New->getReg()))
737 Old.setSubReg(AMDGPU::NoSubRegister);
738 if (New->getReg().isPhysical()) {
739 Old.substPhysReg(New->getReg(), *TRI);
740 } else {
741 Register OldReg = Old.getReg();
742 Old.substVirtReg(New->getReg(), New->getSubReg(), *TRI);
743 Old.setIsUndef(New->isUndef());
744
745 // If MI is in a BUNDLE, also update header's matching implicit use.
746 if (MI->isBundledWithPred()) {
747 MachineInstr &Header = *getBundleStart(MI->getIterator());
748 for (MachineOperand &MO : Header.operands()) {
749 if (MO.getReg() == OldReg) {
750 MO.setReg(New->getReg());
751 MO.setSubReg(New->getSubReg());
752 }
753 }
754 }
755 }
756 return true;
757}
758
760 FoldCandidate &&Entry) {
761 // Skip additional folding on the same operand.
762 for (FoldCandidate &Fold : FoldList)
763 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
764 return;
765 LLVM_DEBUG(dbgs() << "Append " << (Entry.Commuted ? "commuted" : "normal")
766 << " operand " << Entry.UseOpNo << "\n " << *Entry.UseMI);
767 FoldList.push_back(Entry);
768}
769
771 MachineInstr *MI, unsigned OpNo,
772 const FoldableDef &FoldOp,
773 bool Commuted = false, int ShrinkOp = -1) {
774 appendFoldCandidate(FoldList,
775 FoldCandidate(MI, OpNo, FoldOp, Commuted, ShrinkOp));
776}
777
778// Returns true if the instruction is a packed F32 instruction and the
779// corresponding scalar operand reads 32 bits and replicates the bits to both
780// channels.
782 const GCNSubtarget *ST, MachineInstr *MI, unsigned OpNo) {
783 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
784 return false;
785 const MCOperandInfo &OpDesc = MI->getDesc().operands()[OpNo];
787}
788
789// Packed FP32 instructions only read 32 bits from a scalar operand (SGPR or
790// literal) and replicates the bits to both channels. Therefore, if the hi and
791// lo are not same, we can't fold it.
793 const FoldableDef &OpToFold) {
794 assert(OpToFold.isImm() && "Expected immediate operand");
795 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
796 uint32_t Lo = Lo_32(ImmVal);
797 uint32_t Hi = Hi_32(ImmVal);
798 return Lo == Hi;
799}
800
801bool SIFoldOperandsImpl::tryAddToFoldList(
802 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *MI, unsigned OpNo,
803 const FoldableDef &OpToFold) const {
804 const unsigned Opc = MI->getOpcode();
805
806 auto tryToFoldAsFMAAKorMK = [&]() {
807 if (!OpToFold.isImm())
808 return false;
809
810 const bool TryAK = OpNo == 3;
811 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
812 MI->setDesc(TII->get(NewOpc));
813
814 // We have to fold into operand which would be Imm not into OpNo.
815 bool FoldAsFMAAKorMK =
816 tryAddToFoldList(FoldList, MI, TryAK ? 3 : 2, OpToFold);
817 if (FoldAsFMAAKorMK) {
818 // Untie Src2 of fmac.
819 MI->untieRegOperand(3);
820 // For fmamk swap operands 1 and 2 if OpToFold was meant for operand 1.
821 if (OpNo == 1) {
822 MachineOperand &Op1 = MI->getOperand(1);
823 MachineOperand &Op2 = MI->getOperand(2);
824 Register OldReg = Op1.getReg();
825 // Operand 2 might be an inlinable constant
826 if (Op2.isImm()) {
827 Op1.ChangeToImmediate(Op2.getImm());
828 Op2.ChangeToRegister(OldReg, false);
829 } else {
830 Op1.setReg(Op2.getReg());
831 Op2.setReg(OldReg);
832 }
833 }
834 return true;
835 }
836 MI->setDesc(TII->get(Opc));
837 return false;
838 };
839
840 bool IsLegal = OpToFold.isOperandLegal(*TII, *MI, OpNo);
841 if (!IsLegal && OpToFold.isImm()) {
842 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
843 IsLegal = canUseImmWithOpSel(MI, OpNo, *ImmVal);
844 }
845
846 if (!IsLegal) {
847 // Special case for v_mac_{f16, f32}_e64 if we are trying to fold into src2
848 unsigned NewOpc = macToMad(Opc);
849 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
850 // Check if changing this to a v_mad_{f16, f32} instruction will allow us
851 // to fold the operand.
852 MI->setDesc(TII->get(NewOpc));
853 bool AddOpSel = !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::op_sel) &&
854 AMDGPU::hasNamedOperand(NewOpc, AMDGPU::OpName::op_sel);
855 if (AddOpSel)
856 MI->addOperand(MachineOperand::CreateImm(0));
857 bool FoldAsMAD = tryAddToFoldList(FoldList, MI, OpNo, OpToFold);
858 if (FoldAsMAD) {
859 MI->untieRegOperand(OpNo);
860 return true;
861 }
862 if (AddOpSel)
863 MI->removeOperand(MI->getNumExplicitOperands() - 1);
864 MI->setDesc(TII->get(Opc));
865 }
866
867 // Special case for s_fmac_f32 if we are trying to fold into Src2.
868 // By transforming into fmaak we can untie Src2 and make folding legal.
869 if (Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
870 if (tryToFoldAsFMAAKorMK())
871 return true;
872 }
873
874 // Special case for s_setreg_b32
875 if (OpToFold.isImm()) {
876 unsigned ImmOpc = 0;
877 if (Opc == AMDGPU::S_SETREG_B32)
878 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
879 else if (Opc == AMDGPU::S_SETREG_B32_mode)
880 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
881 if (ImmOpc) {
882 MI->setDesc(TII->get(ImmOpc));
883 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
884 return true;
885 }
886 }
887
888 // Operand is not legal, so try to commute the instruction to
889 // see if this makes it possible to fold.
890 unsigned CommuteOpNo = TargetInstrInfo::CommuteAnyOperandIndex;
891 bool CanCommute = TII->findCommutedOpIndices(*MI, OpNo, CommuteOpNo);
892 if (!CanCommute)
893 return false;
894
895 MachineOperand &Op = MI->getOperand(OpNo);
896 MachineOperand &CommutedOp = MI->getOperand(CommuteOpNo);
897
898 // One of operands might be an Imm operand, and OpNo may refer to it after
899 // the call of commuteInstruction() below. Such situations are avoided
900 // here explicitly as OpNo must be a register operand to be a candidate
901 // for memory folding.
902 if (!Op.isReg() || !CommutedOp.isReg())
903 return false;
904
905 // The same situation with an immediate could reproduce if both inputs are
906 // the same register.
907 if (Op.isReg() && CommutedOp.isReg() &&
908 (Op.getReg() == CommutedOp.getReg() &&
909 Op.getSubReg() == CommutedOp.getSubReg()))
910 return false;
911
912 if (!TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo))
913 return false;
914
915 int Op32 = -1;
916 if (!OpToFold.isOperandLegal(*TII, *MI, CommuteOpNo)) {
917 if ((Opc != AMDGPU::V_ADD_CO_U32_e64 && Opc != AMDGPU::V_SUB_CO_U32_e64 &&
918 Opc != AMDGPU::V_SUBREV_CO_U32_e64) || // FIXME
919 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
920 TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo);
921 return false;
922 }
923
924 // Verify the other operand is a VGPR, otherwise we would violate the
925 // constant bus restriction.
926 MachineOperand &OtherOp = MI->getOperand(OpNo);
927 if (!OtherOp.isReg() ||
928 !TII->getRegisterInfo().isVGPR(*MRI, OtherOp.getReg()))
929 return false;
930
931 assert(MI->getOperand(1).isDef());
932
933 // Make sure to get the 32-bit version of the commuted opcode.
934 unsigned MaybeCommutedOpc = MI->getOpcode();
935 Op32 = AMDGPU::getVOPe32(MaybeCommutedOpc);
936 }
937
938 appendFoldCandidate(FoldList, MI, CommuteOpNo, OpToFold, /*Commuted=*/true,
939 Op32);
940 return true;
941 }
942
943 // Special case for s_fmac_f32 if we are trying to fold into Src0 or Src1.
944 // By changing into fmamk we can untie Src2.
945 // If folding for Src0 happens first and it is identical operand to Src1 we
946 // should avoid transforming into fmamk which requires commuting as it would
947 // cause folding into Src1 to fail later on due to wrong OpNo used.
948 if (Opc == AMDGPU::S_FMAC_F32 &&
949 (OpNo != 1 || !MI->getOperand(1).isIdenticalTo(MI->getOperand(2)))) {
950 if (tryToFoldAsFMAAKorMK())
951 return true;
952 }
953
954 // Special case for PK_F32 instructions if we are trying to fold an imm to
955 // src0 or src1.
956 if (OpToFold.isImm() &&
959 return false;
960
961 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
962 return true;
963}
964
965bool SIFoldOperandsImpl::isUseSafeToFold(const MachineInstr &MI,
966 const MachineOperand &UseMO) const {
967 // Operands of SDWA instructions must be registers.
968 return !TII->isSDWA(MI);
969}
970
972 const MachineRegisterInfo &MRI,
973 Register SrcReg) {
974 MachineOperand *Sub = nullptr;
975 for (MachineInstr *SubDef = MRI.getVRegDef(SrcReg);
976 SubDef && TII.isFoldableCopy(*SubDef);
977 SubDef = MRI.getVRegDef(Sub->getReg())) {
978 unsigned SrcIdx = TII.getFoldableCopySrcIdx(*SubDef);
979 MachineOperand &SrcOp = SubDef->getOperand(SrcIdx);
980
981 if (SrcOp.isImm())
982 return &SrcOp;
983 if (!SrcOp.isReg() || SrcOp.getReg().isPhysical())
984 break;
985 Sub = &SrcOp;
986 // TODO: Support compose
987 if (SrcOp.getSubReg())
988 break;
989 }
990
991 return Sub;
992}
993
994const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
995 MachineInstr &RegSeq,
996 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs) const {
997
998 assert(RegSeq.isRegSequence());
999
1000 const TargetRegisterClass *RC = nullptr;
1001
1002 for (unsigned I = 1, E = RegSeq.getNumExplicitOperands(); I != E; I += 2) {
1003 MachineOperand &SrcOp = RegSeq.getOperand(I);
1004 if (SrcOp.getReg().isPhysical())
1005 return nullptr;
1006 unsigned SubRegIdx = RegSeq.getOperand(I + 1).getImm();
1007
1008 // Only accept reg_sequence with uniform reg class inputs for simplicity.
1009 const TargetRegisterClass *OpRC = getRegOpRC(*MRI, *TRI, SrcOp);
1010 if (!RC)
1011 RC = OpRC;
1012 else if (!TRI->getCommonSubClass(RC, OpRC))
1013 return nullptr;
1014
1015 if (SrcOp.getSubReg()) {
1016 // TODO: Handle subregister compose
1017 Defs.emplace_back(&SrcOp, SubRegIdx);
1018 continue;
1019 }
1020
1021 MachineOperand *DefSrc = lookUpCopyChain(*TII, *MRI, SrcOp.getReg());
1022 if (DefSrc && (DefSrc->isReg() || DefSrc->isImm())) {
1023 Defs.emplace_back(DefSrc, SubRegIdx);
1024 continue;
1025 }
1026
1027 Defs.emplace_back(&SrcOp, SubRegIdx);
1028 }
1029
1030 return RC;
1031}
1032
1033// Find a def of the UseReg, check if it is a reg_sequence and find initializers
1034// for each subreg, tracking it to an immediate if possible. Returns the
1035// register class of the inputs on success.
1036const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
1037 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1038 Register UseReg) const {
1039 MachineInstr *Def = MRI->getVRegDef(UseReg);
1040 if (!Def || !Def->isRegSequence())
1041 return nullptr;
1042
1043 return getRegSeqInit(*Def, Defs);
1044}
1045
1046std::pair<int64_t, const TargetRegisterClass *>
1047SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const {
1049 const TargetRegisterClass *SrcRC = getRegSeqInit(RegSeq, Defs);
1050 if (!SrcRC)
1051 return {};
1052
1053 bool TryToMatchSplat64 = false;
1054
1055 int64_t Imm;
1056 for (unsigned I = 0, E = Defs.size(); I != E; ++I) {
1057 const MachineOperand *Op = Defs[I].first;
1058 if (!Op->isImm())
1059 return {};
1060
1061 int64_t SubImm = Op->getImm();
1062 if (!I) {
1063 Imm = SubImm;
1064 continue;
1065 }
1066
1067 if (Imm != SubImm) {
1068 if (I == 1 && (E & 1) == 0) {
1069 // If we have an even number of inputs, there's a chance this is a
1070 // 64-bit element splat broken into 32-bit pieces.
1071 TryToMatchSplat64 = true;
1072 break;
1073 }
1074
1075 return {}; // Can only fold splat constants
1076 }
1077 }
1078
1079 if (!TryToMatchSplat64)
1080 return {Defs[0].first->getImm(), SrcRC};
1081
1082 // Fallback to recognizing 64-bit splats broken into 32-bit pieces
1083 // (i.e. recognize every other other element is 0 for 64-bit immediates)
1084 int64_t SplatVal64;
1085 for (unsigned I = 0, E = Defs.size(); I != E; I += 2) {
1086 const MachineOperand *Op0 = Defs[I].first;
1087 const MachineOperand *Op1 = Defs[I + 1].first;
1088
1089 if (!Op0->isImm() || !Op1->isImm())
1090 return {};
1091
1092 unsigned SubReg0 = Defs[I].second;
1093 unsigned SubReg1 = Defs[I + 1].second;
1094
1095 // Assume we're going to generally encounter reg_sequences with sorted
1096 // subreg indexes, so reject any that aren't consecutive.
1097 if (TRI->getChannelFromSubReg(SubReg0) + 1 !=
1098 TRI->getChannelFromSubReg(SubReg1))
1099 return {};
1100
1101 if (TRI->getSubRegIdxSize(SubReg0) != 32)
1102 return {};
1103
1104 int64_t MergedVal = Make_64(Op1->getImm(), Op0->getImm());
1105 if (I == 0)
1106 SplatVal64 = MergedVal;
1107 else if (SplatVal64 != MergedVal)
1108 return {};
1109 }
1110
1111 const TargetRegisterClass *RC64 = TRI->getSubRegisterClass(
1112 MRI->getRegClass(RegSeq.getOperand(0).getReg()), AMDGPU::sub0_sub1);
1113
1114 return {SplatVal64, RC64};
1115}
1116
1117bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1118 MachineInstr *UseMI, unsigned UseOpIdx, int64_t SplatVal,
1119 const TargetRegisterClass *SplatRC) const {
1120 const MCInstrDesc &Desc = UseMI->getDesc();
1121 if (UseOpIdx >= Desc.getNumOperands())
1122 return false;
1123
1124 // Filter out unhandled pseudos.
1125 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1126 return false;
1127
1128 int16_t RCID = TII->getOpRegClassID(Desc.operands()[UseOpIdx]);
1129 if (RCID == -1)
1130 return false;
1131
1132 const TargetRegisterClass *OpRC = TRI->getRegClass(RCID);
1133
1134 // Special case 0/-1, since when interpreted as a 64-bit element both halves
1135 // have the same bits. These are the only cases where a splat has the same
1136 // interpretation for 32-bit and 64-bit splats.
1137 if (SplatVal != 0 && SplatVal != -1) {
1138 // We need to figure out the scalar type read by the operand. e.g. the MFMA
1139 // operand will be AReg_128, and we want to check if it's compatible with an
1140 // AReg_32 constant.
1141 uint8_t OpTy = Desc.operands()[UseOpIdx].OperandType;
1142 switch (OpTy) {
1147 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1148 break;
1154 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1155 break;
1156 default:
1157 return false;
1158 }
1159
1160 if (!TRI->getCommonSubClass(OpRC, SplatRC))
1161 return false;
1162 }
1163
1164 MachineOperand TmpOp = MachineOperand::CreateImm(SplatVal);
1165 if (!TII->isOperandLegal(*UseMI, UseOpIdx, &TmpOp))
1166 return false;
1167
1168 return true;
1169}
1170
1171bool SIFoldOperandsImpl::tryToFoldACImm(
1172 const FoldableDef &OpToFold, MachineInstr *UseMI, unsigned UseOpIdx,
1173 SmallVectorImpl<FoldCandidate> &FoldList) const {
1174 const MCInstrDesc &Desc = UseMI->getDesc();
1175 if (UseOpIdx >= Desc.getNumOperands())
1176 return false;
1177
1178 // Filter out unhandled pseudos.
1179 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1180 return false;
1181
1182 if (OpToFold.isImm() && OpToFold.isOperandLegal(*TII, *UseMI, UseOpIdx)) {
1185 return false;
1186 appendFoldCandidate(FoldList, UseMI, UseOpIdx, OpToFold);
1187 return true;
1188 }
1189
1190 return false;
1191}
1192
1193bool SIFoldOperandsImpl::foldOperand(
1194 FoldableDef OpToFold, MachineInstr *UseMI, int UseOpIdx,
1195 SmallVectorImpl<FoldCandidate> &FoldList,
1196 SmallVectorImpl<MachineInstr *> &CopiesToReplace) const {
1197 bool Changed = false;
1198 const MachineOperand *UseOp = &UseMI->getOperand(UseOpIdx);
1199
1200 if (!isUseSafeToFold(*UseMI, *UseOp))
1201 return Changed;
1202
1203 // FIXME: Fold operands with subregs.
1204 if (UseOp->isReg() && OpToFold.isReg()) {
1205 if (UseOp->isImplicit())
1206 return Changed;
1207 // Allow folding from SGPRs to 16-bit VGPRs.
1208 if (UseOp->getSubReg() != AMDGPU::NoSubRegister &&
1209 (UseOp->getSubReg() != AMDGPU::lo16 ||
1210 !TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1211 return Changed;
1212 }
1213
1214 // Special case for REG_SEQUENCE: We can't fold literals into
1215 // REG_SEQUENCE instructions, so we have to fold them into the
1216 // uses of REG_SEQUENCE.
1217 if (UseMI->isRegSequence()) {
1218 Register RegSeqDstReg = UseMI->getOperand(0).getReg();
1219 unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
1220
1221 int64_t SplatVal;
1222 const TargetRegisterClass *SplatRC;
1223 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*UseMI);
1224
1225 // Grab the use operands first
1227 llvm::make_pointer_range(MRI->use_nodbg_operands(RegSeqDstReg)));
1228 for (unsigned I = 0; I != UsesToProcess.size(); ++I) {
1229 MachineOperand *RSUse = UsesToProcess[I];
1230 MachineInstr *RSUseMI = RSUse->getParent();
1231 unsigned OpNo = RSUseMI->getOperandNo(RSUse);
1232
1233 if (SplatRC) {
1234 if (RSUseMI->isCopy()) {
1235 Register DstReg = RSUseMI->getOperand(0).getReg();
1236 append_range(UsesToProcess,
1238 continue;
1239 }
1240 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1241 FoldableDef SplatDef(SplatVal, SplatRC);
1242 appendFoldCandidate(FoldList, RSUseMI, OpNo, SplatDef);
1243 Changed = true;
1244 continue;
1245 }
1246 }
1247
1248 // TODO: Handle general compose
1249 if (RSUse->getSubReg() != RegSeqDstSubReg)
1250 continue;
1251
1252 // FIXME: We should avoid recursing here. There should be a cleaner split
1253 // between the in-place mutations and adding to the fold list.
1254 Changed |= foldOperand(OpToFold, RSUseMI, RSUseMI->getOperandNo(RSUse),
1255 FoldList, CopiesToReplace);
1256 }
1257
1258 return Changed;
1259 }
1260
1261 if (tryToFoldACImm(OpToFold, UseMI, UseOpIdx, FoldList))
1262 return true;
1263
1264 if (frameIndexMayFold(*UseMI, UseOpIdx, OpToFold)) {
1265 // Verify that this is a stack access.
1266 // FIXME: Should probably use stack pseudos before frame lowering.
1267
1268 if (TII->isMUBUF(*UseMI)) {
1269 if (TII->getNamedOperand(*UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1270 MFI->getScratchRSrcReg())
1271 return Changed;
1272
1273 // Ensure this is either relative to the current frame or the current
1274 // wave.
1275 MachineOperand &SOff =
1276 *TII->getNamedOperand(*UseMI, AMDGPU::OpName::soffset);
1277 if (!SOff.isImm() || SOff.getImm() != 0)
1278 return Changed;
1279 }
1280
1281 const unsigned Opc = UseMI->getOpcode();
1282 if (TII->isFLATScratch(*UseMI) &&
1283 AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr) &&
1284 !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::saddr)) {
1285 unsigned NewOpc = AMDGPU::getFlatScratchInstSSfromSV(Opc);
1286 unsigned CPol =
1287 TII->getNamedOperand(*UseMI, AMDGPU::OpName::cpol)->getImm();
1288 if ((CPol & AMDGPU::CPol::SCAL) &&
1290 return Changed;
1291
1292 UseMI->setDesc(TII->get(NewOpc));
1293 }
1294
1295 // A frame index will resolve to a positive constant, so it should always be
1296 // safe to fold the addressing mode, even pre-GFX9.
1297 UseMI->getOperand(UseOpIdx).ChangeToFrameIndex(OpToFold.getFI());
1298
1299 return true;
1300 }
1301
1302 bool FoldingImmLike =
1303 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1304
1305 if (FoldingImmLike && UseMI->isCopy()) {
1306 Register DestReg = UseMI->getOperand(0).getReg();
1307 Register SrcReg = UseMI->getOperand(1).getReg();
1308 unsigned UseSubReg = UseMI->getOperand(1).getSubReg();
1309 assert(SrcReg.isVirtual());
1310
1311 const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg);
1312
1313 // Don't fold into a copy to a physical register with the same class. Doing
1314 // so would interfere with the register coalescer's logic which would avoid
1315 // redundant initializations.
1316 if (DestReg.isPhysical() && SrcRC->contains(DestReg))
1317 return Changed;
1318
1319 const TargetRegisterClass *DestRC = TRI->getRegClassForReg(*MRI, DestReg);
1320 // In order to fold immediates into copies, we need to change the copy to a
1321 // MOV. Find a compatible mov instruction with the value.
1322 for (unsigned MovOp :
1323 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1324 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1325 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1326 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1327 const MCInstrDesc &MovDesc = TII->get(MovOp);
1328 const TargetRegisterClass *MovDstRC =
1329 TRI->getRegClass(TII->getOpRegClassID(MovDesc.operands()[0]));
1330
1331 // Fold if the destination register class of the MOV instruction (ResRC)
1332 // is a superclass of (or equal to) the destination register class of the
1333 // COPY (DestRC). If this condition fails, folding would be illegal.
1334 if (!DestRC->hasSuperClassEq(MovDstRC))
1335 continue;
1336
1337 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1338
1339 int16_t RegClassID = TII->getOpRegClassID(MovDesc.operands()[SrcIdx]);
1340 if (RegClassID != -1) {
1341 const TargetRegisterClass *MovSrcRC = TRI->getRegClass(RegClassID);
1342
1343 if (UseSubReg)
1344 MovSrcRC = TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1345
1346 // FIXME: We should be able to directly check immediate operand legality
1347 // for all cases, but gfx908 hacks break.
1348 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1349 (!OpToFold.isImm() ||
1350 !TII->isImmOperandLegal(MovDesc, SrcIdx,
1351 *OpToFold.getEffectiveImmVal())))
1352 break;
1353
1354 if (!MRI->constrainRegClass(SrcReg, MovSrcRC))
1355 break;
1356
1357 // FIXME: This is mutating the instruction only and deferring the actual
1358 // fold of the immediate
1359 } else {
1360 // For the _IMM_PSEUDO cases, there can be value restrictions on the
1361 // immediate to verify. Technically we should always verify this, but it
1362 // only matters for these concrete cases.
1363 // TODO: Handle non-imm case if it's useful.
1364 if (!OpToFold.isImm() ||
1365 !TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1366 break;
1367 }
1368
1371 while (ImpOpI != ImpOpE) {
1372 MachineInstr::mop_iterator Tmp = ImpOpI;
1373 ImpOpI++;
1375 }
1376 UseMI->setDesc(MovDesc);
1377
1378 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1379 const auto &SrcOp = UseMI->getOperand(UseOpIdx);
1380 MachineOperand NewSrcOp(SrcOp);
1381 UseMI->removeOperand(1);
1382 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // src0_modifiers
1383 UseMI->addOperand(NewSrcOp); // src0
1384 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // op_sel
1385 UseOpIdx = SrcIdx;
1386 UseOp = &UseMI->getOperand(UseOpIdx);
1387 }
1388 CopiesToReplace.push_back(UseMI);
1389 Changed = true;
1390 break;
1391 }
1392
1393 // We failed to replace the copy, so give up.
1394 if (UseMI->getOpcode() == AMDGPU::COPY)
1395 return Changed;
1396
1397 } else {
1398 if (UseMI->isCopy() && OpToFold.isReg() &&
1399 UseMI->getOperand(0).getReg().isVirtual() &&
1400 !UseMI->getOperand(1).getSubReg() &&
1401 OpToFold.DefMI->implicit_operands().empty()) {
1402 LLVM_DEBUG(dbgs() << "Folding " << *OpToFold.OpToFold << "\n into "
1403 << *UseMI);
1404 unsigned Size = TII->getOpSize(*UseMI, 1);
1405 Register UseReg = OpToFold.getReg();
1407 unsigned SubRegIdx = OpToFold.getSubReg();
1408 // Hack to allow 32-bit SGPRs to be folded into True16 instructions
1409 // Remove this if 16-bit SGPRs (i.e. SGPR_LO16) are added to the
1410 // VS_16RegClass
1411 //
1412 // Excerpt from AMDGPUGenRegisterInfoEnums.inc
1413 // NoSubRegister, //0
1414 // hi16, // 1
1415 // lo16, // 2
1416 // sub0, // 3
1417 // ...
1418 // sub1, // 11
1419 // sub1_hi16, // 12
1420 // sub1_lo16, // 13
1421 static_assert(AMDGPU::sub1_hi16 == 12, "Subregister layout has changed");
1422 if (Size == 2 && TRI->isVGPR(*MRI, UseMI->getOperand(0).getReg()) &&
1423 TRI->isSGPRReg(*MRI, UseReg)) {
1424 // Produce the 32 bit subregister index to which the 16-bit subregister
1425 // is aligned.
1426 if (SubRegIdx > AMDGPU::sub1) {
1427 LaneBitmask M = TRI->getSubRegIndexLaneMask(SubRegIdx);
1428 M |= M.getLane(M.getHighestLane() - 1);
1429 SmallVector<unsigned, 4> Indexes;
1430 TRI->getCoveringSubRegIndexes(TRI->getRegClassForReg(*MRI, UseReg), M,
1431 Indexes);
1432 assert(Indexes.size() == 1 && "Expected one 32-bit subreg to cover");
1433 SubRegIdx = Indexes[0];
1434 // 32-bit registers do not have a sub0 index
1435 } else if (TII->getOpSize(*UseMI, 1) == 4)
1436 SubRegIdx = 0;
1437 else
1438 SubRegIdx = AMDGPU::sub0;
1439 }
1440 UseMI->getOperand(1).setSubReg(SubRegIdx);
1441 UseMI->getOperand(1).setIsKill(false);
1442 CopiesToReplace.push_back(UseMI);
1443 OpToFold.OpToFold->setIsKill(false);
1444 Changed = true;
1445
1446 // Remove kill flags as kills may now be out of order with uses.
1447 MRI->clearKillFlags(UseReg);
1448 if (foldCopyToAGPRRegSequence(UseMI))
1449 return true;
1450 }
1451
1452 unsigned UseOpc = UseMI->getOpcode();
1453 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1454 (UseOpc == AMDGPU::V_READLANE_B32 &&
1455 (int)UseOpIdx ==
1456 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1457 // %vgpr = V_MOV_B32 imm
1458 // %sgpr = V_READFIRSTLANE_B32 %vgpr
1459 // =>
1460 // %sgpr = S_MOV_B32 imm
1461 if (FoldingImmLike) {
1463 UseMI->getOperand(UseOpIdx).getReg(),
1464 *OpToFold.DefMI, *UseMI))
1465 return Changed;
1466
1467 UseMI->setDesc(TII->get(AMDGPU::S_MOV_B32));
1469
1470 if (OpToFold.isImm()) {
1472 *OpToFold.getEffectiveImmVal());
1473 } else if (OpToFold.isFI())
1474 UseMI->getOperand(1).ChangeToFrameIndex(OpToFold.getFI());
1475 else {
1476 assert(OpToFold.isGlobal());
1477 UseMI->getOperand(1).ChangeToGA(OpToFold.OpToFold->getGlobal(),
1478 OpToFold.OpToFold->getOffset(),
1479 OpToFold.OpToFold->getTargetFlags());
1480 }
1481 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1482 return true;
1483 }
1484
1485 if (OpToFold.isReg() && TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1487 UseMI->getOperand(UseOpIdx).getReg(),
1488 *OpToFold.DefMI, *UseMI))
1489 return Changed;
1490
1491 // %vgpr = COPY %sgpr0
1492 // %sgpr1 = V_READFIRSTLANE_B32 %vgpr
1493 // =>
1494 // %sgpr1 = COPY %sgpr0
1495 UseMI->setDesc(TII->get(AMDGPU::COPY));
1496 UseMI->getOperand(1).setReg(OpToFold.getReg());
1497 UseMI->getOperand(1).setSubReg(OpToFold.getSubReg());
1498 UseMI->getOperand(1).setIsKill(false);
1499 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1501 return true;
1502 }
1503 }
1504
1505 const MCInstrDesc &UseDesc = UseMI->getDesc();
1506
1507 // Don't fold into target independent nodes. Target independent opcodes
1508 // don't have defined register classes.
1509 if (UseDesc.isVariadic() || UseOp->isImplicit() ||
1510 UseDesc.operands()[UseOpIdx].RegClass == -1)
1511 return Changed;
1512 }
1513
1514 // FIXME: We could try to change the instruction from 64-bit to 32-bit
1515 // to enable more folding opportunities. The shrink operands pass
1516 // already does this.
1517
1518 Changed |= tryAddToFoldList(FoldList, UseMI, UseOpIdx, OpToFold);
1519 return Changed;
1520}
1521
1522static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result,
1524 switch (Opcode) {
1525 case AMDGPU::S_ADD_I32:
1526 case AMDGPU::S_ADD_U32:
1527 Result = LHS + RHS;
1528 return true;
1529 case AMDGPU::S_SUB_I32:
1530 case AMDGPU::S_SUB_U32:
1531 Result = LHS - RHS;
1532 return true;
1533 case AMDGPU::V_AND_B32_e64:
1534 case AMDGPU::V_AND_B32_e32:
1535 case AMDGPU::S_AND_B32:
1536 Result = LHS & RHS;
1537 return true;
1538 case AMDGPU::V_OR_B32_e64:
1539 case AMDGPU::V_OR_B32_e32:
1540 case AMDGPU::S_OR_B32:
1541 Result = LHS | RHS;
1542 return true;
1543 case AMDGPU::V_XOR_B32_e64:
1544 case AMDGPU::V_XOR_B32_e32:
1545 case AMDGPU::S_XOR_B32:
1546 Result = LHS ^ RHS;
1547 return true;
1548 case AMDGPU::S_XNOR_B32:
1549 Result = ~(LHS ^ RHS);
1550 return true;
1551 case AMDGPU::S_NAND_B32:
1552 Result = ~(LHS & RHS);
1553 return true;
1554 case AMDGPU::S_NOR_B32:
1555 Result = ~(LHS | RHS);
1556 return true;
1557 case AMDGPU::S_ANDN2_B32:
1558 Result = LHS & ~RHS;
1559 return true;
1560 case AMDGPU::S_ORN2_B32:
1561 Result = LHS | ~RHS;
1562 return true;
1563 case AMDGPU::V_LSHL_B32_e64:
1564 case AMDGPU::V_LSHL_B32_e32:
1565 case AMDGPU::S_LSHL_B32:
1566 // The instruction ignores the high bits for out of bounds shifts.
1567 Result = LHS << (RHS & 31);
1568 return true;
1569 case AMDGPU::V_LSHLREV_B32_e64:
1570 case AMDGPU::V_LSHLREV_B32_e32:
1571 Result = RHS << (LHS & 31);
1572 return true;
1573 case AMDGPU::V_LSHR_B32_e64:
1574 case AMDGPU::V_LSHR_B32_e32:
1575 case AMDGPU::S_LSHR_B32:
1576 Result = LHS >> (RHS & 31);
1577 return true;
1578 case AMDGPU::V_LSHRREV_B32_e64:
1579 case AMDGPU::V_LSHRREV_B32_e32:
1580 Result = RHS >> (LHS & 31);
1581 return true;
1582 case AMDGPU::V_ASHR_I32_e64:
1583 case AMDGPU::V_ASHR_I32_e32:
1584 case AMDGPU::S_ASHR_I32:
1585 Result = static_cast<int32_t>(LHS) >> (RHS & 31);
1586 return true;
1587 case AMDGPU::V_ASHRREV_I32_e64:
1588 case AMDGPU::V_ASHRREV_I32_e32:
1589 Result = static_cast<int32_t>(RHS) >> (LHS & 31);
1590 return true;
1591 default:
1592 return false;
1593 }
1594}
1595
1596static unsigned getMovOpc(bool IsScalar) {
1597 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1598}
1599
1600// Try to simplify operations with a constant that may appear after instruction
1601// selection.
1602// TODO: See if a frame index with a fixed offset can fold.
1603bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *MI) const {
1604 if (!MI->allImplicitDefsAreDead())
1605 return false;
1606
1607 unsigned Opc = MI->getOpcode();
1608
1609 int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
1610 if (Src0Idx == -1)
1611 return false;
1612
1613 MachineOperand *Src0 = &MI->getOperand(Src0Idx);
1614 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*Src0);
1615
1616 if ((Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
1617 Opc == AMDGPU::S_NOT_B32) &&
1618 Src0Imm) {
1619 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1620 TII->mutateAndCleanupImplicit(
1621 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
1622 return true;
1623 }
1624
1625 int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
1626 if (Src1Idx == -1)
1627 return false;
1628
1629 MachineOperand *Src1 = &MI->getOperand(Src1Idx);
1630 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*Src1);
1631
1632 if (!Src0Imm && !Src1Imm)
1633 return false;
1634
1635 // and k0, k1 -> v_mov_b32 (k0 & k1)
1636 // or k0, k1 -> v_mov_b32 (k0 | k1)
1637 // xor k0, k1 -> v_mov_b32 (k0 ^ k1)
1638 if (Src0Imm && Src1Imm) {
1639 int32_t NewImm;
1640 if (!evalBinaryInstruction(Opc, NewImm, *Src0Imm, *Src1Imm))
1641 return false;
1642
1643 bool IsSGPR = TRI->isSGPRReg(*MRI, MI->getOperand(0).getReg());
1644
1645 // Be careful to change the right operand, src0 may belong to a different
1646 // instruction.
1647 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1648 MI->removeOperand(Src1Idx);
1649 TII->mutateAndCleanupImplicit(*MI, TII->get(getMovOpc(IsSGPR)));
1650 return true;
1651 }
1652
1653 // S_SUB_* is not commutable, so handle it before the commutability gate.
1654 // Only `x - 0 -> copy x` is valid; `0 - x` is a negation, not a copy.
1655 if (Opc == AMDGPU::S_SUB_I32 || Opc == AMDGPU::S_SUB_U32) {
1656 if (Src1Imm && static_cast<int32_t>(*Src1Imm) == 0) {
1657 // y = sub x, 0 => y = copy x
1658 MI->removeOperand(Src1Idx);
1659 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1660 return true;
1661 }
1662 return false;
1663 }
1664
1665 if (!MI->isCommutable())
1666 return false;
1667
1668 if (Src0Imm && !Src1Imm) {
1669 std::swap(Src0, Src1);
1670 std::swap(Src0Idx, Src1Idx);
1671 std::swap(Src0Imm, Src1Imm);
1672 }
1673
1674 int32_t Src1Val = static_cast<int32_t>(*Src1Imm);
1675 if (Opc == AMDGPU::S_ADD_I32 || Opc == AMDGPU::S_ADD_U32) {
1676 if (Src1Val == 0) {
1677 // y = add x, 0 => y = copy x
1678 MI->removeOperand(Src1Idx);
1679 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1680 return true;
1681 }
1682 return false;
1683 }
1684
1685 if (Opc == AMDGPU::V_OR_B32_e64 ||
1686 Opc == AMDGPU::V_OR_B32_e32 ||
1687 Opc == AMDGPU::S_OR_B32) {
1688 if (Src1Val == 0) {
1689 // y = or x, 0 => y = copy x
1690 MI->removeOperand(Src1Idx);
1691 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1692 } else if (Src1Val == -1) {
1693 // y = or x, -1 => y = v_mov_b32 -1
1694 MI->removeOperand(Src0Idx);
1695 TII->mutateAndCleanupImplicit(
1696 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
1697 } else
1698 return false;
1699
1700 return true;
1701 }
1702
1703 if (Opc == AMDGPU::V_AND_B32_e64 || Opc == AMDGPU::V_AND_B32_e32 ||
1704 Opc == AMDGPU::S_AND_B32) {
1705 if (Src1Val == 0) {
1706 // y = and x, 0 => y = v_mov_b32 0
1707 MI->removeOperand(Src0Idx);
1708 TII->mutateAndCleanupImplicit(
1709 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
1710 } else if (Src1Val == -1) {
1711 // y = and x, -1 => y = copy x
1712 MI->removeOperand(Src1Idx);
1713 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1714 } else
1715 return false;
1716
1717 return true;
1718 }
1719
1720 if (Opc == AMDGPU::V_XOR_B32_e64 || Opc == AMDGPU::V_XOR_B32_e32 ||
1721 Opc == AMDGPU::S_XOR_B32) {
1722 if (Src1Val == 0) {
1723 // y = xor x, 0 => y = copy x
1724 MI->removeOperand(Src1Idx);
1725 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1726 return true;
1727 }
1728 }
1729
1730 return false;
1731}
1732
1733// Try to fold an instruction into a simpler one
1734bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &MI) const {
1735 unsigned Opc = MI.getOpcode();
1736 if (Opc != AMDGPU::V_CNDMASK_B32_e32 && Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1737 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1738 return false;
1739
1740 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1741 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1742 if (!Src1->isIdenticalTo(*Src0)) {
1743 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*Src1);
1744 if (!Src1Imm)
1745 return false;
1746
1747 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*Src0);
1748 if (!Src0Imm || *Src0Imm != *Src1Imm)
1749 return false;
1750 }
1751
1752 int Src1ModIdx =
1753 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1_modifiers);
1754 int Src0ModIdx =
1755 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers);
1756 if ((Src1ModIdx != -1 && MI.getOperand(Src1ModIdx).getImm() != 0) ||
1757 (Src0ModIdx != -1 && MI.getOperand(Src0ModIdx).getImm() != 0))
1758 return false;
1759
1760 LLVM_DEBUG(dbgs() << "Folded " << MI << " into ");
1761 auto &NewDesc =
1762 TII->get(Src0->isReg() ? (unsigned)AMDGPU::COPY : getMovOpc(false));
1763 int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
1764 if (Src2Idx != -1)
1765 MI.removeOperand(Src2Idx);
1766 MI.removeOperand(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1));
1767 if (Src1ModIdx != -1)
1768 MI.removeOperand(Src1ModIdx);
1769 if (Src0ModIdx != -1)
1770 MI.removeOperand(Src0ModIdx);
1771 TII->mutateAndCleanupImplicit(MI, NewDesc);
1772 LLVM_DEBUG(dbgs() << MI);
1773 return true;
1774}
1775
1776bool SIFoldOperandsImpl::tryFoldZeroHighBits(MachineInstr &MI) const {
1777 if (MI.getOpcode() != AMDGPU::V_AND_B32_e64 &&
1778 MI.getOpcode() != AMDGPU::V_AND_B32_e32)
1779 return false;
1780
1781 std::optional<int64_t> Src0Imm =
1782 TII->getImmOrMaterializedImm(MI.getOperand(1));
1783 if (!Src0Imm || *Src0Imm != 0xffff || !MI.getOperand(2).isReg())
1784 return false;
1785
1786 Register Src1 = MI.getOperand(2).getReg();
1787 MachineInstr *SrcDef = MRI->getVRegDef(Src1);
1788 if (!ST->zeroesHigh16BitsOfDest(SrcDef->getOpcode()))
1789 return false;
1790
1791 Register Dst = MI.getOperand(0).getReg();
1792 MRI->replaceRegWith(Dst, Src1);
1793 if (!MI.getOperand(2).isKill())
1794 MRI->clearKillFlags(Src1);
1795 MI.eraseFromParent();
1796 return true;
1797}
1798
1799bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &MI,
1800 const FoldableDef &OpToFold) const {
1801 // We need mutate the operands of new mov instructions to add implicit
1802 // uses of EXEC, but adding them invalidates the use_iterator, so defer
1803 // this.
1804 SmallVector<MachineInstr *, 4> CopiesToReplace;
1806 MachineOperand &Dst = MI.getOperand(0);
1807 bool Changed = false;
1808
1809 if (OpToFold.isImm()) {
1810 for (auto &UseMI :
1811 make_early_inc_range(MRI->use_nodbg_instructions(Dst.getReg()))) {
1812 // Folding the immediate may reveal operations that can be constant
1813 // folded or replaced with a copy. This can happen for example after
1814 // frame indices are lowered to constants or from splitting 64-bit
1815 // constants.
1816 //
1817 // We may also encounter cases where one or both operands are
1818 // immediates materialized into a register, which would ordinarily not
1819 // be folded due to multiple uses or operand constraints.
1820 if (tryConstantFoldOp(&UseMI)) {
1821 LLVM_DEBUG(dbgs() << "Constant folded " << UseMI);
1822 Changed = true;
1823 }
1824 }
1825 }
1826
1828 llvm::make_pointer_range(MRI->use_nodbg_operands(Dst.getReg())));
1829 for (auto *U : UsesToProcess) {
1830 MachineInstr *UseMI = U->getParent();
1831
1832 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*TRI, U->getSubReg());
1833 Changed |= foldOperand(SubOpToFold, UseMI, UseMI->getOperandNo(U), FoldList,
1834 CopiesToReplace);
1835 }
1836
1837 if (CopiesToReplace.empty() && FoldList.empty())
1838 return Changed;
1839
1840 // Make sure we add EXEC uses to any new v_mov instructions created.
1841 for (MachineInstr *Copy : CopiesToReplace)
1842 Copy->addImplicitDefUseOperands(*MF);
1843
1844 SetVector<MachineInstr *> ConstantFoldCandidates;
1845 for (FoldCandidate &Fold : FoldList) {
1846 assert(!Fold.isReg() || Fold.Def.OpToFold);
1847 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1848 Register Reg = Fold.getReg();
1849 const MachineInstr *DefMI = Fold.Def.DefMI;
1850 if (DefMI->readsRegister(AMDGPU::EXEC, TRI) &&
1851 execMayBeModifiedBeforeUse(*MRI, Reg, *DefMI, *Fold.UseMI))
1852 continue;
1853 }
1854 if (updateOperand(Fold)) {
1855 // Clear kill flags.
1856 if (Fold.isReg()) {
1857 assert(Fold.Def.OpToFold && Fold.isReg());
1858 // FIXME: Probably shouldn't bother trying to fold if not an
1859 // SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
1860 // copies.
1861 MRI->clearKillFlags(Fold.getReg());
1862 }
1863 LLVM_DEBUG(dbgs() << "Folded source from " << MI << " into OpNo "
1864 << static_cast<int>(Fold.UseOpNo) << " of "
1865 << *Fold.UseMI);
1866
1867 if (Fold.isImm())
1868 ConstantFoldCandidates.insert(Fold.UseMI);
1869
1870 } else if (Fold.Commuted) {
1871 // Restoring instruction's original operand order if fold has failed.
1872 TII->commuteInstruction(*Fold.UseMI, false);
1873 }
1874 }
1875
1876 for (MachineInstr *MI : ConstantFoldCandidates) {
1877 if (tryConstantFoldOp(MI)) {
1878 LLVM_DEBUG(dbgs() << "Constant folded " << *MI);
1879 Changed = true;
1880 }
1881 }
1882 return true;
1883}
1884
1885/// Fold %agpr = COPY (REG_SEQUENCE x_MOV_B32, ...) into REG_SEQUENCE
1886/// (V_ACCVGPR_WRITE_B32_e64) ... depending on the reg_sequence input values.
1887bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI) const {
1888 // It is very tricky to store a value into an AGPR. v_accvgpr_write_b32 can
1889 // only accept VGPR or inline immediate. Recreate a reg_sequence with its
1890 // initializers right here, so we will rematerialize immediates and avoid
1891 // copies via different reg classes.
1892 const TargetRegisterClass *DefRC =
1893 MRI->getRegClass(CopyMI->getOperand(0).getReg());
1894 if (!TRI->isAGPRClass(DefRC))
1895 return false;
1896
1897 Register UseReg = CopyMI->getOperand(1).getReg();
1898 MachineInstr *RegSeq = MRI->getVRegDef(UseReg);
1899 if (!RegSeq || !RegSeq->isRegSequence())
1900 return false;
1901
1902 const DebugLoc &DL = CopyMI->getDebugLoc();
1903 MachineBasicBlock &MBB = *CopyMI->getParent();
1904
1905 MachineInstrBuilder B(*MBB.getParent(), CopyMI);
1906 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
1907
1908 const TargetRegisterClass *UseRC =
1909 MRI->getRegClass(CopyMI->getOperand(1).getReg());
1910
1911 // Value, subregindex for new REG_SEQUENCE
1913
1914 unsigned NumRegSeqOperands = RegSeq->getNumOperands();
1915 unsigned NumFoldable = 0;
1916
1917 for (unsigned I = 1; I != NumRegSeqOperands; I += 2) {
1918 MachineOperand &RegOp = RegSeq->getOperand(I);
1919 unsigned SubRegIdx = RegSeq->getOperand(I + 1).getImm();
1920
1921 if (RegOp.getSubReg()) {
1922 // TODO: Handle subregister compose
1923 NewDefs.emplace_back(&RegOp, SubRegIdx);
1924 continue;
1925 }
1926
1927 MachineOperand *Lookup = lookUpCopyChain(*TII, *MRI, RegOp.getReg());
1928 if (!Lookup)
1929 Lookup = &RegOp;
1930
1931 if (Lookup->isImm()) {
1932 // Check if this is an agpr_32 subregister.
1933 const TargetRegisterClass *DestSuperRC = TRI->getMatchingSuperRegClass(
1934 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
1935 if (DestSuperRC &&
1936 TII->isInlineConstant(*Lookup, AMDGPU::OPERAND_REG_INLINE_C_INT32)) {
1937 ++NumFoldable;
1938 NewDefs.emplace_back(Lookup, SubRegIdx);
1939 continue;
1940 }
1941 }
1942
1943 const TargetRegisterClass *InputRC =
1944 Lookup->isReg() ? MRI->getRegClass(Lookup->getReg())
1945 : MRI->getRegClass(RegOp.getReg());
1946
1947 // TODO: Account for Lookup->getSubReg()
1948
1949 // If we can't find a matching super class, this is an SGPR->AGPR or
1950 // VGPR->AGPR subreg copy (or something constant-like we have to materialize
1951 // in the AGPR). We can't directly copy from SGPR to AGPR on gfx908, so we
1952 // want to rewrite to copy to an intermediate VGPR class.
1953 const TargetRegisterClass *MatchRC =
1954 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
1955 if (!MatchRC) {
1956 ++NumFoldable;
1957 NewDefs.emplace_back(&RegOp, SubRegIdx);
1958 continue;
1959 }
1960
1961 NewDefs.emplace_back(&RegOp, SubRegIdx);
1962 }
1963
1964 // Do not clone a reg_sequence and merely change the result register class.
1965 if (NumFoldable == 0)
1966 return false;
1967
1968 CopyMI->setDesc(TII->get(AMDGPU::REG_SEQUENCE));
1969 for (unsigned I = CopyMI->getNumOperands() - 1; I > 0; --I)
1970 CopyMI->removeOperand(I);
1971
1972 for (auto [Def, DestSubIdx] : NewDefs) {
1973 if (!Def->isReg()) {
1974 // TODO: Should we use single write for each repeated value like in
1975 // register case?
1976 Register Tmp = MRI->createVirtualRegister(&AMDGPU::AGPR_32RegClass);
1977 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
1978 .add(*Def);
1979 B.addReg(Tmp);
1980 } else {
1981 TargetInstrInfo::RegSubRegPair Src = getRegSubRegPair(*Def);
1982 Def->setIsKill(false);
1983
1984 Register &VGPRCopy = VGPRCopies[Src];
1985 if (!VGPRCopy) {
1986 const TargetRegisterClass *VGPRUseSubRC =
1987 TRI->getSubRegisterClass(UseRC, DestSubIdx);
1988
1989 // We cannot build a reg_sequence out of the same registers, they
1990 // must be copied. Better do it here before copyPhysReg() created
1991 // several reads to do the AGPR->VGPR->AGPR copy.
1992
1993 // Direct copy from SGPR to AGPR is not possible on gfx908. To avoid
1994 // creation of exploded copies SGPR->VGPR->AGPR in the copyPhysReg()
1995 // later, create a copy here and track if we already have such a copy.
1996 const TargetRegisterClass *SubRC =
1997 TRI->getSubRegisterClass(MRI->getRegClass(Src.Reg), Src.SubReg);
1998 if (!VGPRUseSubRC->hasSubClassEq(SubRC)) {
1999 // TODO: Try to reconstrain class
2000 VGPRCopy = MRI->createVirtualRegister(VGPRUseSubRC);
2001 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::COPY), VGPRCopy).add(*Def);
2002 B.addReg(VGPRCopy);
2003 } else {
2004 // If it is already a VGPR, do not copy the register.
2005 B.add(*Def);
2006 }
2007 } else {
2008 B.addReg(VGPRCopy);
2009 }
2010 }
2011
2012 B.addImm(DestSubIdx);
2013 }
2014
2015 LLVM_DEBUG(dbgs() << "Folded " << *CopyMI);
2016 return true;
2017}
2018
2019bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2020 MachineInstr &MI, MachineOperand *&CurrentKnownM0Val) const {
2021 Register DstReg = MI.getOperand(0).getReg();
2022 // Specially track simple redefs of m0 to the same value in a block, so we
2023 // can erase the later ones.
2024 if (DstReg == AMDGPU::M0) {
2025 MachineOperand &NewM0Val = MI.getOperand(1);
2026 if (CurrentKnownM0Val && CurrentKnownM0Val->isIdenticalTo(NewM0Val)) {
2027 MI.eraseFromParent();
2028 return true;
2029 }
2030
2031 // We aren't tracking other physical registers
2032 CurrentKnownM0Val = (NewM0Val.isReg() && NewM0Val.getReg().isPhysical())
2033 ? nullptr
2034 : &NewM0Val;
2035 return false;
2036 }
2037
2038 MachineOperand *OpToFoldPtr;
2039 if (MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2040 // Folding when any src_modifiers are non-zero is unsupported
2041 if (TII->hasAnyModifiersSet(MI))
2042 return false;
2043 OpToFoldPtr = &MI.getOperand(2);
2044 } else
2045 OpToFoldPtr = &MI.getOperand(1);
2046 MachineOperand &OpToFold = *OpToFoldPtr;
2047 bool FoldingImm = OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
2048
2049 // FIXME: We could also be folding things like TargetIndexes.
2050 if (!FoldingImm && !OpToFold.isReg())
2051 return false;
2052
2053 // Fold virtual registers and constant physical registers.
2054 if (OpToFold.isReg() && OpToFold.getReg().isPhysical() &&
2055 !TRI->isConstantPhysReg(OpToFold.getReg()))
2056 return false;
2057
2058 // Prevent folding operands backwards in the function. For example,
2059 // the COPY opcode must not be replaced by 1 in this example:
2060 //
2061 // %3 = COPY %vgpr0; VGPR_32:%3
2062 // ...
2063 // %vgpr0 = V_MOV_B32_e32 1, implicit %exec
2064 if (!DstReg.isVirtual())
2065 return false;
2066
2067 const TargetRegisterClass *DstRC =
2068 MRI->getRegClass(MI.getOperand(0).getReg());
2069
2070 // True16: Fix malformed 16-bit sgpr COPY produced by peephole-opt
2071 // Can remove this code if proper 16-bit SGPRs are implemented
2072 // Example: Pre-peephole-opt
2073 // %29:sgpr_lo16 = COPY %16.lo16:sreg_32
2074 // %32:sreg_32 = COPY %29:sgpr_lo16
2075 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2076 // Post-peephole-opt and DCE
2077 // %32:sreg_32 = COPY %16.lo16:sreg_32
2078 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2079 // After this transform
2080 // %32:sreg_32 = COPY %16:sreg_32
2081 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2082 // After the fold operands pass
2083 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %16:sreg_32
2084 if (MI.getOpcode() == AMDGPU::COPY && OpToFold.isReg() &&
2085 OpToFold.getSubReg()) {
2086 if (DstRC == &AMDGPU::SReg_32RegClass &&
2087 DstRC == MRI->getRegClass(OpToFold.getReg())) {
2088 assert(OpToFold.getSubReg() == AMDGPU::lo16);
2089 OpToFold.setSubReg(0);
2090 }
2091 }
2092
2093 // Fold copy to AGPR through reg_sequence
2094 // TODO: Handle with subregister extract
2095 if (OpToFold.isReg() && MI.isCopy() && !MI.getOperand(1).getSubReg()) {
2096 if (foldCopyToAGPRRegSequence(&MI))
2097 return true;
2098 }
2099
2100 FoldableDef Def(OpToFold, DstRC);
2101 bool Changed = foldInstOperand(MI, Def);
2102
2103 // If we managed to fold all uses of this copy then we might as well
2104 // delete it now.
2105 // The only reason we need to follow chains of copies here is that
2106 // tryFoldRegSequence looks forward through copies before folding a
2107 // REG_SEQUENCE into its eventual users.
2108 auto *InstToErase = &MI;
2109 while (MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2110 auto &SrcOp = InstToErase->getOperand(1);
2111 auto SrcReg = SrcOp.isReg() ? SrcOp.getReg() : Register();
2112 InstToErase->eraseFromParent();
2113 Changed = true;
2114 InstToErase = nullptr;
2115 if (!SrcReg || SrcReg.isPhysical())
2116 break;
2117 InstToErase = MRI->getVRegDef(SrcReg);
2118 if (!InstToErase || !TII->isFoldableCopy(*InstToErase))
2119 break;
2120 }
2121
2122 if (InstToErase && InstToErase->isRegSequence() &&
2123 MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2124 InstToErase->eraseFromParent();
2125 Changed = true;
2126 }
2127
2128 if (Changed)
2129 return true;
2130
2131 // Run this after foldInstOperand to avoid turning scalar additions into
2132 // vector additions when the result scalar result could just be folded into
2133 // the user(s).
2134 return OpToFold.isReg() &&
2135 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.getReg(), MI);
2136}
2137
2138// Clamp patterns are canonically selected to v_max_* instructions, so only
2139// handle them.
2140const MachineOperand *
2141SIFoldOperandsImpl::isClamp(const MachineInstr &MI) const {
2142 unsigned Op = MI.getOpcode();
2143 switch (Op) {
2144 case AMDGPU::V_MAX_F32_e64:
2145 case AMDGPU::V_MAX_F16_e64:
2146 case AMDGPU::V_MAX_F16_t16_e64:
2147 case AMDGPU::V_MAX_F16_fake16_e64:
2148 case AMDGPU::V_MAX_F64_e64:
2149 case AMDGPU::V_MAX_NUM_F64_e64:
2150 case AMDGPU::V_PK_MAX_F16:
2151 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2152 case AMDGPU::V_PK_MAX_NUM_BF16: {
2153 if (MI.mayRaiseFPException())
2154 return nullptr;
2155
2156 if (!TII->getNamedOperand(MI, AMDGPU::OpName::clamp)->getImm())
2157 return nullptr;
2158
2159 // Make sure sources are identical.
2160 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2161 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2162 if (!Src0->isReg() || !Src1->isReg() ||
2163 Src0->getReg() != Src1->getReg() ||
2164 Src0->getSubReg() != Src1->getSubReg() ||
2165 Src0->getSubReg() != AMDGPU::NoSubRegister)
2166 return nullptr;
2167
2168 // Can't fold up if we have modifiers.
2169 if (TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2170 return nullptr;
2171
2172 unsigned Src0Mods
2173 = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)->getImm();
2174 unsigned Src1Mods
2175 = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers)->getImm();
2176
2177 // Having a 0 op_sel_hi would require swizzling the output in the source
2178 // instruction, which we can't do.
2179 unsigned UnsetMods =
2180 (Op == AMDGPU::V_PK_MAX_F16 || Op == AMDGPU::V_PK_MAX_NUM_BF16)
2182 : 0u;
2183 if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
2184 return nullptr;
2185 return Src0;
2186 }
2187 default:
2188 return nullptr;
2189 }
2190}
2191
2192// FIXME: Clamp for v_mad_mixhi_f16 handled during isel.
2193bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &MI) {
2194 const MachineOperand *ClampSrc = isClamp(MI);
2195 if (!ClampSrc || !MRI->hasOneNonDBGUser(ClampSrc->getReg()))
2196 return false;
2197
2198 if (!ClampSrc->getReg().isVirtual())
2199 return false;
2200
2201 // Look through COPY. COPY only observed with True16.
2202 Register DefSrcReg = TRI->lookThruCopyLike(ClampSrc->getReg(), MRI);
2203 MachineInstr *Def =
2204 MRI->getVRegDef(DefSrcReg.isVirtual() ? DefSrcReg : ClampSrc->getReg());
2205
2206 // The type of clamp must be compatible.
2207 if (!SIInstrInfo::hasSameClamp(*Def, MI))
2208 return false;
2209
2210 if (Def->mayRaiseFPException())
2211 return false;
2212
2213 MachineOperand *DefClamp = TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2214 if (!DefClamp)
2215 return false;
2216
2217 LLVM_DEBUG(dbgs() << "Folding clamp " << *DefClamp << " into " << *Def);
2218
2219 // Clamp is applied after omod, so it is OK if omod is set.
2220 DefClamp->setImm(1);
2221
2222 Register DefReg = Def->getOperand(0).getReg();
2223 Register MIDstReg = MI.getOperand(0).getReg();
2224 if (TRI->isSGPRReg(*MRI, DefReg)) {
2225 // Pseudo scalar instructions have a SGPR for dst and clamp is a v_max*
2226 // instruction with a VGPR dst.
2227 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY),
2228 MIDstReg)
2229 .addReg(DefReg);
2230 } else {
2231 MRI->replaceRegWith(MIDstReg, DefReg);
2232 }
2233 MI.eraseFromParent();
2234
2235 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2236 // instruction, so we might as well convert it to the more flexible VOP3-only
2237 // mad/fma form.
2238 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2239 Def->eraseFromParent();
2240
2241 return true;
2242}
2243
2244static int getOModValue(unsigned Opc, int64_t Val) {
2245 switch (Opc) {
2246 case AMDGPU::V_MUL_F64_e64:
2247 case AMDGPU::V_MUL_F64_pseudo_e64: {
2248 switch (Val) {
2249 case 0x3fe0000000000000: // 0.5
2250 return SIOutMods::DIV2;
2251 case 0x4000000000000000: // 2.0
2252 return SIOutMods::MUL2;
2253 case 0x4010000000000000: // 4.0
2254 return SIOutMods::MUL4;
2255 default:
2256 return SIOutMods::NONE;
2257 }
2258 }
2259 case AMDGPU::V_MUL_F32_e64: {
2260 switch (static_cast<uint32_t>(Val)) {
2261 case 0x3f000000: // 0.5
2262 return SIOutMods::DIV2;
2263 case 0x40000000: // 2.0
2264 return SIOutMods::MUL2;
2265 case 0x40800000: // 4.0
2266 return SIOutMods::MUL4;
2267 default:
2268 return SIOutMods::NONE;
2269 }
2270 }
2271 case AMDGPU::V_MUL_F16_e64:
2272 case AMDGPU::V_MUL_F16_t16_e64:
2273 case AMDGPU::V_MUL_F16_fake16_e64: {
2274 switch (static_cast<uint16_t>(Val)) {
2275 case 0x3800: // 0.5
2276 return SIOutMods::DIV2;
2277 case 0x4000: // 2.0
2278 return SIOutMods::MUL2;
2279 case 0x4400: // 4.0
2280 return SIOutMods::MUL4;
2281 default:
2282 return SIOutMods::NONE;
2283 }
2284 }
2285 default:
2286 llvm_unreachable("invalid mul opcode");
2287 }
2288}
2289
2290// FIXME: Does this really not support denormals with f16?
2291// FIXME: Does this need to check IEEE mode bit? SNaNs are generally not
2292// handled, so will anything other than that break?
2293std::pair<const MachineOperand *, int>
2294SIFoldOperandsImpl::isOMod(const MachineInstr &MI) const {
2295 unsigned Op = MI.getOpcode();
2296 switch (Op) {
2297 case AMDGPU::V_MUL_F64_e64:
2298 case AMDGPU::V_MUL_F64_pseudo_e64:
2299 case AMDGPU::V_MUL_F32_e64:
2300 case AMDGPU::V_MUL_F16_t16_e64:
2301 case AMDGPU::V_MUL_F16_fake16_e64:
2302 case AMDGPU::V_MUL_F16_e64: {
2303 // If output denormals are enabled, omod is ignored.
2304 if ((Op == AMDGPU::V_MUL_F32_e64 &&
2306 ((Op == AMDGPU::V_MUL_F64_e64 || Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2307 Op == AMDGPU::V_MUL_F16_e64 || Op == AMDGPU::V_MUL_F16_t16_e64 ||
2308 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2311 MI.mayRaiseFPException())
2312 return std::pair(nullptr, SIOutMods::NONE);
2313
2314 const MachineOperand *RegOp = nullptr;
2315 const MachineOperand *ImmOp = nullptr;
2316 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2317 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2318 if (Src0->isImm()) {
2319 ImmOp = Src0;
2320 RegOp = Src1;
2321 } else if (Src1->isImm()) {
2322 ImmOp = Src1;
2323 RegOp = Src0;
2324 } else
2325 return std::pair(nullptr, SIOutMods::NONE);
2326
2327 int OMod = getOModValue(Op, ImmOp->getImm());
2328 if (OMod == SIOutMods::NONE ||
2329 TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
2330 TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) ||
2331 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2332 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2333 return std::pair(nullptr, SIOutMods::NONE);
2334
2335 return std::pair(RegOp, OMod);
2336 }
2337 case AMDGPU::V_ADD_F64_e64:
2338 case AMDGPU::V_ADD_F64_pseudo_e64:
2339 case AMDGPU::V_ADD_F32_e64:
2340 case AMDGPU::V_ADD_F16_e64:
2341 case AMDGPU::V_ADD_F16_t16_e64:
2342 case AMDGPU::V_ADD_F16_fake16_e64: {
2343 // If output denormals are enabled, omod is ignored.
2344 if ((Op == AMDGPU::V_ADD_F32_e64 &&
2346 ((Op == AMDGPU::V_ADD_F64_e64 || Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2347 Op == AMDGPU::V_ADD_F16_e64 || Op == AMDGPU::V_ADD_F16_t16_e64 ||
2348 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2350 return std::pair(nullptr, SIOutMods::NONE);
2351
2352 // Look through the DAGCombiner canonicalization fmul x, 2 -> fadd x, x
2353 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2354 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2355
2356 if (Src0->isReg() && Src1->isReg() && Src0->getReg() == Src1->getReg() &&
2357 Src0->getSubReg() == Src1->getSubReg() &&
2358 !TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) &&
2359 !TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) &&
2360 !TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) &&
2361 !TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2362 return std::pair(Src0, SIOutMods::MUL2);
2363
2364 return std::pair(nullptr, SIOutMods::NONE);
2365 }
2366 default:
2367 return std::pair(nullptr, SIOutMods::NONE);
2368 }
2369}
2370
2371// FIXME: Does this need to check IEEE bit on function?
2372bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &MI) {
2373 const MachineOperand *RegOp;
2374 int OMod;
2375 std::tie(RegOp, OMod) = isOMod(MI);
2376 if (OMod == SIOutMods::NONE || !RegOp->isReg() ||
2377 RegOp->getSubReg() != AMDGPU::NoSubRegister ||
2378 !MRI->hasOneNonDBGUser(RegOp->getReg()))
2379 return false;
2380
2381 MachineInstr *Def = MRI->getVRegDef(RegOp->getReg());
2382 MachineOperand *DefOMod = TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2383 if (!DefOMod || DefOMod->getImm() != SIOutMods::NONE)
2384 return false;
2385
2386 if (Def->mayRaiseFPException())
2387 return false;
2388
2389 // Clamp is applied after omod. If the source already has clamp set, don't
2390 // fold it.
2391 if (TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2392 return false;
2393
2394 LLVM_DEBUG(dbgs() << "Folding omod " << MI << " into " << *Def);
2395
2396 DefOMod->setImm(OMod);
2397 MRI->replaceRegWith(MI.getOperand(0).getReg(), Def->getOperand(0).getReg());
2398 // Kill flags can be wrong if we replaced a def inside a loop with a def
2399 // outside the loop.
2400 MRI->clearKillFlags(Def->getOperand(0).getReg());
2401 MI.eraseFromParent();
2402
2403 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2404 // instruction, so we might as well convert it to the more flexible VOP3-only
2405 // mad/fma form.
2406 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2407 Def->eraseFromParent();
2408
2409 return true;
2410}
2411
2412// Try to fold a reg_sequence with vgpr output and agpr inputs into an
2413// instruction which can take an agpr. So far that means a store.
2414bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &MI) {
2415 assert(MI.isRegSequence());
2416 auto Reg = MI.getOperand(0).getReg();
2417
2418 if (!ST->hasGFX90AInsts() || !TRI->isVGPR(*MRI, Reg) ||
2419 !MRI->hasOneNonDBGUse(Reg))
2420 return false;
2421
2423 if (!getRegSeqInit(Defs, Reg))
2424 return false;
2425
2426 for (auto &[Op, SubIdx] : Defs) {
2427 if (!Op->isReg())
2428 return false;
2429 if (TRI->isAGPR(*MRI, Op->getReg()))
2430 continue;
2431 // Maybe this is a COPY from AREG
2432 const MachineInstr *SubDef = MRI->getVRegDef(Op->getReg());
2433 if (!SubDef || !SubDef->isCopy() || SubDef->getOperand(1).getSubReg())
2434 return false;
2435 if (!TRI->isAGPR(*MRI, SubDef->getOperand(1).getReg()))
2436 return false;
2437 }
2438
2439 MachineOperand *Op = &*MRI->use_nodbg_begin(Reg);
2440 MachineInstr *UseMI = Op->getParent();
2441 while (UseMI->isCopy() && !Op->getSubReg()) {
2442 Reg = UseMI->getOperand(0).getReg();
2443 if (!TRI->isVGPR(*MRI, Reg) || !MRI->hasOneNonDBGUse(Reg))
2444 return false;
2445 Op = &*MRI->use_nodbg_begin(Reg);
2446 UseMI = Op->getParent();
2447 }
2448
2449 if (Op->getSubReg())
2450 return false;
2451
2452 unsigned OpIdx = Op - &UseMI->getOperand(0);
2453 const MCInstrDesc &InstDesc = UseMI->getDesc();
2454 const TargetRegisterClass *OpRC = TII->getRegClass(InstDesc, OpIdx);
2455 if (!OpRC || !TRI->isVectorSuperClass(OpRC))
2456 return false;
2457
2458 const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg));
2459 auto Dst = MRI->createVirtualRegister(NewDstRC);
2460 auto RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2461 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2462
2463 for (auto &[Def, SubIdx] : Defs) {
2464 Def->setIsKill(false);
2465 if (TRI->isAGPR(*MRI, Def->getReg())) {
2466 RS.add(*Def);
2467 } else { // This is a copy
2468 MachineInstr *SubDef = MRI->getVRegDef(Def->getReg());
2469 SubDef->getOperand(1).setIsKill(false);
2470 RS.addReg(SubDef->getOperand(1).getReg(), {}, Def->getSubReg());
2471 }
2472 RS.addImm(SubIdx);
2473 }
2474
2475 Op->setReg(Dst);
2476 if (!TII->isOperandLegal(*UseMI, OpIdx, Op)) {
2477 Op->setReg(Reg);
2478 RS->eraseFromParent();
2479 return false;
2480 }
2481
2482 LLVM_DEBUG(dbgs() << "Folded " << *RS << " into " << *UseMI);
2483
2484 // Erase the REG_SEQUENCE eagerly, unless we followed a chain of COPY users,
2485 // in which case we can erase them all later in runOnMachineFunction.
2486 if (MRI->use_nodbg_empty(MI.getOperand(0).getReg()))
2487 MI.eraseFromParent();
2488 return true;
2489}
2490
2491/// Checks whether \p Copy is a AGPR -> VGPR copy. Returns `true` on success and
2492/// stores the AGPR register in \p OutReg and the subreg in \p OutSubReg
2493static bool isAGPRCopy(const SIRegisterInfo &TRI,
2494 const MachineRegisterInfo &MRI, const MachineInstr &Copy,
2495 Register &OutReg, unsigned &OutSubReg) {
2496 assert(Copy.isCopy());
2497
2498 const MachineOperand &CopySrc = Copy.getOperand(1);
2499 Register CopySrcReg = CopySrc.getReg();
2500 if (!CopySrcReg.isVirtual())
2501 return false;
2502
2503 // Common case: copy from AGPR directly, e.g.
2504 // %1:vgpr_32 = COPY %0:agpr_32
2505 if (TRI.isAGPR(MRI, CopySrcReg)) {
2506 OutReg = CopySrcReg;
2507 OutSubReg = CopySrc.getSubReg();
2508 return true;
2509 }
2510
2511 // Sometimes it can also involve two copies, e.g.
2512 // %1:vgpr_256 = COPY %0:agpr_256
2513 // %2:vgpr_32 = COPY %1:vgpr_256.sub0
2514 const MachineInstr *CopySrcDef = MRI.getVRegDef(CopySrcReg);
2515 if (!CopySrcDef || !CopySrcDef->isCopy())
2516 return false;
2517
2518 const MachineOperand &OtherCopySrc = CopySrcDef->getOperand(1);
2519 Register OtherCopySrcReg = OtherCopySrc.getReg();
2520 if (!OtherCopySrcReg.isVirtual() ||
2521 CopySrcDef->getOperand(0).getSubReg() != AMDGPU::NoSubRegister ||
2522 OtherCopySrc.getSubReg() != AMDGPU::NoSubRegister ||
2523 !TRI.isAGPR(MRI, OtherCopySrcReg))
2524 return false;
2525
2526 OutReg = OtherCopySrcReg;
2527 OutSubReg = CopySrc.getSubReg();
2528 return true;
2529}
2530
2531// Try to hoist an AGPR to VGPR copy across a PHI.
2532// This should allow folding of an AGPR into a consumer which may support it.
2533//
2534// Example 1: LCSSA PHI
2535// loop:
2536// %1:vreg = COPY %0:areg
2537// exit:
2538// %2:vreg = PHI %1:vreg, %loop
2539// =>
2540// loop:
2541// exit:
2542// %1:areg = PHI %0:areg, %loop
2543// %2:vreg = COPY %1:areg
2544//
2545// Example 2: PHI with multiple incoming values:
2546// entry:
2547// %1:vreg = GLOBAL_LOAD(..)
2548// loop:
2549// %2:vreg = PHI %1:vreg, %entry, %5:vreg, %loop
2550// %3:areg = COPY %2:vreg
2551// %4:areg = (instr using %3:areg)
2552// %5:vreg = COPY %4:areg
2553// =>
2554// entry:
2555// %1:vreg = GLOBAL_LOAD(..)
2556// %2:areg = COPY %1:vreg
2557// loop:
2558// %3:areg = PHI %2:areg, %entry, %X:areg,
2559// %4:areg = (instr using %3:areg)
2560bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &PHI) {
2561 assert(PHI.isPHI());
2562
2563 Register PhiOut = PHI.getOperand(0).getReg();
2564 if (!TRI->isVGPR(*MRI, PhiOut))
2565 return false;
2566
2567 // Iterate once over all incoming values of the PHI to check if this PHI is
2568 // eligible, and determine the exact AGPR RC we'll target.
2569 const TargetRegisterClass *ARC = nullptr;
2570 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2571 MachineOperand &MO = PHI.getOperand(K);
2572 MachineInstr *Copy = MRI->getVRegDef(MO.getReg());
2573 if (!Copy || !Copy->isCopy())
2574 continue;
2575
2576 Register AGPRSrc;
2577 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2578 if (!isAGPRCopy(*TRI, *MRI, *Copy, AGPRSrc, AGPRRegMask))
2579 continue;
2580
2581 const TargetRegisterClass *CopyInRC = MRI->getRegClass(AGPRSrc);
2582 if (const auto *SubRC = TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2583 CopyInRC = SubRC;
2584
2585 if (ARC && !ARC->hasSubClassEq(CopyInRC))
2586 return false;
2587 ARC = CopyInRC;
2588 }
2589
2590 if (!ARC)
2591 return false;
2592
2593 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2594
2595 // Rewrite the PHI's incoming values to ARC.
2596 LLVM_DEBUG(dbgs() << "Folding AGPR copies into: " << PHI);
2597 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2598 MachineOperand &MO = PHI.getOperand(K);
2599 Register Reg = MO.getReg();
2600
2602 MachineBasicBlock *InsertMBB = nullptr;
2603
2604 // Look at the def of Reg, ignoring all copies.
2605 unsigned CopyOpc = AMDGPU::COPY;
2606 if (MachineInstr *Def = MRI->getVRegDef(Reg)) {
2607
2608 // Look at pre-existing COPY instructions from ARC: Steal the operand. If
2609 // the copy was single-use, it will be removed by DCE later.
2610 if (Def->isCopy()) {
2611 Register AGPRSrc;
2612 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2613 if (isAGPRCopy(*TRI, *MRI, *Def, AGPRSrc, AGPRSubReg)) {
2614 MO.setReg(AGPRSrc);
2615 MO.setSubReg(AGPRSubReg);
2616 continue;
2617 }
2618
2619 // If this is a multi-use SGPR -> VGPR copy, use V_ACCVGPR_WRITE on
2620 // GFX908 directly instead of a COPY. Otherwise, SIFoldOperand may try
2621 // to fold the sgpr -> vgpr -> agpr copy into a sgpr -> agpr copy which
2622 // is unlikely to be profitable.
2623 //
2624 // Note that V_ACCVGPR_WRITE is only used for AGPR_32.
2625 MachineOperand &CopyIn = Def->getOperand(1);
2626 if (IsAGPR32 && !ST->hasGFX90AInsts() && !MRI->hasOneNonDBGUse(Reg) &&
2627 TRI->isSGPRReg(*MRI, CopyIn.getReg()))
2628 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2629 }
2630
2631 InsertMBB = Def->getParent();
2632 InsertPt = InsertMBB->SkipPHIsLabelsAndDebug(++Def->getIterator());
2633 } else {
2634 InsertMBB = PHI.getOperand(MO.getOperandNo() + 1).getMBB();
2635 InsertPt = InsertMBB->getFirstTerminator();
2636 }
2637
2638 Register NewReg = MRI->createVirtualRegister(ARC);
2639 MachineInstr *MI = BuildMI(*InsertMBB, InsertPt, PHI.getDebugLoc(),
2640 TII->get(CopyOpc), NewReg)
2641 .addReg(Reg);
2642 MO.setReg(NewReg);
2643
2644 (void)MI;
2645 LLVM_DEBUG(dbgs() << " Created COPY: " << *MI);
2646 }
2647
2648 // Replace the PHI's result with a new register.
2649 Register NewReg = MRI->createVirtualRegister(ARC);
2650 PHI.getOperand(0).setReg(NewReg);
2651
2652 // COPY that new register back to the original PhiOut register. This COPY will
2653 // usually be folded out later.
2654 MachineBasicBlock *MBB = PHI.getParent();
2655 BuildMI(*MBB, MBB->getFirstNonPHI(), PHI.getDebugLoc(),
2656 TII->get(AMDGPU::COPY), PhiOut)
2657 .addReg(NewReg);
2658
2659 LLVM_DEBUG(dbgs() << " Done: Folded " << PHI);
2660 return true;
2661}
2662
2663// Attempt to convert VGPR load to an AGPR load.
2664bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &MI) {
2665 assert(MI.mayLoad());
2666 if (!ST->hasGFX90AInsts() || MI.getNumExplicitDefs() != 1)
2667 return false;
2668
2669 MachineOperand &Def = MI.getOperand(0);
2670 if (!Def.isDef())
2671 return false;
2672
2673 Register DefReg = Def.getReg();
2674
2675 if (DefReg.isPhysical() || !TRI->isVGPR(*MRI, DefReg))
2676 return false;
2677
2680 SmallVector<Register, 8> MoveRegs;
2681
2682 if (Users.empty())
2683 return false;
2684
2685 // Check that all uses a copy to an agpr or a reg_sequence producing an agpr.
2686 while (!Users.empty()) {
2687 const MachineInstr *I = Users.pop_back_val();
2688 if (!I->isCopy() && !I->isRegSequence())
2689 return false;
2690 Register DstReg = I->getOperand(0).getReg();
2691 // Physical registers may have more than one instruction definitions
2692 if (DstReg.isPhysical())
2693 return false;
2694 if (TRI->isAGPR(*MRI, DstReg))
2695 continue;
2696 MoveRegs.push_back(DstReg);
2697 for (const MachineInstr &U : MRI->use_nodbg_instructions(DstReg))
2698 Users.push_back(&U);
2699 }
2700
2701 const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
2702 MRI->setRegClass(DefReg, TRI->getEquivalentAGPRClass(RC));
2703 if (!TII->isOperandLegal(MI, 0, &Def)) {
2704 MRI->setRegClass(DefReg, RC);
2705 return false;
2706 }
2707
2708 while (!MoveRegs.empty()) {
2709 Register Reg = MoveRegs.pop_back_val();
2710 MRI->setRegClass(Reg, TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)));
2711 }
2712
2713 LLVM_DEBUG(dbgs() << "Folded " << MI);
2714
2715 return true;
2716}
2717
2718// tryFoldPhiAGPR will aggressively try to create AGPR PHIs.
2719// For GFX90A and later, this is pretty much always a good thing, but for GFX908
2720// there's cases where it can create a lot more AGPR-AGPR copies, which are
2721// expensive on this architecture due to the lack of V_ACCVGPR_MOV.
2722//
2723// This function looks at all AGPR PHIs in a basic block and collects their
2724// operands. Then, it checks for register that are used more than once across
2725// all PHIs and caches them in a VGPR. This prevents ExpandPostRAPseudo from
2726// having to create one VGPR temporary per use, which can get very messy if
2727// these PHIs come from a broken-up large PHI (e.g. 32 AGPR phis, one per vector
2728// element).
2729//
2730// Example
2731// a:
2732// %in:agpr_256 = COPY %foo:vgpr_256
2733// c:
2734// %x:agpr_32 = ..
2735// b:
2736// %0:areg = PHI %in.sub0:agpr_32, %a, %x, %c
2737// %1:areg = PHI %in.sub0:agpr_32, %a, %y, %c
2738// %2:areg = PHI %in.sub0:agpr_32, %a, %z, %c
2739// =>
2740// a:
2741// %in:agpr_256 = COPY %foo:vgpr_256
2742// %tmp:vgpr_32 = V_ACCVGPR_READ_B32_e64 %in.sub0:agpr_32
2743// %tmp_agpr:agpr_32 = COPY %tmp
2744// c:
2745// %x:agpr_32 = ..
2746// b:
2747// %0:areg = PHI %tmp_agpr, %a, %x, %c
2748// %1:areg = PHI %tmp_agpr, %a, %y, %c
2749// %2:areg = PHI %tmp_agpr, %a, %z, %c
2750bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &MBB) {
2751 // This is only really needed on GFX908 where AGPR-AGPR copies are
2752 // unreasonably difficult.
2753 if (ST->hasGFX90AInsts())
2754 return false;
2755
2756 // Look at all AGPR Phis and collect the register + subregister used.
2757 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
2758 RegToMO;
2759
2760 for (auto &MI : MBB) {
2761 if (!MI.isPHI())
2762 break;
2763
2764 if (!TRI->isAGPR(*MRI, MI.getOperand(0).getReg()))
2765 continue;
2766
2767 for (unsigned K = 1; K < MI.getNumOperands(); K += 2) {
2768 MachineOperand &PhiMO = MI.getOperand(K);
2769 if (!PhiMO.getSubReg())
2770 continue;
2771 RegToMO[{PhiMO.getReg(), PhiMO.getSubReg()}].push_back(&PhiMO);
2772 }
2773 }
2774
2775 // For all (Reg, SubReg) pair that are used more than once, cache the value in
2776 // a VGPR.
2777 bool Changed = false;
2778 for (const auto &[Entry, MOs] : RegToMO) {
2779 if (MOs.size() == 1)
2780 continue;
2781
2782 const auto [Reg, SubReg] = Entry;
2783 MachineInstr *Def = MRI->getVRegDef(Reg);
2784 MachineBasicBlock *DefMBB = Def->getParent();
2785
2786 // Create a copy in a VGPR using V_ACCVGPR_READ_B32_e64 so it's not folded
2787 // out.
2788 const TargetRegisterClass *ARC = getRegOpRC(*MRI, *TRI, *MOs.front());
2789 Register TempVGPR =
2790 MRI->createVirtualRegister(TRI->getEquivalentVGPRClass(ARC));
2791 MachineInstr *VGPRCopy =
2792 BuildMI(*DefMBB, ++Def->getIterator(), Def->getDebugLoc(),
2793 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
2794 .addReg(Reg, /* flags */ {}, SubReg);
2795
2796 // Copy back to an AGPR and use that instead of the AGPR subreg in all MOs.
2797 Register TempAGPR = MRI->createVirtualRegister(ARC);
2798 BuildMI(*DefMBB, ++VGPRCopy->getIterator(), Def->getDebugLoc(),
2799 TII->get(AMDGPU::COPY), TempAGPR)
2800 .addReg(TempVGPR);
2801
2802 LLVM_DEBUG(dbgs() << "Caching AGPR into VGPR: " << *VGPRCopy);
2803 for (MachineOperand *MO : MOs) {
2804 MO->setReg(TempAGPR);
2805 MO->setSubReg(AMDGPU::NoSubRegister);
2806 LLVM_DEBUG(dbgs() << " Changed PHI Operand: " << *MO << "\n");
2807 }
2808
2809 Changed = true;
2810 }
2811
2812 return Changed;
2813}
2814
2815bool SIFoldOperandsImpl::run(MachineFunction &MF) {
2816 this->MF = &MF;
2817 MRI = &MF.getRegInfo();
2818 ST = &MF.getSubtarget<GCNSubtarget>();
2819 TII = ST->getInstrInfo();
2820 TRI = &TII->getRegisterInfo();
2821 MFI = MF.getInfo<SIMachineFunctionInfo>();
2822
2823 // omod is ignored by hardware if IEEE bit is enabled. omod also does not
2824 // correctly handle signed zeros.
2825 //
2826 // FIXME: Also need to check strictfp
2827 bool IsIEEEMode = MFI->getMode().IEEE;
2828
2829 bool Changed = false;
2830 for (MachineBasicBlock *MBB : depth_first(&MF)) {
2831 MachineOperand *CurrentKnownM0Val = nullptr;
2832 for (auto &MI : make_early_inc_range(*MBB)) {
2833 Changed |= tryFoldCndMask(MI);
2834
2835 if (tryFoldZeroHighBits(MI)) {
2836 Changed = true;
2837 continue;
2838 }
2839
2840 if (MI.isRegSequence() && tryFoldRegSequence(MI)) {
2841 Changed = true;
2842 continue;
2843 }
2844
2845 if (MI.isPHI() && tryFoldPhiAGPR(MI)) {
2846 Changed = true;
2847 continue;
2848 }
2849
2850 if (MI.mayLoad() && tryFoldLoad(MI)) {
2851 Changed = true;
2852 continue;
2853 }
2854
2855 if (TII->isFoldableCopy(MI)) {
2856 Changed |= tryFoldFoldableCopy(MI, CurrentKnownM0Val);
2857 continue;
2858 }
2859
2860 // Saw an unknown clobber of m0, so we no longer know what it is.
2861 if (CurrentKnownM0Val && MI.modifiesRegister(AMDGPU::M0, TRI))
2862 CurrentKnownM0Val = nullptr;
2863
2864 // TODO: Omod might be OK if there is NSZ only on the source
2865 // instruction, and not the omod multiply.
2866 if (IsIEEEMode || !MI.getFlag(MachineInstr::FmNsz) || !tryFoldOMod(MI))
2867 Changed |= tryFoldClamp(MI);
2868 }
2869
2870 Changed |= tryOptimizeAGPRPhis(*MBB);
2871 }
2872
2873 return Changed;
2874}
2875
2878 MFPropsModifier _(*this, MF);
2879
2880 bool Changed = SIFoldOperandsImpl().run(MF);
2881 if (!Changed) {
2882 return PreservedAnalyses::all();
2883 }
2885 PA.preserveSet<CFGAnalyses>();
2886 return PA;
2887}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
Provides AMDGPU specific target descriptions.
Rewrite undef for PHI
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat)
Updates the operand at Idx in instruction Inst with the result of instruction Mat.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
iv Induction Variable Users
Definition IVUsers.cpp:48
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
MachineInstr unsigned OpIdx
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static unsigned macToMad(unsigned Opc)
static bool isAGPRCopy(const SIRegisterInfo &TRI, const MachineRegisterInfo &MRI, const MachineInstr &Copy, Register &OutReg, unsigned &OutSubReg)
Checks whether Copy is a AGPR -> VGPR copy.
static void appendFoldCandidate(SmallVectorImpl< FoldCandidate > &FoldList, FoldCandidate &&Entry)
static const TargetRegisterClass * getRegOpRC(const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const MachineOperand &MO)
static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result, uint32_t LHS, uint32_t RHS)
static int getOModValue(unsigned Opc, int64_t Val)
static unsigned getMovOpc(bool IsScalar)
static MachineOperand * lookUpCopyChain(const SIInstrInfo &TII, const MachineRegisterInfo &MRI, Register SrcReg)
static bool checkImmOpForPKF32InstrReplicatesLower32BitsOfScalarOperand(const FoldableDef &OpToFold)
static bool isPKF32InstrReplicatesLower32BitsOfScalarOperand(const GCNSubtarget *ST, MachineInstr *MI, unsigned OpNo)
Interface definition for SIInstrInfo.
Interface definition for SIRegisterInfo.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
Value * RHS
Value * LHS
Represent the analysis usage information of a 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
const SIInstrInfo * getInstrInfo() const override
bool hasDOTOpSelHazard() const
bool zeroesHigh16BitsOfDest(unsigned Opcode) const
Returns if the result of this instruction with a 16-bit result returned in a 32-bit register implicit...
const HexagonRegisterInfo & getRegisterInfo() const
ArrayRef< MCOperandInfo > operands() const
int getOperandConstraint(unsigned OpNum, MCOI::OperandConstraint Constraint) const
Returns the value of the specified operand constraint if it is present.
bool isVariadic() const
Return true if this instruction can have a variable number of operands.
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition MCInstrDesc.h:86
uint8_t OperandType
Information about the type of the operand.
Definition MCInstrDesc.h:98
bool hasSuperClassEq(const MCRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
bool hasSubClassEq(const MCRegisterClass *RC) const
Returns true if RC is a sub-class of or equal to this class.
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI iterator SkipPHIsLabelsAndDebug(iterator I, Register Reg=Register(), bool SkipPseudoOp=true)
Return the first instruction in MBB after I that is not a PHI, label or debug.
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.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
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.
Properties which a MachineFunction may have at a given point in time.
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.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isCopy() const
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
unsigned getOperandNo(const_mop_iterator I) const
Returns the number of the operand iterator I points to.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
mop_range implicit_operands()
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
void clearFlag(MIFlag Flag)
clearFlag - Clear a MI flag.
bool isRegSequence() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand * mop_iterator
iterator/begin/end - Iterate over all operands of a machine instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
LLVM_ABI void substVirtReg(Register Reg, unsigned SubIdx, const TargetRegisterInfo &)
substVirtReg - Substitute the current register with the virtual subregister Reg:SubReg.
LLVM_ABI void ChangeToFrameIndex(int Idx, unsigned TargetFlags=0)
Replace this operand with a frame index.
void setImm(int64_t immVal)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
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.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
LLVM_ABI void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
void setIsKill(bool Val=true)
LLVM_ABI void ChangeToRegister(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isDebug=false)
ChangeToRegister - Replace this operand with a new register operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
LLVM_ABI void substPhysReg(MCRegister Reg, const TargetRegisterInfo &)
substPhysReg - Substitute the current register with the physical register Reg, taking any existing Su...
static MachineOperand CreateImm(int64_t Val)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_FrameIndex
Abstract Stack Frame Index.
@ MO_Register
Register operand.
static MachineOperand CreateFI(int Idx)
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.
use_nodbg_iterator use_nodbg_begin(Register RegNo) const
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual 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 ...
iterator_range< use_nodbg_iterator > use_nodbg_operands(Register Reg) const
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 Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool hasOneNonDBGUser(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug instruction using the specified regis...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
void setRegAllocationHint(Register VReg, unsigned Type, Register PrefReg)
setRegAllocationHint - Specify a register allocation hint for the specified virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
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
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
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)
static bool hasSameClamp(const MachineInstr &A, const MachineInstr &B)
static std::optional< int64_t > extractSubregFromImm(int64_t ImmVal, unsigned SubRegIndex)
Return the extracted immediate value in a subregister use from a constant materialized in a super reg...
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
Register getScratchRSrcReg() const
Returns the physical register reserved for use as the resource descriptor for scratch accesses.
SIModeRegisterDefaults getMode() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
Register getReg() const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static const unsigned CommuteAnyOperandIndex
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
Definition ilist_node.h:123
IteratorT end() const
IteratorT begin() const
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isInlinableLiteralV216(uint32_t Literal, uint8_t OpType)
LLVM_READONLY int32_t getMFMAEarlyClobberOp(uint32_t Opcode)
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
constexpr bool isSISrcOperand(const MCOperandInfo &OpInfo)
Is this an AMDGPU specific source operand?
@ OPERAND_REG_IMM_V2FP64
Definition SIDefines.h:433
@ OPERAND_REG_IMM_V2FP16
Definition SIDefines.h:426
@ OPERAND_REG_INLINE_C_FP64
Definition SIDefines.h:442
@ OPERAND_REG_INLINE_C_V2BF16
Definition SIDefines.h:444
@ OPERAND_REG_IMM_V2INT64
Definition SIDefines.h:429
@ OPERAND_REG_IMM_V2INT16
Definition SIDefines.h:428
@ OPERAND_REG_IMM_V2BF16
Definition SIDefines.h:425
@ OPERAND_REG_INLINE_C_INT64
Definition SIDefines.h:438
@ OPERAND_REG_IMM_NOINLINE_V2FP16
Definition SIDefines.h:430
@ OPERAND_REG_INLINE_C_V2FP16
Definition SIDefines.h:445
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
Definition SIDefines.h:456
@ OPERAND_REG_INLINE_AC_FP32
Definition SIDefines.h:457
@ OPERAND_REG_INLINE_C_FP32
Definition SIDefines.h:441
@ OPERAND_REG_INLINE_C_INT32
Definition SIDefines.h:437
@ OPERAND_REG_INLINE_C_V2INT16
Definition SIDefines.h:443
@ OPERAND_REG_IMM_V2FP32
Definition SIDefines.h:432
@ OPERAND_REG_INLINE_AC_FP64
Definition SIDefines.h:458
LLVM_READONLY int32_t getFlatScratchInstSSfromSV(uint32_t Opcode)
bool supportsScaleOffset(const MCInstrInfo &MII, unsigned Opcode)
@ Entry
Definition COFF.h:862
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
constexpr bool isVOP3(const T &...O)
Definition SIDefines.h:234
constexpr bool isMAI(const T &...O)
Definition SIDefines.h:345
constexpr bool isSWMMAC(const T &...O)
Definition SIDefines.h:372
constexpr bool isVOP3P(const T &...O)
Definition SIDefines.h:237
constexpr bool isWMMA(const T &...O)
Definition SIDefines.h:360
constexpr bool isDOT(const T &...O)
Definition SIDefines.h:348
constexpr bool isPacked(const T &...O)
Definition SIDefines.h:330
NodeAddr< DefNode * > Def
Definition RDFGraph.h:386
This is an optimization pass for GlobalISel generic memory operations.
TargetInstrInfo::RegSubRegPair getRegSubRegPair(const MachineOperand &O)
Create RegSubRegPair from a register MachineOperand.
MachineBasicBlock::instr_iterator getBundleStart(MachineBasicBlock::instr_iterator I)
Returns an iterator to the first instruction in the bundle containing I.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool execMayBeModifiedBeforeUse(const MachineRegisterInfo &MRI, Register VReg, const MachineInstr &DefMI, const MachineInstr &UseMI)
Return false if EXEC is not changed between the def of VReg at DefMI and the use at UseMI.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Op::Description Desc
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createSIFoldOperandsLegacyPass()
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
Definition MathExtras.h:150
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:155
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
DWARFExpression::Operation Op
char & SIFoldOperandsLegacyID
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
iterator_range< df_iterator< T > > depth_first(const T &G)
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
constexpr uint64_t Make_64(uint32_t High, uint32_t Low)
Make a 64-bit integer from a high / low pair of 32-bit integers.
Definition MathExtras.h:160
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:862
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
DenormalMode FP64FP16Denormals
If this is set, neither input or output denormals are flushed for both f64 and f16/v2f16 instructions...
bool IEEE
Floating point opcodes that support exception flag gathering quiet and propagate signaling NaN inputs...
DenormalMode FP32Denormals
If this is set, neither input or output denormals are flushed for most f32 instructions.