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