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