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 // Special case for s_setreg_b32
925 if (OpToFold.isImm()) {
926 unsigned ImmOpc = 0;
927 if (Opc == AMDGPU::S_SETREG_B32)
928 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
929 else if (Opc == AMDGPU::S_SETREG_B32_mode)
930 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
931 if (ImmOpc) {
932 MI->setDesc(TII->get(ImmOpc));
933 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
934 return true;
935 }
936 }
937
938 // Operand is not legal, so try to commute the instruction to
939 // see if this makes it possible to fold.
940 unsigned CommuteOpNo = TargetInstrInfo::CommuteAnyOperandIndex;
941 bool CanCommute = TII->findCommutedOpIndices(*MI, OpNo, CommuteOpNo);
942 if (!CanCommute)
943 return false;
944
945 MachineOperand &Op = MI->getOperand(OpNo);
946 MachineOperand &CommutedOp = MI->getOperand(CommuteOpNo);
947
948 // One of operands might be an Imm operand, and OpNo may refer to it after
949 // the call of commuteInstruction() below. Such situations are avoided
950 // here explicitly as OpNo must be a register operand to be a candidate
951 // for memory folding.
952 if (!Op.isReg() || !CommutedOp.isReg())
953 return false;
954
955 // The same situation with an immediate could reproduce if both inputs are
956 // the same register.
957 if (Op.isReg() && CommutedOp.isReg() &&
958 (Op.getReg() == CommutedOp.getReg() &&
959 Op.getSubReg() == CommutedOp.getSubReg()))
960 return false;
961
962 if (!TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo))
963 return false;
964
965 int Op32 = -1;
966 if (!OpToFold.isOperandLegal(*TII, *MI, CommuteOpNo)) {
967 if ((Opc != AMDGPU::V_ADD_CO_U32_e64 && Opc != AMDGPU::V_SUB_CO_U32_e64 &&
968 Opc != AMDGPU::V_SUBREV_CO_U32_e64) || // FIXME
969 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
970 TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo);
971 return false;
972 }
973
974 // Verify the other operand is a VGPR, otherwise we would violate the
975 // constant bus restriction.
976 MachineOperand &OtherOp = MI->getOperand(OpNo);
977 if (!OtherOp.isReg() ||
978 !TII->getRegisterInfo().isVGPR(*MRI, OtherOp.getReg()))
979 return false;
980
981 assert(MI->getOperand(1).isDef());
982
983 // Make sure to get the 32-bit version of the commuted opcode.
984 unsigned MaybeCommutedOpc = MI->getOpcode();
985 Op32 = AMDGPU::getVOPe32(MaybeCommutedOpc);
986 }
987
988 appendFoldCandidate(FoldList, MI, CommuteOpNo, OpToFold, /*Commuted=*/true,
989 Op32);
990 return true;
991 }
992
993 // Special case for s_fmac_f32 if we are trying to fold into Src0 or Src1.
994 // By changing into fmamk we can untie Src2.
995 // If folding for Src0 happens first and it is identical operand to Src1 we
996 // should avoid transforming into fmamk which requires commuting as it would
997 // cause folding into Src1 to fail later on due to wrong OpNo used.
998 if (Opc == AMDGPU::S_FMAC_F32 &&
999 (OpNo != 1 || !MI->getOperand(1).isIdenticalTo(MI->getOperand(2)))) {
1000 if (tryToFoldAsFMAAKorMK())
1001 return true;
1002 }
1003
1004 // Special case for PK_F32 instructions if we are trying to fold an imm to
1005 // src0 or src1.
1006 if (OpToFold.isImm() &&
1009 return false;
1010
1011 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
1012 return true;
1013}
1014
1015bool SIFoldOperandsImpl::isUseSafeToFold(const MachineInstr &MI,
1016 const MachineOperand &UseMO) const {
1017 // Operands of SDWA instructions must be registers.
1018 return !TII->isSDWA(MI);
1019}
1020
1021// Returns true if any instruction in \p L modifies EXEC.
1022static bool loopModifiesExec(const MachineLoop &L, const SIRegisterInfo &TRI) {
1023 for (const MachineBasicBlock *MBB : L.getBlocks())
1024 for (const MachineInstr &MI : *MBB)
1025 if (MI.modifiesRegister(TRI.getExec(), &TRI))
1026 return true;
1027 return false;
1028}
1029
1030// An SGPR->VGPR copy inside a divergent loop latches each lane value as it
1031// exits. Folding its scalar source into a use after the loop would make every
1032// lane read the same reconverged value, so do not fold across the loop exit.
1033bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1034 const FoldableDef &OpToFold, const MachineInstr &UseMI) const {
1035 if (!OpToFold.isReg())
1036 return false;
1037 const MachineInstr *DefMI = OpToFold.DefMI;
1038 if (!DefMI || !DefMI->isCopy() ||
1039 TRI->isSGPRReg(*MRI, DefMI->getOperand(0).getReg()) ||
1040 !TRI->isSGPRReg(*MRI, OpToFold.getReg()))
1041 return false;
1042 const MachineLoop *DefLoop = MLI->getLoopFor(DefMI->getParent());
1043 return DefLoop && !DefLoop->contains(UseMI.getParent()) &&
1044 loopModifiesExec(*DefLoop, *TRI);
1045}
1046
1048 const MachineRegisterInfo &MRI,
1049 Register SrcReg) {
1050 MachineOperand *Sub = nullptr;
1051 for (MachineInstr *SubDef = MRI.getVRegDef(SrcReg);
1052 SubDef && TII.isFoldableCopy(*SubDef);
1053 SubDef = MRI.getVRegDef(Sub->getReg())) {
1054 unsigned SrcIdx = TII.getFoldableCopySrcIdx(*SubDef);
1055 MachineOperand &SrcOp = SubDef->getOperand(SrcIdx);
1056
1057 if (SrcOp.isImm())
1058 return &SrcOp;
1059 if (!SrcOp.isReg() || SrcOp.getReg().isPhysical())
1060 break;
1061 Sub = &SrcOp;
1062 // TODO: Support compose
1063 if (SrcOp.getSubReg())
1064 break;
1065 }
1066
1067 return Sub;
1068}
1069
1070const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
1071 MachineInstr &RegSeq,
1072 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs) const {
1073
1074 assert(RegSeq.isRegSequence());
1075
1076 const TargetRegisterClass *RC = nullptr;
1077
1078 for (unsigned I = 1, E = RegSeq.getNumExplicitOperands(); I != E; I += 2) {
1079 MachineOperand &SrcOp = RegSeq.getOperand(I);
1080 if (SrcOp.getReg().isPhysical())
1081 return nullptr;
1082 unsigned SubRegIdx = RegSeq.getOperand(I + 1).getImm();
1083
1084 // Only accept reg_sequence with uniform reg class inputs for simplicity.
1085 const TargetRegisterClass *OpRC = getRegOpRC(*MRI, *TRI, SrcOp);
1086 if (!RC)
1087 RC = OpRC;
1088 else if (!TRI->getCommonSubClass(RC, OpRC))
1089 return nullptr;
1090
1091 if (SrcOp.getSubReg()) {
1092 // TODO: Handle subregister compose
1093 Defs.emplace_back(&SrcOp, SubRegIdx);
1094 continue;
1095 }
1096
1097 MachineOperand *DefSrc = lookUpCopyChain(*TII, *MRI, SrcOp.getReg());
1098 if (DefSrc && (DefSrc->isReg() || DefSrc->isImm())) {
1099 Defs.emplace_back(DefSrc, SubRegIdx);
1100 continue;
1101 }
1102
1103 Defs.emplace_back(&SrcOp, SubRegIdx);
1104 }
1105
1106 return RC;
1107}
1108
1109// Find a def of the UseReg, check if it is a reg_sequence and find initializers
1110// for each subreg, tracking it to an immediate if possible. Returns the
1111// register class of the inputs on success.
1112const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
1113 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1114 Register UseReg) const {
1115 MachineInstr *Def = MRI->getVRegDef(UseReg);
1116 if (!Def || !Def->isRegSequence())
1117 return nullptr;
1118
1119 return getRegSeqInit(*Def, Defs);
1120}
1121
1122std::pair<int64_t, const TargetRegisterClass *>
1123SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const {
1125 const TargetRegisterClass *SrcRC = getRegSeqInit(RegSeq, Defs);
1126 if (!SrcRC)
1127 return {};
1128
1129 bool TryToMatchSplat64 = false;
1130
1131 std::optional<int64_t> Imm;
1132 for (unsigned I = 0, E = Defs.size(); I != E; ++I) {
1133 const MachineOperand *Op = Defs[I].first;
1134 if (!Op->isImm()) {
1135 if (Op->isReg()) {
1136 MachineInstr *Def = MRI->getVRegDef(Op->getReg());
1137 if (!Def || Def->isImplicitDef())
1138 continue;
1139 }
1140 return {};
1141 }
1142
1143 int64_t SubImm = Op->getImm();
1144 if (!Imm) {
1145 Imm = SubImm;
1146 continue;
1147 }
1148
1149 if (Imm != SubImm) {
1150 if (I == 1 && (E & 1) == 0) {
1151 // If we have an even number of inputs, there's a chance this is a
1152 // 64-bit element splat broken into 32-bit pieces.
1153 TryToMatchSplat64 = true;
1154 break;
1155 }
1156
1157 return {}; // Can only fold splat constants
1158 }
1159 }
1160
1161 if (!TryToMatchSplat64) {
1162 if (Imm)
1163 return {*Imm, SrcRC};
1164 return {};
1165 }
1166
1167 // Fallback to recognizing 64-bit splats broken into 32-bit pieces
1168 // (i.e. recognize every other other element is 0 for 64-bit immediates)
1169 int64_t SplatVal64;
1170 for (unsigned I = 0, E = Defs.size(); I != E; I += 2) {
1171 const MachineOperand *Op0 = Defs[I].first;
1172 const MachineOperand *Op1 = Defs[I + 1].first;
1173
1174 if (!Op0->isImm() || !Op1->isImm())
1175 return {};
1176
1177 unsigned SubReg0 = Defs[I].second;
1178 unsigned SubReg1 = Defs[I + 1].second;
1179
1180 // Assume we're going to generally encounter reg_sequences with sorted
1181 // subreg indexes, so reject any that aren't consecutive.
1182 if (TRI->getChannelFromSubReg(SubReg0) + 1 !=
1183 TRI->getChannelFromSubReg(SubReg1))
1184 return {};
1185
1186 if (TRI->getSubRegIdxSize(SubReg0) != 32)
1187 return {};
1188
1189 int64_t MergedVal = Make_64(Op1->getImm(), Op0->getImm());
1190 if (I == 0)
1191 SplatVal64 = MergedVal;
1192 else if (SplatVal64 != MergedVal)
1193 return {};
1194 }
1195
1196 const TargetRegisterClass *RC64 = TRI->getSubRegisterClass(
1197 MRI->getRegClass(RegSeq.getOperand(0).getReg()), AMDGPU::sub0_sub1);
1198
1199 return {SplatVal64, RC64};
1200}
1201
1202bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1203 MachineInstr *UseMI, unsigned UseOpIdx, int64_t SplatVal,
1204 const TargetRegisterClass *SplatRC) const {
1205 const MCInstrDesc &Desc = UseMI->getDesc();
1206 if (UseOpIdx >= Desc.getNumOperands())
1207 return false;
1208
1209 // Filter out unhandled pseudos.
1210 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1211 return false;
1212
1213 int16_t RCID = TII->getOpRegClassID(Desc.operands()[UseOpIdx]);
1214 if (RCID == -1)
1215 return false;
1216
1217 const TargetRegisterClass *OpRC = TRI->getRegClass(RCID);
1218
1219 // Special case 0/-1, since when interpreted as a 64-bit element both halves
1220 // have the same bits. These are the only cases where a splat has the same
1221 // interpretation for 32-bit and 64-bit splats.
1222 if (SplatVal != 0 && SplatVal != -1) {
1223 // We need to figure out the scalar type read by the operand. e.g. the MFMA
1224 // operand will be AReg_128, and we want to check if it's compatible with an
1225 // AReg_32 constant.
1226 uint8_t OpTy = Desc.operands()[UseOpIdx].OperandType;
1227 switch (OpTy) {
1233 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1234 break;
1240 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1241 break;
1242 default:
1243 return false;
1244 }
1245
1246 if (!TRI->getCommonSubClass(OpRC, SplatRC))
1247 return false;
1248 }
1249
1250 MachineOperand TmpOp = MachineOperand::CreateImm(SplatVal);
1251 if (!TII->isOperandLegal(*UseMI, UseOpIdx, &TmpOp))
1252 return false;
1253
1254 return true;
1255}
1256
1257bool SIFoldOperandsImpl::tryToFoldACImm(
1258 const FoldableDef &OpToFold, MachineInstr *UseMI, unsigned UseOpIdx,
1259 SmallVectorImpl<FoldCandidate> &FoldList) const {
1260 const MCInstrDesc &Desc = UseMI->getDesc();
1261 if (UseOpIdx >= Desc.getNumOperands())
1262 return false;
1263
1264 // Filter out unhandled pseudos.
1265 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1266 return false;
1267
1268 if (OpToFold.isImm() && OpToFold.isOperandLegal(*TII, *UseMI, UseOpIdx)) {
1271 return false;
1272 appendFoldCandidate(FoldList, UseMI, UseOpIdx, OpToFold);
1273 return true;
1274 }
1275
1276 return false;
1277}
1278
1279bool SIFoldOperandsImpl::foldOperand(
1280 FoldableDef OpToFold, MachineInstr *UseMI, int UseOpIdx,
1281 SmallVectorImpl<FoldCandidate> &FoldList,
1282 SmallVectorImpl<MachineInstr *> &CopiesToReplace) const {
1283 bool Changed = false;
1284 const MachineOperand *UseOp = &UseMI->getOperand(UseOpIdx);
1285
1286 if (!isUseSafeToFold(*UseMI, *UseOp))
1287 return Changed;
1288
1289 if (isTemporallyDivergentUse(OpToFold, *UseMI))
1290 return Changed;
1291
1292 // FIXME: Fold operands with subregs.
1293 if (UseOp->isReg() && OpToFold.isReg()) {
1294 if (UseOp->isImplicit())
1295 return Changed;
1296 // Allow folding from SGPRs to 16-bit VGPRs.
1297 if (UseOp->getSubReg() != AMDGPU::NoSubRegister &&
1298 (UseOp->getSubReg() != AMDGPU::lo16 ||
1299 !TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1300 return Changed;
1301 }
1302
1303 // Special case for REG_SEQUENCE: We can't fold literals into
1304 // REG_SEQUENCE instructions, so we have to fold them into the
1305 // uses of REG_SEQUENCE.
1306 if (UseMI->isRegSequence()) {
1307 Register RegSeqDstReg = UseMI->getOperand(0).getReg();
1308 unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
1309
1310 int64_t SplatVal;
1311 const TargetRegisterClass *SplatRC;
1312 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*UseMI);
1313
1314 // Grab the use operands first
1316 llvm::make_pointer_range(MRI->use_nodbg_operands(RegSeqDstReg)));
1317 for (unsigned I = 0; I != UsesToProcess.size(); ++I) {
1318 MachineOperand *RSUse = UsesToProcess[I];
1319 MachineInstr *RSUseMI = RSUse->getParent();
1320 unsigned OpNo = RSUseMI->getOperandNo(RSUse);
1321
1322 if (SplatRC) {
1323 if (RSUseMI->isCopy()) {
1324 Register DstReg = RSUseMI->getOperand(0).getReg();
1325 append_range(UsesToProcess,
1327 continue;
1328 }
1329 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1330 FoldableDef SplatDef(SplatVal, SplatRC);
1331 appendFoldCandidate(FoldList, RSUseMI, OpNo, SplatDef);
1332 Changed = true;
1333 continue;
1334 }
1335 }
1336
1337 // TODO: Handle general compose
1338 if (RSUse->getSubReg() != RegSeqDstSubReg)
1339 continue;
1340
1341 // FIXME: We should avoid recursing here. There should be a cleaner split
1342 // between the in-place mutations and adding to the fold list.
1343 Changed |= foldOperand(OpToFold, RSUseMI, RSUseMI->getOperandNo(RSUse),
1344 FoldList, CopiesToReplace);
1345 }
1346
1347 return Changed;
1348 }
1349
1350 if (tryToFoldACImm(OpToFold, UseMI, UseOpIdx, FoldList))
1351 return true;
1352
1353 if (frameIndexMayFold(*UseMI, UseOpIdx, OpToFold)) {
1354 // Verify that this is a stack access.
1355 // FIXME: Should probably use stack pseudos before frame lowering.
1356
1357 if (TII->isMUBUF(*UseMI)) {
1358 if (TII->getNamedOperand(*UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1359 MFI->getScratchRSrcReg())
1360 return Changed;
1361
1362 // Ensure this is either relative to the current frame or the current
1363 // wave.
1364 MachineOperand &SOff =
1365 *TII->getNamedOperand(*UseMI, AMDGPU::OpName::soffset);
1366 if (!SOff.isImm() || SOff.getImm() != 0)
1367 return Changed;
1368 }
1369
1370 const unsigned Opc = UseMI->getOpcode();
1371 if (TII->isFLATScratch(*UseMI) &&
1372 AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr) &&
1373 !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::saddr)) {
1374 unsigned NewOpc = AMDGPU::getFlatScratchInstSSfromSV(Opc);
1375 unsigned CPol =
1376 TII->getNamedOperand(*UseMI, AMDGPU::OpName::cpol)->getImm();
1377 if ((CPol & AMDGPU::CPol::SCAL) &&
1379 return Changed;
1380
1381 UseMI->setDesc(TII->get(NewOpc));
1382 }
1383
1384 // A frame index will resolve to a positive constant, so it should always be
1385 // safe to fold the addressing mode, even pre-GFX9.
1386 UseMI->getOperand(UseOpIdx).ChangeToFrameIndex(OpToFold.getFI());
1387
1388 return true;
1389 }
1390
1391 bool FoldingImmLike =
1392 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1393
1394 if (FoldingImmLike && UseMI->isCopy()) {
1395 Register DestReg = UseMI->getOperand(0).getReg();
1396 Register SrcReg = UseMI->getOperand(1).getReg();
1397 unsigned UseSubReg = UseMI->getOperand(1).getSubReg();
1398 assert(SrcReg.isVirtual());
1399
1400 const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg);
1401
1402 // Don't fold into a copy to a physical register with the same class. Doing
1403 // so would interfere with the register coalescer's logic which would avoid
1404 // redundant initializations.
1405 if (DestReg.isPhysical() && SrcRC->contains(DestReg))
1406 return Changed;
1407
1408 const TargetRegisterClass *DestRC = TRI->getRegClassForReg(*MRI, DestReg);
1409 // In order to fold immediates into copies, we need to change the copy to a
1410 // MOV. Find a compatible mov instruction with the value.
1411 for (unsigned MovOp :
1412 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1413 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1414 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1415 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1416 const MCInstrDesc &MovDesc = TII->get(MovOp);
1417 const TargetRegisterClass *MovDstRC =
1418 TRI->getRegClass(TII->getOpRegClassID(MovDesc.operands()[0]));
1419
1420 // Fold if the destination register class of the MOV instruction (ResRC)
1421 // is a superclass of (or equal to) the destination register class of the
1422 // COPY (DestRC). If this condition fails, folding would be illegal.
1423 if (!DestRC->hasSuperClassEq(MovDstRC))
1424 continue;
1425
1426 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1427
1428 int16_t RegClassID = TII->getOpRegClassID(MovDesc.operands()[SrcIdx]);
1429 if (RegClassID != -1) {
1430 const TargetRegisterClass *MovSrcRC = TRI->getRegClass(RegClassID);
1431
1432 if (UseSubReg)
1433 MovSrcRC = TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1434
1435 // FIXME: We should be able to directly check immediate operand legality
1436 // for all cases, but gfx908 hacks break.
1437 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1438 (!OpToFold.isImm() ||
1439 !TII->isImmOperandLegal(MovDesc, SrcIdx,
1440 *OpToFold.getEffectiveImmVal())))
1441 break;
1442
1443 if (!MRI->constrainRegClass(SrcReg, MovSrcRC))
1444 break;
1445
1446 // FIXME: This is mutating the instruction only and deferring the actual
1447 // fold of the immediate
1448 } else {
1449 // For the _IMM_PSEUDO cases, there can be value restrictions on the
1450 // immediate to verify. Technically we should always verify this, but it
1451 // only matters for these concrete cases.
1452 // TODO: Handle non-imm case if it's useful.
1453 if (!OpToFold.isImm() ||
1454 !TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1455 break;
1456 }
1457
1460 while (ImpOpI != ImpOpE) {
1461 MachineInstr::mop_iterator Tmp = ImpOpI;
1462 ImpOpI++;
1464 }
1465 UseMI->setDesc(MovDesc);
1466
1467 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1468 const auto &SrcOp = UseMI->getOperand(UseOpIdx);
1469 MachineOperand NewSrcOp(SrcOp);
1470 UseMI->removeOperand(1);
1471 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // src0_modifiers
1472 UseMI->addOperand(NewSrcOp); // src0
1473 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // op_sel
1474 UseOpIdx = SrcIdx;
1475 UseOp = &UseMI->getOperand(UseOpIdx);
1476 }
1477 CopiesToReplace.push_back(UseMI);
1478 Changed = true;
1479 break;
1480 }
1481
1482 // We failed to replace the copy, so give up.
1483 if (UseMI->getOpcode() == AMDGPU::COPY)
1484 return Changed;
1485
1486 } else {
1487 if (UseMI->isCopy() && OpToFold.isReg() &&
1488 UseMI->getOperand(0).getReg().isVirtual() &&
1489 !UseMI->getOperand(1).getSubReg() &&
1490 OpToFold.DefMI->implicit_operands().empty()) {
1491 LLVM_DEBUG(dbgs() << "Folding " << *OpToFold.OpToFold << "\n into "
1492 << *UseMI);
1493 unsigned Size = TII->getOpSize(*UseMI, 1);
1494 Register UseReg = OpToFold.getReg();
1496 unsigned SubRegIdx = OpToFold.getSubReg();
1497 // Hack to allow 32-bit SGPRs to be folded into True16 instructions
1498 // Remove this if 16-bit SGPRs (i.e. SGPR_LO16) are added to the
1499 // VS_16RegClass
1500 //
1501 // Excerpt from AMDGPUGenRegisterInfoEnums.inc
1502 // NoSubRegister, //0
1503 // hi16, // 1
1504 // lo16, // 2
1505 // sub0, // 3
1506 // ...
1507 // sub1, // 11
1508 // sub1_hi16, // 12
1509 // sub1_lo16, // 13
1510 static_assert(AMDGPU::sub1_hi16 == 12, "Subregister layout has changed");
1511 if (Size == 2 && TRI->isVGPR(*MRI, UseMI->getOperand(0).getReg()) &&
1512 TRI->isSGPRReg(*MRI, UseReg)) {
1513 // Produce the 32 bit subregister index to which the 16-bit subregister
1514 // is aligned.
1515 if (SubRegIdx > AMDGPU::sub1) {
1516 LaneBitmask M = TRI->getSubRegIndexLaneMask(SubRegIdx);
1517 M |= M.getLane(M.getHighestLane() - 1);
1518 SmallVector<unsigned, 4> Indexes;
1519 TRI->getCoveringSubRegIndexes(TRI->getRegClassForReg(*MRI, UseReg), M,
1520 Indexes);
1521 assert(Indexes.size() == 1 && "Expected one 32-bit subreg to cover");
1522 SubRegIdx = Indexes[0];
1523 // 32-bit registers do not have a sub0 index
1524 } else if (TII->getOpSize(*UseMI, 1) == 4)
1525 SubRegIdx = 0;
1526 else
1527 SubRegIdx = AMDGPU::sub0;
1528 }
1529 UseMI->getOperand(1).setSubReg(SubRegIdx);
1530 UseMI->getOperand(1).setIsKill(false);
1531 CopiesToReplace.push_back(UseMI);
1532 OpToFold.OpToFold->setIsKill(false);
1533 Changed = true;
1534
1535 // Remove kill flags as kills may now be out of order with uses.
1536 MRI->clearKillFlags(UseReg);
1537 if (foldCopyToAGPRRegSequence(UseMI))
1538 return true;
1539 }
1540
1541 unsigned UseOpc = UseMI->getOpcode();
1542 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1543 (UseOpc == AMDGPU::V_READLANE_B32 &&
1544 (int)UseOpIdx ==
1545 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1546 // %vgpr = V_MOV_B32 imm
1547 // %sgpr = V_READFIRSTLANE_B32 %vgpr
1548 // =>
1549 // %sgpr = S_MOV_B32 imm
1550 if (FoldingImmLike) {
1552 UseMI->getOperand(UseOpIdx).getReg(),
1553 *OpToFold.DefMI, *UseMI))
1554 return Changed;
1555
1556 UseMI->setDesc(TII->get(AMDGPU::S_MOV_B32));
1558
1559 if (OpToFold.isImm()) {
1561 *OpToFold.getEffectiveImmVal());
1562 } else if (OpToFold.isFI())
1563 UseMI->getOperand(1).ChangeToFrameIndex(OpToFold.getFI());
1564 else {
1565 assert(OpToFold.isGlobal());
1566 UseMI->getOperand(1).ChangeToGA(OpToFold.OpToFold->getGlobal(),
1567 OpToFold.OpToFold->getOffset(),
1568 OpToFold.OpToFold->getTargetFlags());
1569 }
1570 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1571 return true;
1572 }
1573
1574 if (OpToFold.isReg() && TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1576 UseMI->getOperand(UseOpIdx).getReg(),
1577 *OpToFold.DefMI, *UseMI))
1578 return Changed;
1579
1580 // %vgpr = COPY %sgpr0
1581 // %sgpr1 = V_READFIRSTLANE_B32 %vgpr
1582 // =>
1583 // %sgpr1 = COPY %sgpr0
1584 UseMI->setDesc(TII->get(AMDGPU::COPY));
1585 UseMI->getOperand(1).setReg(OpToFold.getReg());
1586 UseMI->getOperand(1).setSubReg(OpToFold.getSubReg());
1587 UseMI->getOperand(1).setIsKill(false);
1588 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1590 return true;
1591 }
1592 }
1593
1594 const MCInstrDesc &UseDesc = UseMI->getDesc();
1595
1596 // Don't fold into target independent nodes. Target independent opcodes
1597 // don't have defined register classes.
1598 if (UseDesc.isVariadic() || UseOp->isImplicit() ||
1599 UseDesc.operands()[UseOpIdx].RegClass == -1)
1600 return Changed;
1601 }
1602
1603 // FIXME: We could try to change the instruction from 64-bit to 32-bit
1604 // to enable more folding opportunities. The shrink operands pass
1605 // already does this.
1606
1607 Changed |= tryAddToFoldList(FoldList, UseMI, UseOpIdx, OpToFold);
1608 return Changed;
1609}
1610
1611static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result,
1613 switch (Opcode) {
1614 case AMDGPU::S_ADD_I32:
1615 case AMDGPU::S_ADD_U32:
1616 Result = LHS + RHS;
1617 return true;
1618 case AMDGPU::S_SUB_I32:
1619 case AMDGPU::S_SUB_U32:
1620 Result = LHS - RHS;
1621 return true;
1622 case AMDGPU::V_AND_B32_e64:
1623 case AMDGPU::V_AND_B32_e32:
1624 case AMDGPU::S_AND_B32:
1625 Result = LHS & RHS;
1626 return true;
1627 case AMDGPU::V_OR_B32_e64:
1628 case AMDGPU::V_OR_B32_e32:
1629 case AMDGPU::S_OR_B32:
1630 Result = LHS | RHS;
1631 return true;
1632 case AMDGPU::V_XOR_B32_e64:
1633 case AMDGPU::V_XOR_B32_e32:
1634 case AMDGPU::S_XOR_B32:
1635 Result = LHS ^ RHS;
1636 return true;
1637 case AMDGPU::S_XNOR_B32:
1638 Result = ~(LHS ^ RHS);
1639 return true;
1640 case AMDGPU::S_NAND_B32:
1641 Result = ~(LHS & RHS);
1642 return true;
1643 case AMDGPU::S_NOR_B32:
1644 Result = ~(LHS | RHS);
1645 return true;
1646 case AMDGPU::S_ANDN2_B32:
1647 Result = LHS & ~RHS;
1648 return true;
1649 case AMDGPU::S_ORN2_B32:
1650 Result = LHS | ~RHS;
1651 return true;
1652 case AMDGPU::V_LSHL_B32_e64:
1653 case AMDGPU::V_LSHL_B32_e32:
1654 case AMDGPU::S_LSHL_B32:
1655 // The instruction ignores the high bits for out of bounds shifts.
1656 Result = LHS << (RHS & 31);
1657 return true;
1658 case AMDGPU::V_LSHLREV_B32_e64:
1659 case AMDGPU::V_LSHLREV_B32_e32:
1660 Result = RHS << (LHS & 31);
1661 return true;
1662 case AMDGPU::V_LSHR_B32_e64:
1663 case AMDGPU::V_LSHR_B32_e32:
1664 case AMDGPU::S_LSHR_B32:
1665 Result = LHS >> (RHS & 31);
1666 return true;
1667 case AMDGPU::V_LSHRREV_B32_e64:
1668 case AMDGPU::V_LSHRREV_B32_e32:
1669 Result = RHS >> (LHS & 31);
1670 return true;
1671 case AMDGPU::V_ASHR_I32_e64:
1672 case AMDGPU::V_ASHR_I32_e32:
1673 case AMDGPU::S_ASHR_I32:
1674 Result = static_cast<int32_t>(LHS) >> (RHS & 31);
1675 return true;
1676 case AMDGPU::V_ASHRREV_I32_e64:
1677 case AMDGPU::V_ASHRREV_I32_e32:
1678 Result = static_cast<int32_t>(RHS) >> (LHS & 31);
1679 return true;
1680 default:
1681 return false;
1682 }
1683}
1684
1685static unsigned getMovOpc(bool IsScalar) {
1686 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1687}
1688
1689// Try to simplify operations with a constant that may appear after instruction
1690// selection.
1691// TODO: See if a frame index with a fixed offset can fold.
1692bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *MI) const {
1693 if (!MI->allImplicitDefsAreDead())
1694 return false;
1695
1696 unsigned Opc = MI->getOpcode();
1697
1698 int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
1699 if (Src0Idx == -1)
1700 return false;
1701
1702 MachineOperand *Src0 = &MI->getOperand(Src0Idx);
1703 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*MRI, *Src0);
1704
1705 if ((Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
1706 Opc == AMDGPU::S_NOT_B32) &&
1707 Src0Imm) {
1708 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1709 TII->mutateAndCleanupImplicit(
1710 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
1711 return true;
1712 }
1713
1714 int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
1715 if (Src1Idx == -1)
1716 return false;
1717
1718 MachineOperand *Src1 = &MI->getOperand(Src1Idx);
1719 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
1720
1721 if (!Src0Imm && !Src1Imm)
1722 return false;
1723
1724 // and k0, k1 -> v_mov_b32 (k0 & k1)
1725 // or k0, k1 -> v_mov_b32 (k0 | k1)
1726 // xor k0, k1 -> v_mov_b32 (k0 ^ k1)
1727 if (Src0Imm && Src1Imm) {
1728 int32_t NewImm;
1729 if (!evalBinaryInstruction(Opc, NewImm, *Src0Imm, *Src1Imm))
1730 return false;
1731
1732 bool IsSGPR = TRI->isSGPRReg(*MRI, MI->getOperand(0).getReg());
1733
1734 // Be careful to change the right operand, src0 may belong to a different
1735 // instruction.
1736 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1737 MI->removeOperand(Src1Idx);
1738 TII->mutateAndCleanupImplicit(*MI, TII->get(getMovOpc(IsSGPR)));
1739 return true;
1740 }
1741
1742 // S_SUB_* is not commutable, so handle it before the commutability gate.
1743 // Only `x - 0 -> copy x` is valid; `0 - x` is a negation, not a copy.
1744 if (Opc == AMDGPU::S_SUB_I32 || Opc == AMDGPU::S_SUB_U32) {
1745 if (Src1Imm && static_cast<int32_t>(*Src1Imm) == 0) {
1746 // y = sub x, 0 => y = copy x
1747 MI->removeOperand(Src1Idx);
1748 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1749 return true;
1750 }
1751 return false;
1752 }
1753
1754 if (!MI->isCommutable())
1755 return false;
1756
1757 if (Src0Imm && !Src1Imm) {
1758 std::swap(Src0, Src1);
1759 std::swap(Src0Idx, Src1Idx);
1760 std::swap(Src0Imm, Src1Imm);
1761 }
1762
1763 int32_t Src1Val = static_cast<int32_t>(*Src1Imm);
1764 if (Opc == AMDGPU::S_ADD_I32 || Opc == AMDGPU::S_ADD_U32) {
1765 if (Src1Val == 0) {
1766 // y = add x, 0 => y = copy x
1767 MI->removeOperand(Src1Idx);
1768 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1769 return true;
1770 }
1771 return false;
1772 }
1773
1774 if (Opc == AMDGPU::V_OR_B32_e64 ||
1775 Opc == AMDGPU::V_OR_B32_e32 ||
1776 Opc == AMDGPU::S_OR_B32) {
1777 if (Src1Val == 0) {
1778 // y = or x, 0 => y = copy x
1779 MI->removeOperand(Src1Idx);
1780 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1781 } else if (Src1Val == -1) {
1782 // y = or x, -1 => y = v_mov_b32 -1
1783 MI->removeOperand(Src0Idx);
1784 TII->mutateAndCleanupImplicit(
1785 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
1786 } else
1787 return false;
1788
1789 return true;
1790 }
1791
1792 if (Opc == AMDGPU::V_AND_B32_e64 || Opc == AMDGPU::V_AND_B32_e32 ||
1793 Opc == AMDGPU::S_AND_B32) {
1794 if (Src1Val == 0) {
1795 // y = and x, 0 => y = v_mov_b32 0
1796 MI->removeOperand(Src0Idx);
1797 TII->mutateAndCleanupImplicit(
1798 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
1799 } else if (Src1Val == -1) {
1800 // y = and x, -1 => y = copy x
1801 MI->removeOperand(Src1Idx);
1802 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1803 } else
1804 return false;
1805
1806 return true;
1807 }
1808
1809 if (Opc == AMDGPU::V_XOR_B32_e64 || Opc == AMDGPU::V_XOR_B32_e32 ||
1810 Opc == AMDGPU::S_XOR_B32) {
1811 if (Src1Val == 0) {
1812 // y = xor x, 0 => y = copy x
1813 MI->removeOperand(Src1Idx);
1814 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1815 return true;
1816 }
1817 }
1818
1819 return false;
1820}
1821
1822// Try to fold an instruction into a simpler one
1823bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &MI) const {
1824 unsigned Opc = MI.getOpcode();
1825 if (Opc != AMDGPU::V_CNDMASK_B32_e32 && Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1826 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1827 return false;
1828
1829 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1830 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1831 if (!Src1->isIdenticalTo(*Src0)) {
1832 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
1833 if (!Src1Imm)
1834 return false;
1835
1836 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*MRI, *Src0);
1837 if (!Src0Imm || *Src0Imm != *Src1Imm)
1838 return false;
1839 }
1840
1841 int Src1ModIdx =
1842 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1_modifiers);
1843 int Src0ModIdx =
1844 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers);
1845 if ((Src1ModIdx != -1 && MI.getOperand(Src1ModIdx).getImm() != 0) ||
1846 (Src0ModIdx != -1 && MI.getOperand(Src0ModIdx).getImm() != 0))
1847 return false;
1848
1849 LLVM_DEBUG(dbgs() << "Folded " << MI << " into ");
1850 auto &NewDesc =
1851 TII->get(Src0->isReg() ? (unsigned)AMDGPU::COPY : getMovOpc(false));
1852 int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
1853 if (Src2Idx != -1)
1854 MI.removeOperand(Src2Idx);
1855 MI.removeOperand(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1));
1856 if (Src1ModIdx != -1)
1857 MI.removeOperand(Src1ModIdx);
1858 if (Src0ModIdx != -1)
1859 MI.removeOperand(Src0ModIdx);
1860 TII->mutateAndCleanupImplicit(MI, NewDesc);
1861 LLVM_DEBUG(dbgs() << MI);
1862 return true;
1863}
1864
1865// Extract mask, register, and register operand index from an AND instruction.
1866// Immediate can be in operand 1 or 2.
1867std::optional<SIFoldOperandsImpl::ANDMaskResult>
1868SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI) const {
1869 unsigned Opc = AndMI.getOpcode();
1870 if (Opc != AMDGPU::V_AND_B32_e64 && Opc != AMDGPU::V_AND_B32_e32 &&
1871 Opc != AMDGPU::S_AND_B32)
1872 return std::nullopt;
1873
1874 std::optional<int64_t> MaskImm =
1875 TII->getImmOrMaterializedImm(*MRI, AndMI.getOperand(1));
1876 if (MaskImm && AndMI.getOperand(2).isReg())
1877 return ANDMaskResult{*MaskImm, AndMI.getOperand(2).getReg(), 2};
1878
1879 MaskImm = TII->getImmOrMaterializedImm(*MRI, AndMI.getOperand(2));
1880 if (MaskImm && AndMI.getOperand(1).isReg())
1881 return ANDMaskResult{*MaskImm, AndMI.getOperand(1).getReg(), 1};
1882
1883 return std::nullopt;
1884}
1885
1886// Eliminate redundant 32-bit AND operations by detecting when ChildMI's mask
1887// contains ParentMI's mask.
1888//
1889// For example:
1890// ParentMI: %1 = AND %0, 0x7fff
1891// ChildMI: %2 = AND %1, 0xffff
1892//
1893// This also handles cases where ParentMI implicitly zeros high bits (e.g., f16
1894// operations that write 16-bit results into 32-bit registers), making a
1895// subsequent AND with 0xffff redundant.
1896bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI) const {
1897 // Ensure implicit defs (e.g., $scc) are not live.
1898 if (!ChildMI.allImplicitDefsAreDead())
1899 return false;
1900
1901 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1902 if (!ChildResult)
1903 return false;
1904
1905 if (!ChildResult->Reg.isVirtual())
1906 return false;
1907
1908 MachineInstr *ParentMI = MRI->getVRegDef(ChildResult->Reg);
1909 if (!ParentMI)
1910 return false;
1911
1912 int64_t ParentMask = 0;
1913 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
1914 if (ParentResult) {
1915 // Parent is an AND - extract its mask.
1916 ParentMask = ParentResult->Mask;
1917 } else if (ST->zeroesHigh16BitsOfDest(ParentMI->getOpcode())) {
1918 // Parent instruction implicitly zeros high 16 bits.
1919 ParentMask = 0xffff;
1920 } else {
1921 return false;
1922 }
1923
1924 // Check if ChildMI is not redundant.
1925 if ((ParentMask & ChildResult->Mask) != ParentMask)
1926 return false;
1927
1928 Register Dst = ChildMI.getOperand(0).getReg();
1929 Register Src = ChildResult->Reg;
1930
1931 // Src must be legal in every use of Dst. An S_AND_B32 parent with a
1932 // V_AND_B32 child defines Src in the scalar bank, and a use that requires a
1933 // VGPR does not accept it.
1934 if (!Dst.isVirtual() || !MRI->constrainRegClass(Src, MRI->getRegClass(Dst)))
1935 return false;
1936
1937 MRI->replaceRegWith(Dst, Src);
1938
1939 // Clear kill flags if the register operand is not marked as kill.
1940 if (!ChildMI.getOperand(ChildResult->RegIdx).isKill())
1941 MRI->clearKillFlags(Src);
1942
1943 ChildMI.eraseFromParent();
1944 return true;
1945}
1946
1947bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &MI,
1948 const FoldableDef &OpToFold) const {
1949 // We need mutate the operands of new mov instructions to add implicit
1950 // uses of EXEC, but adding them invalidates the use_iterator, so defer
1951 // this.
1952 SmallVector<MachineInstr *, 4> CopiesToReplace;
1954 MachineOperand &Dst = MI.getOperand(0);
1955 bool Changed = false;
1956
1958 llvm::make_pointer_range(MRI->use_nodbg_operands(Dst.getReg())));
1959 for (auto *U : UsesToProcess) {
1960 MachineInstr *UseMI = U->getParent();
1961
1962 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*TRI, U->getSubReg());
1963 Changed |= foldOperand(SubOpToFold, UseMI, UseMI->getOperandNo(U), FoldList,
1964 CopiesToReplace);
1965 }
1966
1967 if (CopiesToReplace.empty() && FoldList.empty())
1968 return Changed;
1969
1970 // Make sure we add EXEC uses to any new v_mov instructions created.
1971 for (MachineInstr *Copy : CopiesToReplace)
1972 Copy->addImplicitDefUseOperands(*MF);
1973
1974 SetVector<MachineInstr *> ConstantFoldCandidates;
1975 for (FoldCandidate &Fold : FoldList) {
1976 assert(!Fold.isReg() || Fold.Def.OpToFold);
1977 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1978 Register Reg = Fold.getReg();
1979 const MachineInstr *DefMI = Fold.Def.DefMI;
1980 if (DefMI->readsRegister(AMDGPU::EXEC, TRI) &&
1981 execMayBeModifiedBeforeUse(*MRI, Reg, *DefMI, *Fold.UseMI))
1982 continue;
1983 }
1984 if (updateOperand(Fold)) {
1985 // Clear kill flags.
1986 if (Fold.isReg()) {
1987 assert(Fold.Def.OpToFold && Fold.isReg());
1988 // FIXME: Probably shouldn't bother trying to fold if not an
1989 // SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
1990 // copies.
1991 MRI->clearKillFlags(Fold.getReg());
1992 }
1993 LLVM_DEBUG(dbgs() << "Folded source from " << MI << " into OpNo "
1994 << static_cast<int>(Fold.UseOpNo) << " of "
1995 << *Fold.UseMI);
1996
1997 if (Fold.isImm())
1998 ConstantFoldCandidates.insert(Fold.UseMI);
1999
2000 } else if (Fold.Commuted) {
2001 // Restoring instruction's original operand order if fold has failed.
2002 TII->commuteInstruction(*Fold.UseMI, false);
2003 }
2004 }
2005
2006 for (MachineInstr *MI : ConstantFoldCandidates) {
2007 if (tryConstantFoldOp(MI)) {
2008 LLVM_DEBUG(dbgs() << "Constant folded " << *MI);
2009 Changed = true;
2010 }
2011 }
2012 return true;
2013}
2014
2015/// Fold %agpr = COPY (REG_SEQUENCE x_MOV_B32, ...) into REG_SEQUENCE
2016/// (V_ACCVGPR_WRITE_B32_e64) ... depending on the reg_sequence input values.
2017bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI) const {
2018 // It is very tricky to store a value into an AGPR. v_accvgpr_write_b32 can
2019 // only accept VGPR or inline immediate. Recreate a reg_sequence with its
2020 // initializers right here, so we will rematerialize immediates and avoid
2021 // copies via different reg classes.
2022 const TargetRegisterClass *DefRC =
2023 MRI->getRegClass(CopyMI->getOperand(0).getReg());
2024 if (!TRI->isAGPRClass(DefRC))
2025 return false;
2026
2027 Register UseReg = CopyMI->getOperand(1).getReg();
2028 MachineInstr *RegSeq = MRI->getVRegDef(UseReg);
2029 if (!RegSeq || !RegSeq->isRegSequence())
2030 return false;
2031
2032 const DebugLoc &DL = CopyMI->getDebugLoc();
2033 MachineBasicBlock &MBB = *CopyMI->getParent();
2034
2035 MachineInstrBuilder B(*MBB.getParent(), CopyMI);
2036 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2037
2038 const TargetRegisterClass *UseRC =
2039 MRI->getRegClass(CopyMI->getOperand(1).getReg());
2040
2041 // Value, subregindex for new REG_SEQUENCE
2043
2044 unsigned NumRegSeqOperands = RegSeq->getNumOperands();
2045 unsigned NumFoldable = 0;
2046
2047 for (unsigned I = 1; I != NumRegSeqOperands; I += 2) {
2048 MachineOperand &RegOp = RegSeq->getOperand(I);
2049 unsigned SubRegIdx = RegSeq->getOperand(I + 1).getImm();
2050
2051 if (RegOp.getSubReg()) {
2052 // TODO: Handle subregister compose
2053 NewDefs.emplace_back(&RegOp, SubRegIdx);
2054 continue;
2055 }
2056
2057 MachineOperand *Lookup = lookUpCopyChain(*TII, *MRI, RegOp.getReg());
2058 if (!Lookup)
2059 Lookup = &RegOp;
2060
2061 if (Lookup->isImm()) {
2062 // Check if this is an agpr_32 subregister.
2063 const TargetRegisterClass *DestSuperRC = TRI->getMatchingSuperRegClass(
2064 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2065 if (DestSuperRC &&
2066 TII->isInlineConstant(*Lookup, AMDGPU::OPERAND_REG_INLINE_C_INT32)) {
2067 ++NumFoldable;
2068 NewDefs.emplace_back(Lookup, SubRegIdx);
2069 continue;
2070 }
2071 }
2072
2073 const TargetRegisterClass *InputRC =
2074 Lookup->isReg() ? MRI->getRegClass(Lookup->getReg())
2075 : MRI->getRegClass(RegOp.getReg());
2076
2077 // TODO: Account for Lookup->getSubReg()
2078
2079 // If we can't find a matching super class, this is an SGPR->AGPR or
2080 // VGPR->AGPR subreg copy (or something constant-like we have to materialize
2081 // in the AGPR). We can't directly copy from SGPR to AGPR on gfx908, so we
2082 // want to rewrite to copy to an intermediate VGPR class.
2083 const TargetRegisterClass *MatchRC =
2084 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2085 if (!MatchRC) {
2086 ++NumFoldable;
2087 NewDefs.emplace_back(&RegOp, SubRegIdx);
2088 continue;
2089 }
2090
2091 NewDefs.emplace_back(&RegOp, SubRegIdx);
2092 }
2093
2094 // Do not clone a reg_sequence and merely change the result register class.
2095 if (NumFoldable == 0)
2096 return false;
2097
2098 CopyMI->setDesc(TII->get(AMDGPU::REG_SEQUENCE));
2099 for (unsigned I = CopyMI->getNumOperands() - 1; I > 0; --I)
2100 CopyMI->removeOperand(I);
2101
2102 for (auto [Def, DestSubIdx] : NewDefs) {
2103 if (!Def->isReg()) {
2104 // TODO: Should we use single write for each repeated value like in
2105 // register case?
2106 Register Tmp = MRI->createVirtualRegister(&AMDGPU::AGPR_32RegClass);
2107 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2108 .add(*Def);
2109 B.addReg(Tmp);
2110 } else {
2111 TargetInstrInfo::RegSubRegPair Src = getRegSubRegPair(*Def);
2112 Def->setIsKill(false);
2113
2114 Register &VGPRCopy = VGPRCopies[Src];
2115 if (!VGPRCopy) {
2116 const TargetRegisterClass *VGPRUseSubRC =
2117 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2118
2119 // We cannot build a reg_sequence out of the same registers, they
2120 // must be copied. Better do it here before copyPhysReg() created
2121 // several reads to do the AGPR->VGPR->AGPR copy.
2122
2123 // Direct copy from SGPR to AGPR is not possible on gfx908. To avoid
2124 // creation of exploded copies SGPR->VGPR->AGPR in the copyPhysReg()
2125 // later, create a copy here and track if we already have such a copy.
2126 const TargetRegisterClass *SubRC =
2127 TRI->getSubRegisterClass(MRI->getRegClass(Src.Reg), Src.SubReg);
2128 if (!VGPRUseSubRC->hasSubClassEq(SubRC)) {
2129 // TODO: Try to reconstrain class
2130 VGPRCopy = MRI->createVirtualRegister(VGPRUseSubRC);
2131 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::COPY), VGPRCopy).add(*Def);
2132 B.addReg(VGPRCopy);
2133 } else {
2134 // If it is already a VGPR, do not copy the register.
2135 B.add(*Def);
2136 }
2137 } else {
2138 B.addReg(VGPRCopy);
2139 }
2140 }
2141
2142 B.addImm(DestSubIdx);
2143 }
2144
2145 LLVM_DEBUG(dbgs() << "Folded " << *CopyMI);
2146 return true;
2147}
2148
2149bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2150 MachineInstr &MI, MachineOperand *&CurrentKnownM0Val) const {
2151 Register DstReg = MI.getOperand(0).getReg();
2152 // Specially track simple redefs of m0 to the same value in a block, so we
2153 // can erase the later ones.
2154 if (DstReg == AMDGPU::M0) {
2155 MachineOperand &NewM0Val = MI.getOperand(1);
2156 if (CurrentKnownM0Val && CurrentKnownM0Val->isIdenticalTo(NewM0Val)) {
2157 MI.eraseFromParent();
2158 return true;
2159 }
2160
2161 // We aren't tracking other physical registers
2162 CurrentKnownM0Val = (NewM0Val.isReg() && NewM0Val.getReg().isPhysical())
2163 ? nullptr
2164 : &NewM0Val;
2165 return false;
2166 }
2167
2168 MachineOperand *OpToFoldPtr;
2169 if (MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2170 // Folding when any src_modifiers are non-zero is unsupported
2171 if (TII->hasAnyModifiersSet(MI))
2172 return false;
2173 OpToFoldPtr = &MI.getOperand(2);
2174 } else
2175 OpToFoldPtr = &MI.getOperand(1);
2176 MachineOperand &OpToFold = *OpToFoldPtr;
2177 bool FoldingImm = OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
2178
2179 // FIXME: We could also be folding things like TargetIndexes.
2180 if (!FoldingImm && !OpToFold.isReg())
2181 return false;
2182
2183 // Fold virtual registers and constant physical registers.
2184 if (OpToFold.isReg() && OpToFold.getReg().isPhysical() &&
2185 !TRI->isConstantPhysReg(OpToFold.getReg()))
2186 return false;
2187
2188 // Prevent folding operands backwards in the function. For example,
2189 // the COPY opcode must not be replaced by 1 in this example:
2190 //
2191 // %3 = COPY %vgpr0; VGPR_32:%3
2192 // ...
2193 // %vgpr0 = V_MOV_B32_e32 1, implicit %exec
2194 if (!DstReg.isVirtual())
2195 return false;
2196
2197 const TargetRegisterClass *DstRC =
2198 MRI->getRegClass(MI.getOperand(0).getReg());
2199
2200 // True16: Fix malformed 16-bit sgpr COPY produced by peephole-opt
2201 // Can remove this code if proper 16-bit SGPRs are implemented
2202 // Example: Pre-peephole-opt
2203 // %29:sgpr_lo16 = COPY %16.lo16:sreg_32
2204 // %32:sreg_32 = COPY %29:sgpr_lo16
2205 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2206 // Post-peephole-opt and DCE
2207 // %32:sreg_32 = COPY %16.lo16:sreg_32
2208 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2209 // After this transform
2210 // %32:sreg_32 = COPY %16:sreg_32
2211 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2212 // After the fold operands pass
2213 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %16:sreg_32
2214 if (MI.getOpcode() == AMDGPU::COPY && OpToFold.isReg() &&
2215 OpToFold.getSubReg()) {
2216 if (DstRC == &AMDGPU::SReg_32RegClass &&
2217 DstRC == MRI->getRegClass(OpToFold.getReg())) {
2218 assert(OpToFold.getSubReg() == AMDGPU::lo16);
2219 OpToFold.setSubReg(0);
2220 }
2221 }
2222
2223 // Fold copy to AGPR through reg_sequence
2224 // TODO: Handle with subregister extract
2225 if (OpToFold.isReg() && MI.isCopy() && !MI.getOperand(1).getSubReg()) {
2226 if (foldCopyToAGPRRegSequence(&MI))
2227 return true;
2228 }
2229
2230 FoldableDef Def(OpToFold, DstRC);
2231 bool Changed = foldInstOperand(MI, Def);
2232
2233 // If we managed to fold all uses of this copy then we might as well
2234 // delete it now.
2235 // The only reason we need to follow chains of copies here is that
2236 // tryFoldRegSequence looks forward through copies before folding a
2237 // REG_SEQUENCE into its eventual users.
2238 auto *InstToErase = &MI;
2239 while (MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2240 auto &SrcOp = InstToErase->getOperand(1);
2241 auto SrcReg = SrcOp.isReg() ? SrcOp.getReg() : Register();
2242 InstToErase->eraseFromParent();
2243 Changed = true;
2244 InstToErase = nullptr;
2245 if (!SrcReg || SrcReg.isPhysical())
2246 break;
2247 InstToErase = MRI->getVRegDef(SrcReg);
2248 if (!InstToErase || !TII->isFoldableCopy(*InstToErase))
2249 break;
2250 }
2251
2252 if (InstToErase && InstToErase->isRegSequence() &&
2253 MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2254 InstToErase->eraseFromParent();
2255 Changed = true;
2256 }
2257
2258 if (Changed)
2259 return true;
2260
2261 // Run this after foldInstOperand to avoid turning scalar additions into
2262 // vector additions when the result scalar result could just be folded into
2263 // the user(s).
2264 return OpToFold.isReg() &&
2265 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.getReg(), MI);
2266}
2267
2268// Clamp patterns are canonically selected to v_max_* instructions, so only
2269// handle them.
2270const MachineOperand *
2271SIFoldOperandsImpl::isClamp(const MachineInstr &MI) const {
2272 unsigned Op = MI.getOpcode();
2273 switch (Op) {
2274 case AMDGPU::V_MAX_F32_e64:
2275 case AMDGPU::V_MAX_F16_e64:
2276 case AMDGPU::V_MAX_F16_t16_e64:
2277 case AMDGPU::V_MAX_F16_fake16_e64:
2278 case AMDGPU::V_MAX_F64_e64:
2279 case AMDGPU::V_MAX_NUM_F64_e64:
2280 case AMDGPU::V_PK_MAX_F16:
2281 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2282 case AMDGPU::V_PK_MAX_NUM_BF16: {
2283 if (MI.mayRaiseFPException())
2284 return nullptr;
2285
2286 if (!TII->getNamedOperand(MI, AMDGPU::OpName::clamp)->getImm())
2287 return nullptr;
2288
2289 // Make sure sources are identical.
2290 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2291 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2292 if (!Src0->isReg() || !Src1->isReg() ||
2293 Src0->getReg() != Src1->getReg() ||
2294 Src0->getSubReg() != Src1->getSubReg() ||
2295 Src0->getSubReg() != AMDGPU::NoSubRegister)
2296 return nullptr;
2297
2298 // Can't fold up if we have modifiers.
2299 if (TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2300 return nullptr;
2301
2302 unsigned Src0Mods
2303 = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)->getImm();
2304 unsigned Src1Mods
2305 = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers)->getImm();
2306
2307 // Having a 0 op_sel_hi would require swizzling the output in the source
2308 // instruction, which we can't do.
2309 unsigned UnsetMods =
2310 (Op == AMDGPU::V_PK_MAX_F16 || Op == AMDGPU::V_PK_MAX_NUM_BF16)
2312 : 0u;
2313 if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
2314 return nullptr;
2315 return Src0;
2316 }
2317 default:
2318 return nullptr;
2319 }
2320}
2321
2322// FIXME: Clamp for v_mad_mixhi_f16 handled during isel.
2323bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &MI) {
2324 const MachineOperand *ClampSrc = isClamp(MI);
2325 if (!ClampSrc || !MRI->hasOneNonDBGUser(ClampSrc->getReg()))
2326 return false;
2327
2328 if (!ClampSrc->getReg().isVirtual())
2329 return false;
2330
2331 // Look through COPY. COPY only observed with True16.
2332 Register DefSrcReg = TRI->lookThruCopyLike(ClampSrc->getReg(), MRI);
2333 MachineInstr *Def =
2334 MRI->getVRegDef(DefSrcReg.isVirtual() ? DefSrcReg : ClampSrc->getReg());
2335
2336 // The type of clamp must be compatible.
2337 if (!SIInstrInfo::hasSameClamp(*Def, MI))
2338 return false;
2339
2340 if (Def->mayRaiseFPException())
2341 return false;
2342
2343 MachineOperand *DefClamp = TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2344 if (!DefClamp)
2345 return false;
2346
2347 LLVM_DEBUG(dbgs() << "Folding clamp " << *DefClamp << " into " << *Def);
2348
2349 // Clamp is applied after omod, so it is OK if omod is set.
2350 DefClamp->setImm(1);
2351
2352 Register DefReg = Def->getOperand(0).getReg();
2353 Register MIDstReg = MI.getOperand(0).getReg();
2354 if (TRI->isSGPRReg(*MRI, DefReg)) {
2355 // Pseudo scalar instructions have a SGPR for dst and clamp is a v_max*
2356 // instruction with a VGPR dst.
2357 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY),
2358 MIDstReg)
2359 .addReg(DefReg);
2360 } else {
2361 MRI->replaceRegWith(MIDstReg, DefReg);
2362 }
2363 MI.eraseFromParent();
2364
2365 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2366 // instruction, so we might as well convert it to the more flexible VOP3-only
2367 // mad/fma form.
2368 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2369 Def->eraseFromParent();
2370
2371 return true;
2372}
2373
2374static int getOModValue(unsigned Opc, int64_t Val) {
2375 switch (Opc) {
2376 case AMDGPU::V_MUL_F64_e64:
2377 case AMDGPU::V_MUL_F64_pseudo_e64: {
2378 switch (Val) {
2379 case 0x3fe0000000000000: // 0.5
2380 return SIOutMods::DIV2;
2381 case 0x4000000000000000: // 2.0
2382 return SIOutMods::MUL2;
2383 case 0x4010000000000000: // 4.0
2384 return SIOutMods::MUL4;
2385 default:
2386 return SIOutMods::NONE;
2387 }
2388 }
2389 case AMDGPU::V_MUL_F32_e64: {
2390 switch (static_cast<uint32_t>(Val)) {
2391 case 0x3f000000: // 0.5
2392 return SIOutMods::DIV2;
2393 case 0x40000000: // 2.0
2394 return SIOutMods::MUL2;
2395 case 0x40800000: // 4.0
2396 return SIOutMods::MUL4;
2397 default:
2398 return SIOutMods::NONE;
2399 }
2400 }
2401 case AMDGPU::V_MUL_F16_e64:
2402 case AMDGPU::V_MUL_F16_t16_e64:
2403 case AMDGPU::V_MUL_F16_fake16_e64: {
2404 switch (static_cast<uint16_t>(Val)) {
2405 case 0x3800: // 0.5
2406 return SIOutMods::DIV2;
2407 case 0x4000: // 2.0
2408 return SIOutMods::MUL2;
2409 case 0x4400: // 4.0
2410 return SIOutMods::MUL4;
2411 default:
2412 return SIOutMods::NONE;
2413 }
2414 }
2415 case AMDGPU::V_PK_MUL_BF16: {
2416 switch (static_cast<uint16_t>(Val)) {
2417 case 0x3F00: // 0.5 in BF16
2418 return SIOutMods::DIV2;
2419 case 0x4000: // 2.0 in BF16
2420 return SIOutMods::MUL2;
2421 case 0x4080: // 4.0 in BF16
2422 return SIOutMods::MUL4;
2423 default:
2424 return SIOutMods::NONE;
2425 }
2426 }
2427 default:
2428 llvm_unreachable("invalid mul opcode");
2429 }
2430}
2431
2432// FIXME: Does this really not support denormals with f16?
2433// FIXME: Does this need to check IEEE mode bit? SNaNs are generally not
2434// handled, so will anything other than that break?
2435std::pair<const MachineOperand *, int>
2436SIFoldOperandsImpl::isOMod(const MachineInstr &MI) const {
2437 unsigned Op = MI.getOpcode();
2438 switch (Op) {
2439 case AMDGPU::V_MUL_F64_e64:
2440 case AMDGPU::V_MUL_F64_pseudo_e64:
2441 case AMDGPU::V_MUL_F32_e64:
2442 case AMDGPU::V_MUL_F16_t16_e64:
2443 case AMDGPU::V_MUL_F16_fake16_e64:
2444 case AMDGPU::V_MUL_F16_e64: {
2445 // If output denormals are enabled, omod is ignored.
2446 if ((Op == AMDGPU::V_MUL_F32_e64 &&
2448 ((Op == AMDGPU::V_MUL_F64_e64 || Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2449 Op == AMDGPU::V_MUL_F16_e64 || Op == AMDGPU::V_MUL_F16_t16_e64 ||
2450 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2453 MI.mayRaiseFPException())
2454 return {nullptr, SIOutMods::NONE};
2455
2456 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2457 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2458
2459 // If there is an immediate operand, it must be Src1
2460 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
2461 if (!Src1Imm)
2462 return {nullptr, SIOutMods::NONE};
2463
2464 int OMod = getOModValue(Op, *Src1Imm);
2465 if (OMod == SIOutMods::NONE ||
2466 TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
2467 TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) ||
2468 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2469 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2470 return {nullptr, SIOutMods::NONE};
2471
2472 return {Src0, OMod};
2473 }
2474 case AMDGPU::V_ADD_F64_e64:
2475 case AMDGPU::V_ADD_F64_pseudo_e64:
2476 case AMDGPU::V_ADD_F32_e64:
2477 case AMDGPU::V_ADD_F16_e64:
2478 case AMDGPU::V_ADD_F16_t16_e64:
2479 case AMDGPU::V_ADD_F16_fake16_e64: {
2480 // If output denormals are enabled, omod is ignored.
2481 if ((Op == AMDGPU::V_ADD_F32_e64 &&
2483 ((Op == AMDGPU::V_ADD_F64_e64 || Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2484 Op == AMDGPU::V_ADD_F16_e64 || Op == AMDGPU::V_ADD_F16_t16_e64 ||
2485 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2487 return {nullptr, SIOutMods::NONE};
2488
2489 // Look through the DAGCombiner canonicalization fmul x, 2 -> fadd x, x
2490 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2491 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2492
2493 if (Src0->isReg() && Src1->isReg() && Src0->getReg() == Src1->getReg() &&
2494 Src0->getSubReg() == Src1->getSubReg() &&
2495 !TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) &&
2496 !TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) &&
2497 !TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) &&
2498 !TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2499 return {Src0, SIOutMods::MUL2};
2500
2501 return {nullptr, SIOutMods::NONE};
2502 }
2503 case AMDGPU::V_PK_MUL_BF16: {
2504 // OMOD folding for BF16 packed multiply. bf16 has no denormal mode of its
2505 // own; it follows the default ("denormal-fp-math") mode, which is the same
2506 // field as f64/f16.
2508 MI.mayRaiseFPException())
2509 return {nullptr, SIOutMods::NONE};
2510
2511 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2512 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2513
2514 // If there is an immediate operand, it must be Src1
2515 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
2516 if (!Src1Imm)
2517 return {nullptr, SIOutMods::NONE};
2518
2519 int OMod = getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2520 if (OMod == SIOutMods::NONE)
2521 return {nullptr, SIOutMods::NONE};
2522
2523 // Modifiers other than op_sel_hi block OMOD folding
2524 const MachineOperand *Src0Mods =
2525 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
2526 const MachineOperand *Src1Mods =
2527 TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
2528 if ((Src0Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2529 (Src1Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2530 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2531 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2532 return {nullptr, SIOutMods::NONE};
2533
2534 return {Src0, OMod};
2535 }
2536 case AMDGPU::V_PK_ADD_BF16: {
2537 // OMOD folding for BF16 packed add: x + x -> x * 2. See the bf16 denormal
2538 // mode note in the V_PK_MUL_BF16 case above.
2540 return {nullptr, SIOutMods::NONE};
2541
2542 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2543 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2544
2545 if (!Src0->isReg() || !Src1->isReg() || Src0->getReg() != Src1->getReg() ||
2546 Src0->getSubReg() != Src1->getSubReg())
2547 return {nullptr, SIOutMods::NONE};
2548
2549 // Modifiers other than op_sel_hi block OMOD folding
2550 const MachineOperand *Src0Mods =
2551 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
2552 const MachineOperand *Src1Mods =
2553 TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
2554 if ((Src0Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2555 (Src1Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2556 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2557 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2558 return {nullptr, SIOutMods::NONE};
2559
2560 return {Src0, SIOutMods::MUL2};
2561 }
2562 default:
2563 return {nullptr, SIOutMods::NONE};
2564 }
2565}
2566
2567// FIXME: Does this need to check IEEE bit on function?
2568bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &MI) {
2569 const MachineOperand *RegOp;
2570 int OMod;
2571 std::tie(RegOp, OMod) = isOMod(MI);
2572 if (OMod == SIOutMods::NONE || !RegOp->isReg() ||
2573 RegOp->getSubReg() != AMDGPU::NoSubRegister ||
2574 !MRI->hasOneNonDBGUser(RegOp->getReg()))
2575 return false;
2576
2577 MachineInstr *Def = MRI->getVRegDef(RegOp->getReg());
2578 Register OModSrcReg = Def->getOperand(0).getReg();
2579
2580 // In real-true16 mode, vgpr_16 results are packed into vgpr_32 via
2581 // REG_SEQUENCE. Look through it to find the actual instruction.
2582 if (Def->isRegSequence() && Def->getNumOperands() == 5 &&
2583 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2584 // Only look through if the high 16 bits are undefined
2585 bool CanLookThrough = true;
2586 MachineInstr *Hi16Def = MRI->getVRegDef(Def->getOperand(3).getReg());
2587 if (!Hi16Def || !Hi16Def->isImplicitDef())
2588 CanLookThrough = false;
2589
2590 if (CanLookThrough) {
2591 Register SrcReg = Def->getOperand(1).getReg();
2592 if (!MRI->hasOneNonDBGUse(SrcReg))
2593 return false;
2594
2595 Def = MRI->getVRegDef(SrcReg);
2596 if (!Def)
2597 return false;
2598 }
2599 }
2600
2601 MachineOperand *DefOMod = TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2602 if (!DefOMod || DefOMod->getImm() != SIOutMods::NONE)
2603 return false;
2604
2605 if (Def->mayRaiseFPException())
2606 return false;
2607
2608 // Clamp is applied after omod. If the source already has clamp set, don't
2609 // fold it.
2610 if (TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2611 return false;
2612
2613 LLVM_DEBUG(dbgs() << "Folding omod " << MI << " into " << *Def);
2614
2615 DefOMod->setImm(OMod);
2616 MRI->replaceRegWith(MI.getOperand(0).getReg(), OModSrcReg);
2617 // Kill flags can be wrong if we replaced a def inside a loop with a def
2618 // outside the loop.
2619 MRI->clearKillFlags(OModSrcReg);
2620 MI.eraseFromParent();
2621
2622 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2623 // instruction, so we might as well convert it to the more flexible VOP3-only
2624 // mad/fma form.
2625 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2626 Def->eraseFromParent();
2627
2628 return true;
2629}
2630
2631// Try to optimize SGPR reg sequences that are splat <s, s> or <s, s, s, s>
2632// where all uses are PackedSingleSGPR64BitInst, replacing with <s, undef, ...>
2633bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &MI) {
2634 assert(MI.isRegSequence());
2635
2636 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2637 return false;
2638
2639 Register Reg = MI.getOperand(0).getReg();
2640
2641 // Only optimize 128-bit SGPR register sequences
2642 const TargetRegisterClass *RegClass = MRI->getRegClass(Reg);
2643 if (!TRI->isSGPRClass(RegClass) || TRI->getRegSizeInBits(*RegClass) != 128)
2644 return false;
2645
2647 if (!getRegSeqInit(Defs, Reg))
2648 return false;
2649
2650 // Check if this is a splat pattern
2651 if (Defs.size() <= 1)
2652 return false;
2653
2654 const auto &[FirstOp, _] = Defs.front();
2655 if (!FirstOp->isReg())
2656 return false;
2657
2658 Register FirstReg = FirstOp->getReg();
2659 unsigned FirstSubReg = FirstOp->getSubReg();
2660
2661 const TargetRegisterClass *FirstRegClass = MRI->getRegClass(FirstReg);
2662 if (!TRI->isSGPRClass(FirstRegClass))
2663 return false;
2664
2665 // Check remaining elements match first
2666 if (!llvm::all_of(llvm::drop_begin(Defs), [&](const auto &Def) {
2667 const auto &[Op, _] = Def;
2668 return Op->isReg() && Op->getReg() == FirstReg &&
2669 Op->getSubReg() == FirstSubReg;
2670 }))
2671 return false;
2672
2673 // Check if all uses are isSingleSGPRReadInst
2674 for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
2676 return false;
2677 }
2678
2679 // Create new reg sequence with <s, undef, undef, ...>
2680 Register NewDst = MRI->createVirtualRegister(RegClass);
2681 MachineInstrBuilder RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2682 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2683
2684 // Add the first operand
2685 FirstOp->setIsKill(false);
2686 RS.add(*FirstOp);
2687 RS.addImm(Defs[0].second);
2688
2689 // Add undef for remaining lanes
2690 // Create an undef virtual register for the same register class
2691 Register UndefReg = MRI->createVirtualRegister(FirstRegClass);
2692 for (unsigned i = 1; i < Defs.size(); ++i) {
2693 RS.addReg(UndefReg, RegState::Undef);
2694 RS.addImm(Defs[i].second);
2695 }
2696
2697 // Replace all uses
2698 MRI->replaceRegWith(Reg, NewDst);
2699
2700 LLVM_DEBUG(dbgs() << "Folded splat SGPR reg_sequence: " << MI << " into "
2701 << *RS);
2702
2703 MI.eraseFromParent();
2704 return true;
2705}
2706
2707// Try to fold a reg_sequence with vgpr output and agpr inputs into an
2708// instruction which can take an agpr. So far that means a store.
2709bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &MI) {
2710 assert(MI.isRegSequence());
2711
2712 // Try to optimize SGPR splat sequences first
2713 if (tryFoldSGPRSplatRegSequence(MI))
2714 return true;
2715
2716 auto Reg = MI.getOperand(0).getReg();
2717
2718 if (!ST->hasGFX90AInsts() || !TRI->isVGPR(*MRI, Reg) ||
2719 !MRI->hasOneNonDBGUse(Reg))
2720 return false;
2721
2723 if (!getRegSeqInit(Defs, Reg))
2724 return false;
2725
2726 for (auto &[Op, SubIdx] : Defs) {
2727 if (!Op->isReg())
2728 return false;
2729 if (TRI->isAGPR(*MRI, Op->getReg()))
2730 continue;
2731 // Maybe this is a COPY from AREG
2732 const MachineInstr *SubDef = MRI->getVRegDef(Op->getReg());
2733 if (!SubDef || !SubDef->isCopy() || SubDef->getOperand(1).getSubReg())
2734 return false;
2735 if (!TRI->isAGPR(*MRI, SubDef->getOperand(1).getReg()))
2736 return false;
2737 }
2738
2739 MachineOperand *Op = &*MRI->use_nodbg_begin(Reg);
2740 MachineInstr *UseMI = Op->getParent();
2741 while (UseMI->isCopy() && !Op->getSubReg()) {
2742 Reg = UseMI->getOperand(0).getReg();
2743 if (!TRI->isVGPR(*MRI, Reg) || !MRI->hasOneNonDBGUse(Reg))
2744 return false;
2745 Op = &*MRI->use_nodbg_begin(Reg);
2746 UseMI = Op->getParent();
2747 }
2748
2749 if (Op->getSubReg())
2750 return false;
2751
2752 unsigned OpIdx = Op - &UseMI->getOperand(0);
2753 const MCInstrDesc &InstDesc = UseMI->getDesc();
2754 const TargetRegisterClass *OpRC = TII->getRegClass(InstDesc, OpIdx);
2755 if (!OpRC || !TRI->isVectorSuperClass(OpRC))
2756 return false;
2757
2758 const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg));
2759 auto Dst = MRI->createVirtualRegister(NewDstRC);
2760 auto RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2761 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2762
2763 for (auto &[Def, SubIdx] : Defs) {
2764 Def->setIsKill(false);
2765 if (TRI->isAGPR(*MRI, Def->getReg())) {
2766 RS.add(*Def);
2767 } else { // This is a copy
2768 MachineInstr *SubDef = MRI->getVRegDef(Def->getReg());
2769 SubDef->getOperand(1).setIsKill(false);
2770 RS.addReg(SubDef->getOperand(1).getReg(), {}, Def->getSubReg());
2771 }
2772 RS.addImm(SubIdx);
2773 }
2774
2775 Op->setReg(Dst);
2776 if (!TII->isOperandLegal(*UseMI, OpIdx, Op)) {
2777 Op->setReg(Reg);
2778 RS->eraseFromParent();
2779 return false;
2780 }
2781
2782 LLVM_DEBUG(dbgs() << "Folded " << *RS << " into " << *UseMI);
2783
2784 // Erase the REG_SEQUENCE eagerly, unless we followed a chain of COPY users,
2785 // in which case we can erase them all later in runOnMachineFunction.
2786 if (MRI->use_nodbg_empty(MI.getOperand(0).getReg()))
2787 MI.eraseFromParent();
2788 return true;
2789}
2790
2791/// Checks whether \p Copy is a AGPR -> VGPR copy. Returns `true` on success and
2792/// stores the AGPR register in \p OutReg and the subreg in \p OutSubReg
2793static bool isAGPRCopy(const SIRegisterInfo &TRI,
2794 const MachineRegisterInfo &MRI, const MachineInstr &Copy,
2795 Register &OutReg, unsigned &OutSubReg) {
2796 assert(Copy.isCopy());
2797
2798 const MachineOperand &CopySrc = Copy.getOperand(1);
2799 Register CopySrcReg = CopySrc.getReg();
2800 if (!CopySrcReg.isVirtual())
2801 return false;
2802
2803 // Common case: copy from AGPR directly, e.g.
2804 // %1:vgpr_32 = COPY %0:agpr_32
2805 if (TRI.isAGPR(MRI, CopySrcReg)) {
2806 OutReg = CopySrcReg;
2807 OutSubReg = CopySrc.getSubReg();
2808 return true;
2809 }
2810
2811 // Sometimes it can also involve two copies, e.g.
2812 // %1:vgpr_256 = COPY %0:agpr_256
2813 // %2:vgpr_32 = COPY %1:vgpr_256.sub0
2814 const MachineInstr *CopySrcDef = MRI.getVRegDef(CopySrcReg);
2815 if (!CopySrcDef || !CopySrcDef->isCopy())
2816 return false;
2817
2818 const MachineOperand &OtherCopySrc = CopySrcDef->getOperand(1);
2819 Register OtherCopySrcReg = OtherCopySrc.getReg();
2820 if (!OtherCopySrcReg.isVirtual() ||
2821 CopySrcDef->getOperand(0).getSubReg() != AMDGPU::NoSubRegister ||
2822 OtherCopySrc.getSubReg() != AMDGPU::NoSubRegister ||
2823 !TRI.isAGPR(MRI, OtherCopySrcReg))
2824 return false;
2825
2826 OutReg = OtherCopySrcReg;
2827 OutSubReg = CopySrc.getSubReg();
2828 return true;
2829}
2830
2831// Try to hoist an AGPR to VGPR copy across a PHI.
2832// This should allow folding of an AGPR into a consumer which may support it.
2833//
2834// Example 1: LCSSA PHI
2835// loop:
2836// %1:vreg = COPY %0:areg
2837// exit:
2838// %2:vreg = PHI %1:vreg, %loop
2839// =>
2840// loop:
2841// exit:
2842// %1:areg = PHI %0:areg, %loop
2843// %2:vreg = COPY %1:areg
2844//
2845// Example 2: PHI with multiple incoming values:
2846// entry:
2847// %1:vreg = GLOBAL_LOAD(..)
2848// loop:
2849// %2:vreg = PHI %1:vreg, %entry, %5:vreg, %loop
2850// %3:areg = COPY %2:vreg
2851// %4:areg = (instr using %3:areg)
2852// %5:vreg = COPY %4:areg
2853// =>
2854// entry:
2855// %1:vreg = GLOBAL_LOAD(..)
2856// %2:areg = COPY %1:vreg
2857// loop:
2858// %3:areg = PHI %2:areg, %entry, %X:areg,
2859// %4:areg = (instr using %3:areg)
2860bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &PHI) {
2861 assert(PHI.isPHI());
2862
2863 Register PhiOut = PHI.getOperand(0).getReg();
2864 if (!TRI->isVGPR(*MRI, PhiOut))
2865 return false;
2866
2867 // Iterate once over all incoming values of the PHI to check if this PHI is
2868 // eligible, and determine the exact AGPR RC we'll target.
2869 const TargetRegisterClass *ARC = nullptr;
2870 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2871 MachineOperand &MO = PHI.getOperand(K);
2872 MachineInstr *Copy = MRI->getVRegDef(MO.getReg());
2873 if (!Copy || !Copy->isCopy())
2874 continue;
2875
2876 Register AGPRSrc;
2877 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2878 if (!isAGPRCopy(*TRI, *MRI, *Copy, AGPRSrc, AGPRRegMask))
2879 continue;
2880
2881 const TargetRegisterClass *CopyInRC = MRI->getRegClass(AGPRSrc);
2882 if (const auto *SubRC = TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2883 CopyInRC = SubRC;
2884
2885 if (ARC && !ARC->hasSubClassEq(CopyInRC))
2886 return false;
2887 ARC = CopyInRC;
2888 }
2889
2890 if (!ARC)
2891 return false;
2892
2893 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2894
2895 // Rewrite the PHI's incoming values to ARC.
2896 LLVM_DEBUG(dbgs() << "Folding AGPR copies into: " << PHI);
2897 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2898 MachineOperand &MO = PHI.getOperand(K);
2899 Register Reg = MO.getReg();
2900
2902 MachineBasicBlock *InsertMBB = nullptr;
2903
2904 // Look at the def of Reg, ignoring all copies.
2905 unsigned CopyOpc = AMDGPU::COPY;
2906 if (MachineInstr *Def = MRI->getVRegDef(Reg)) {
2907
2908 // Look at pre-existing COPY instructions from ARC: Steal the operand. If
2909 // the copy was single-use, it will be removed by DCE later.
2910 if (Def->isCopy()) {
2911 Register AGPRSrc;
2912 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2913 if (isAGPRCopy(*TRI, *MRI, *Def, AGPRSrc, AGPRSubReg)) {
2914 MO.setReg(AGPRSrc);
2915 MO.setSubReg(AGPRSubReg);
2916 continue;
2917 }
2918
2919 // If this is a multi-use SGPR -> VGPR copy, use V_ACCVGPR_WRITE on
2920 // GFX908 directly instead of a COPY. Otherwise, SIFoldOperand may try
2921 // to fold the sgpr -> vgpr -> agpr copy into a sgpr -> agpr copy which
2922 // is unlikely to be profitable.
2923 //
2924 // Note that V_ACCVGPR_WRITE is only used for AGPR_32.
2925 MachineOperand &CopyIn = Def->getOperand(1);
2926 if (IsAGPR32 && !ST->hasGFX90AInsts() && !MRI->hasOneNonDBGUse(Reg) &&
2927 TRI->isSGPRReg(*MRI, CopyIn.getReg()))
2928 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2929 }
2930
2931 InsertMBB = Def->getParent();
2932 InsertPt = InsertMBB->SkipPHIsLabelsAndDebug(++Def->getIterator());
2933 } else {
2934 InsertMBB = PHI.getOperand(MO.getOperandNo() + 1).getMBB();
2935 InsertPt = InsertMBB->getFirstTerminator();
2936 }
2937
2938 Register NewReg = MRI->createVirtualRegister(ARC);
2939 MachineInstr *MI = BuildMI(*InsertMBB, InsertPt, PHI.getDebugLoc(),
2940 TII->get(CopyOpc), NewReg)
2941 .addReg(Reg);
2942 MO.setReg(NewReg);
2943
2944 (void)MI;
2945 LLVM_DEBUG(dbgs() << " Created COPY: " << *MI);
2946 }
2947
2948 // Replace the PHI's result with a new register.
2949 Register NewReg = MRI->createVirtualRegister(ARC);
2950 PHI.getOperand(0).setReg(NewReg);
2951
2952 // COPY that new register back to the original PhiOut register. This COPY will
2953 // usually be folded out later.
2954 MachineBasicBlock *MBB = PHI.getParent();
2955 BuildMI(*MBB, MBB->getFirstNonPHI(), PHI.getDebugLoc(),
2956 TII->get(AMDGPU::COPY), PhiOut)
2957 .addReg(NewReg);
2958
2959 LLVM_DEBUG(dbgs() << " Done: Folded " << PHI);
2960 return true;
2961}
2962
2963// Attempt to convert VGPR load to an AGPR load.
2964bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &MI) {
2965 assert(MI.mayLoad());
2966 if (!ST->hasGFX90AInsts() || MI.getNumExplicitDefs() != 1)
2967 return false;
2968
2969 MachineOperand &Def = MI.getOperand(0);
2970 if (!Def.isDef())
2971 return false;
2972
2973 Register DefReg = Def.getReg();
2974
2975 if (DefReg.isPhysical() || !TRI->isVGPR(*MRI, DefReg))
2976 return false;
2977
2980 SmallVector<Register, 8> MoveRegs;
2981
2982 if (Users.empty())
2983 return false;
2984
2985 // Check that all uses a copy to an agpr or a reg_sequence producing an agpr.
2986 while (!Users.empty()) {
2987 const MachineInstr *I = Users.pop_back_val();
2988 if (!I->isCopy() && !I->isRegSequence())
2989 return false;
2990 Register DstReg = I->getOperand(0).getReg();
2991 // Physical registers may have more than one instruction definitions
2992 if (DstReg.isPhysical())
2993 return false;
2994 if (TRI->isAGPR(*MRI, DstReg))
2995 continue;
2996 MoveRegs.push_back(DstReg);
2997 for (const MachineInstr &U : MRI->use_nodbg_instructions(DstReg))
2998 Users.push_back(&U);
2999 }
3000
3001 const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
3002 MRI->setRegClass(DefReg, TRI->getEquivalentAGPRClass(RC));
3003 if (!TII->isOperandLegal(MI, 0, &Def)) {
3004 MRI->setRegClass(DefReg, RC);
3005 return false;
3006 }
3007
3008 while (!MoveRegs.empty()) {
3009 Register Reg = MoveRegs.pop_back_val();
3010 MRI->setRegClass(Reg, TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)));
3011 }
3012
3013 LLVM_DEBUG(dbgs() << "Folded " << MI);
3014
3015 return true;
3016}
3017
3018// tryFoldPhiAGPR will aggressively try to create AGPR PHIs.
3019// For GFX90A and later, this is pretty much always a good thing, but for GFX908
3020// there's cases where it can create a lot more AGPR-AGPR copies, which are
3021// expensive on this architecture due to the lack of V_ACCVGPR_MOV.
3022//
3023// This function looks at all AGPR PHIs in a basic block and collects their
3024// operands. Then, it checks for register that are used more than once across
3025// all PHIs and caches them in a VGPR. This prevents ExpandPostRAPseudo from
3026// having to create one VGPR temporary per use, which can get very messy if
3027// these PHIs come from a broken-up large PHI (e.g. 32 AGPR phis, one per vector
3028// element).
3029//
3030// Example
3031// a:
3032// %in:agpr_256 = COPY %foo:vgpr_256
3033// c:
3034// %x:agpr_32 = ..
3035// b:
3036// %0:areg = PHI %in.sub0:agpr_32, %a, %x, %c
3037// %1:areg = PHI %in.sub0:agpr_32, %a, %y, %c
3038// %2:areg = PHI %in.sub0:agpr_32, %a, %z, %c
3039// =>
3040// a:
3041// %in:agpr_256 = COPY %foo:vgpr_256
3042// %tmp:vgpr_32 = V_ACCVGPR_READ_B32_e64 %in.sub0:agpr_32
3043// %tmp_agpr:agpr_32 = COPY %tmp
3044// c:
3045// %x:agpr_32 = ..
3046// b:
3047// %0:areg = PHI %tmp_agpr, %a, %x, %c
3048// %1:areg = PHI %tmp_agpr, %a, %y, %c
3049// %2:areg = PHI %tmp_agpr, %a, %z, %c
3050bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &MBB) {
3051 // This is only really needed on GFX908 where AGPR-AGPR copies are
3052 // unreasonably difficult.
3053 if (ST->hasGFX90AInsts())
3054 return false;
3055
3056 // Look at all AGPR Phis and collect the register + subregister used.
3057 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3058 RegToMO;
3059
3060 for (auto &MI : MBB) {
3061 if (!MI.isPHI())
3062 break;
3063
3064 if (!TRI->isAGPR(*MRI, MI.getOperand(0).getReg()))
3065 continue;
3066
3067 for (unsigned K = 1; K < MI.getNumOperands(); K += 2) {
3068 MachineOperand &PhiMO = MI.getOperand(K);
3069 if (!PhiMO.getSubReg())
3070 continue;
3071 RegToMO[{PhiMO.getReg(), PhiMO.getSubReg()}].push_back(&PhiMO);
3072 }
3073 }
3074
3075 // For all (Reg, SubReg) pair that are used more than once, cache the value in
3076 // a VGPR.
3077 bool Changed = false;
3078 for (const auto &[Entry, MOs] : RegToMO) {
3079 if (MOs.size() == 1)
3080 continue;
3081
3082 const auto [Reg, SubReg] = Entry;
3083 MachineInstr *Def = MRI->getVRegDef(Reg);
3084 MachineBasicBlock *DefMBB = Def->getParent();
3085
3086 // Create a copy in a VGPR using V_ACCVGPR_READ_B32_e64 so it's not folded
3087 // out.
3088 const TargetRegisterClass *ARC = getRegOpRC(*MRI, *TRI, *MOs.front());
3089 Register TempVGPR =
3090 MRI->createVirtualRegister(TRI->getEquivalentVGPRClass(ARC));
3091 MachineInstr *VGPRCopy =
3092 BuildMI(*DefMBB, ++Def->getIterator(), Def->getDebugLoc(),
3093 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3094 .addReg(Reg, /* flags */ {}, SubReg);
3095
3096 // Copy back to an AGPR and use that instead of the AGPR subreg in all MOs.
3097 Register TempAGPR = MRI->createVirtualRegister(ARC);
3098 BuildMI(*DefMBB, ++VGPRCopy->getIterator(), Def->getDebugLoc(),
3099 TII->get(AMDGPU::COPY), TempAGPR)
3100 .addReg(TempVGPR);
3101
3102 LLVM_DEBUG(dbgs() << "Caching AGPR into VGPR: " << *VGPRCopy);
3103 for (MachineOperand *MO : MOs) {
3104 MO->setReg(TempAGPR);
3105 MO->setSubReg(AMDGPU::NoSubRegister);
3106 LLVM_DEBUG(dbgs() << " Changed PHI Operand: " << *MO << "\n");
3107 }
3108
3109 Changed = true;
3110 }
3111
3112 return Changed;
3113}
3114
3115bool SIFoldOperandsImpl::run(MachineFunction &MF, const MachineLoopInfo *MLI) {
3116 this->MF = &MF;
3117 MRI = &MF.getRegInfo();
3118 ST = &MF.getSubtarget<GCNSubtarget>();
3119 TII = ST->getInstrInfo();
3120 TRI = &TII->getRegisterInfo();
3121 MFI = MF.getInfo<SIMachineFunctionInfo>();
3122 this->MLI = MLI;
3123
3124 // omod is ignored by hardware if IEEE bit is enabled. omod also does not
3125 // correctly handle signed zeros.
3126 //
3127 // FIXME: Also need to check strictfp
3128 bool IsIEEEMode = MFI->getMode().IEEE;
3129
3130 bool Changed = false;
3131 for (MachineBasicBlock *MBB : depth_first(&MF)) {
3132 MachineOperand *CurrentKnownM0Val = nullptr;
3133 for (auto &MI : make_early_inc_range(*MBB)) {
3134 Changed |= tryFoldCndMask(MI);
3135
3136 // PeepholeOptimizer may have folded an inline immediate directly onto an
3137 // instruction operand without materializing it into a register first.
3138 // Such an instruction is never reached through a def->use edge in
3139 // foldInstOperand, so try to constant fold it here.
3140 if (tryConstantFoldOp(&MI)) {
3141 Changed = true;
3142 continue;
3143 }
3144
3145 if (tryFoldRedundantAND(MI)) {
3146 Changed = true;
3147 continue;
3148 }
3149
3150 if (MI.isRegSequence() && tryFoldRegSequence(MI)) {
3151 Changed = true;
3152 continue;
3153 }
3154
3155 if (MI.isPHI() && tryFoldPhiAGPR(MI)) {
3156 Changed = true;
3157 continue;
3158 }
3159
3160 if (MI.mayLoad() && tryFoldLoad(MI)) {
3161 Changed = true;
3162 continue;
3163 }
3164
3165 if (TII->isFoldableCopy(MI)) {
3166 Changed |= tryFoldFoldableCopy(MI, CurrentKnownM0Val);
3167 continue;
3168 }
3169
3170 // Saw an unknown clobber of m0, so we no longer know what it is.
3171 if (CurrentKnownM0Val && MI.modifiesRegister(AMDGPU::M0, TRI))
3172 CurrentKnownM0Val = nullptr;
3173
3174 // TODO: Omod might be OK if there is NSZ only on the source
3175 // instruction, and not the omod multiply.
3176 if (IsIEEEMode || !MI.getFlag(MachineInstr::FmNsz) || !tryFoldOMod(MI))
3177 Changed |= tryFoldClamp(MI);
3178 }
3179
3180 Changed |= tryOptimizeAGPRPhis(*MBB);
3181 }
3182
3183 return Changed;
3184}
3185
3186PreservedAnalyses
3189 MFPropsModifier _(*this, MF);
3190
3191 const MachineLoopInfo *MLI = &MFAM.getResult<MachineLoopAnalysis>(MF);
3192 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
3193 if (!Changed) {
3194 return PreservedAnalyses::all();
3195 }
3197 PA.preserveSet<CFGAnalyses>();
3198 PA.preserve<MachineLoopAnalysis>();
3199 return PA;
3200}
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:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const SIInstrInfo * getInstrInfo() const override
bool hasDOTOpSelHazard() const
bool zeroesHigh16BitsOfDest(unsigned Opcode) const
Returns if the result of this instruction with a 16-bit result returned in a 32-bit register implicit...
const HexagonRegisterInfo & getRegisterInfo() const
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:446
@ OPERAND_REG_IMM_V2FP16
Definition SIDefines.h:439
@ OPERAND_REG_INLINE_C_FP64
Definition SIDefines.h:455
@ OPERAND_REG_INLINE_C_BF16
Definition SIDefines.h:452
@ OPERAND_REG_INLINE_C_V2BF16
Definition SIDefines.h:457
@ OPERAND_REG_IMM_V2INT64
Definition SIDefines.h:442
@ OPERAND_REG_IMM_V2INT16
Definition SIDefines.h:441
@ OPERAND_REG_IMM_BF16
Definition SIDefines.h:436
@ OPERAND_REG_IMM_V2BF16
Definition SIDefines.h:438
@ OPERAND_REG_INLINE_C_INT64
Definition SIDefines.h:451
@ OPERAND_REG_IMM_NOINLINE_V2FP16
Definition SIDefines.h:443
@ OPERAND_REG_INLINE_C_V2FP16
Definition SIDefines.h:458
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
Definition SIDefines.h:469
@ OPERAND_REG_INLINE_AC_FP32
Definition SIDefines.h:470
@ OPERAND_REG_INLINE_C_FP32
Definition SIDefines.h:454
@ OPERAND_REG_INLINE_C_INT32
Definition SIDefines.h:450
@ OPERAND_REG_INLINE_C_V2INT16
Definition SIDefines.h:456
@ OPERAND_REG_IMM_V2FP32
Definition SIDefines.h:445
@ OPERAND_REG_INLINE_AC_FP64
Definition SIDefines.h:471
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:239
constexpr bool isMAI(const T &...O)
Definition SIDefines.h:355
constexpr bool isSWMMAC(const T &...O)
Definition SIDefines.h:382
constexpr bool isVOP3P(const T &...O)
Definition SIDefines.h:242
constexpr bool isWMMA(const T &...O)
Definition SIDefines.h:370
constexpr bool isDOT(const T &...O)
Definition SIDefines.h:358
constexpr bool isPacked(const T &...O)
Definition SIDefines.h:340
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:315
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:1739
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool execMayBeModifiedBeforeUse(const MachineRegisterInfo &MRI, Register VReg, const MachineInstr &DefMI, const MachineInstr &UseMI)
Return false if EXEC is not changed between the def of VReg at DefMI and the use at UseMI.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Op::Description Desc
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createSIFoldOperandsLegacyPass()
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.