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 // (src0 << src1) + 0 -> src0 << src1
1724 if (Opc == AMDGPU::V_LSHL_ADD_U32_e64) {
1725 int DataIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
1726 int AddIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
1727 std::optional<int64_t> Addend =
1728 TII->getImmOrMaterializedImm(*MRI, MI->getOperand(AddIdx));
1729
1730 if (Addend && static_cast<uint32_t>(*Addend) == 0) {
1731 MachineOperand Data = MI->getOperand(DataIdx);
1732 MI->removeOperand(AddIdx);
1733 MI->removeOperand(DataIdx);
1734 MI->addOperand(*MF, Data);
1735 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::V_LSHLREV_B32_e64));
1736 return true;
1737 }
1738 }
1739
1740 int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
1741 if (Src0Idx == -1)
1742 return false;
1743
1744 MachineOperand *Src0 = &MI->getOperand(Src0Idx);
1745 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*MRI, *Src0);
1746
1747 if ((Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
1748 Opc == AMDGPU::S_NOT_B32) &&
1749 Src0Imm) {
1750 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1751 TII->mutateAndCleanupImplicit(
1752 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
1753 return true;
1754 }
1755
1756 int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
1757 if (Src1Idx == -1)
1758 return false;
1759
1760 MachineOperand *Src1 = &MI->getOperand(Src1Idx);
1761 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
1762
1763 if (!Src0Imm && !Src1Imm)
1764 return false;
1765
1766 // and k0, k1 -> v_mov_b32 (k0 & k1)
1767 // or k0, k1 -> v_mov_b32 (k0 | k1)
1768 // xor k0, k1 -> v_mov_b32 (k0 ^ k1)
1769 if (Src0Imm && Src1Imm) {
1770 int32_t NewImm;
1771 if (!evalBinaryInstruction(Opc, NewImm, *Src0Imm, *Src1Imm))
1772 return false;
1773
1774 bool IsSGPR = TRI->isSGPRReg(*MRI, MI->getOperand(0).getReg());
1775
1776 // Be careful to change the right operand, src0 may belong to a different
1777 // instruction.
1778 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1779 MI->removeOperand(Src1Idx);
1780 TII->mutateAndCleanupImplicit(*MI, TII->get(getMovOpc(IsSGPR)));
1781 return true;
1782 }
1783
1784 // S_SUB_* is not commutable, so handle it before the commutability gate.
1785 // Only `x - 0 -> copy x` is valid; `0 - x` is a negation, not a copy.
1786 if (Opc == AMDGPU::S_SUB_I32 || Opc == AMDGPU::S_SUB_U32) {
1787 if (Src1Imm && static_cast<int32_t>(*Src1Imm) == 0) {
1788 // y = sub x, 0 => y = copy x
1789 MI->removeOperand(Src1Idx);
1790 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1791 return true;
1792 }
1793 return false;
1794 }
1795
1796 if (!MI->isCommutable())
1797 return false;
1798
1799 if (Src0Imm && !Src1Imm) {
1800 std::swap(Src0, Src1);
1801 std::swap(Src0Idx, Src1Idx);
1802 std::swap(Src0Imm, Src1Imm);
1803 }
1804
1805 int32_t Src1Val = static_cast<int32_t>(*Src1Imm);
1806 if (Opc == AMDGPU::S_ADD_I32 || Opc == AMDGPU::S_ADD_U32) {
1807 if (Src1Val == 0) {
1808 // y = add x, 0 => y = copy x
1809 MI->removeOperand(Src1Idx);
1810 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1811 return true;
1812 }
1813 return false;
1814 }
1815
1816 if (Opc == AMDGPU::V_OR_B32_e64 ||
1817 Opc == AMDGPU::V_OR_B32_e32 ||
1818 Opc == AMDGPU::S_OR_B32) {
1819 if (Src1Val == 0) {
1820 // y = or x, 0 => y = copy x
1821 MI->removeOperand(Src1Idx);
1822 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1823 } else if (Src1Val == -1) {
1824 // y = or x, -1 => y = v_mov_b32 -1
1825 MI->removeOperand(Src0Idx);
1826 TII->mutateAndCleanupImplicit(
1827 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
1828 } else
1829 return false;
1830
1831 return true;
1832 }
1833
1834 if (Opc == AMDGPU::V_AND_B32_e64 || Opc == AMDGPU::V_AND_B32_e32 ||
1835 Opc == AMDGPU::S_AND_B32) {
1836 if (Src1Val == 0) {
1837 // y = and x, 0 => y = v_mov_b32 0
1838 MI->removeOperand(Src0Idx);
1839 TII->mutateAndCleanupImplicit(
1840 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
1841 } else if (Src1Val == -1) {
1842 // y = and x, -1 => y = copy x
1843 MI->removeOperand(Src1Idx);
1844 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1845 } else
1846 return false;
1847
1848 return true;
1849 }
1850
1851 if (Opc == AMDGPU::V_XOR_B32_e64 || Opc == AMDGPU::V_XOR_B32_e32 ||
1852 Opc == AMDGPU::S_XOR_B32) {
1853 if (Src1Val == 0) {
1854 // y = xor x, 0 => y = copy x
1855 MI->removeOperand(Src1Idx);
1856 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1857 return true;
1858 }
1859 }
1860
1861 return false;
1862}
1863
1864// Fold a select whose two sources are the same value into a copy or move.
1865bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &MI) const {
1866 unsigned Opc = MI.getOpcode();
1867 if (Opc != AMDGPU::V_CNDMASK_B32_e32 && Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1868 Opc != AMDGPU::S_CSELECT_B32 && Opc != AMDGPU::S_CSELECT_B64)
1869 return false;
1870
1871 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1872 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1873 if (!Src1->isIdenticalTo(*Src0)) {
1874 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
1875 if (!Src1Imm)
1876 return false;
1877
1878 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*MRI, *Src0);
1879 if (!Src0Imm || *Src0Imm != *Src1Imm)
1880 return false;
1881 }
1882
1883 int Src1ModIdx =
1884 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1_modifiers);
1885 int Src0ModIdx =
1886 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers);
1887 if ((Src1ModIdx != -1 && MI.getOperand(Src1ModIdx).getImm() != 0) ||
1888 (Src0ModIdx != -1 && MI.getOperand(Src0ModIdx).getImm() != 0))
1889 return false;
1890
1891 unsigned NewOpc;
1892 if (Src0->isReg()) {
1893 NewOpc = AMDGPU::COPY;
1894 } else {
1895 switch (Opc) {
1896 case AMDGPU::S_CSELECT_B32:
1897 NewOpc = AMDGPU::S_MOV_B32;
1898 break;
1899 case AMDGPU::S_CSELECT_B64:
1900 NewOpc = AMDGPU::S_MOV_B64;
1901 break;
1902 default:
1903 NewOpc = AMDGPU::V_MOV_B32_e32;
1904 break;
1905 }
1906 }
1907
1908 LLVM_DEBUG(dbgs() << "Folded " << MI << " into ");
1909 int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
1910 if (Src2Idx != -1)
1911 MI.removeOperand(Src2Idx);
1912 MI.removeOperand(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1));
1913 if (Src1ModIdx != -1)
1914 MI.removeOperand(Src1ModIdx);
1915 if (Src0ModIdx != -1)
1916 MI.removeOperand(Src0ModIdx);
1917 TII->mutateAndCleanupImplicit(MI, TII->get(NewOpc));
1918 LLVM_DEBUG(dbgs() << MI);
1919 return true;
1920}
1921
1922// Extract mask and register from an AND instruction.
1923// Immediate can be in operand 1 or 2.
1924std::optional<SIFoldOperandsImpl::ANDMaskResult>
1925SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI) const {
1926 unsigned Opc = AndMI.getOpcode();
1927 if (Opc != AMDGPU::V_AND_B32_e64 && Opc != AMDGPU::V_AND_B32_e32 &&
1928 Opc != AMDGPU::S_AND_B32)
1929 return std::nullopt;
1930
1931 std::optional<int64_t> MaskImm =
1932 TII->getImmOrMaterializedImm(*MRI, AndMI.getOperand(1));
1933 if (MaskImm && AndMI.getOperand(2).isReg())
1934 return ANDMaskResult{*MaskImm, AndMI.getOperand(2).getReg()};
1935
1936 MaskImm = TII->getImmOrMaterializedImm(*MRI, AndMI.getOperand(2));
1937 if (MaskImm && AndMI.getOperand(1).isReg())
1938 return ANDMaskResult{*MaskImm, AndMI.getOperand(1).getReg()};
1939
1940 return std::nullopt;
1941}
1942
1943// Operands of an op_sel instruction that are not present in the equivalent
1944// legacy instruction, in operand order.
1945static constexpr AMDGPU::OpName OpSelOnlyOpNames[] = {
1946 AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
1947 AMDGPU::OpName::src2_modifiers, AMDGPU::OpName::op_sel};
1948
1949// If MI is an op_sel instruction on GFX9 that does not use op_sel, return the
1950// opcode of the equivalent legacy instruction, which zeros the high 16 bits of
1951// the destination. Otherwise return 0.
1952static unsigned getZeroHi16LegacyOpcode(const GCNSubtarget &ST,
1953 const MachineInstr &MI) {
1954 if (ST.getGeneration() != AMDGPUSubtarget::GFX9)
1955 return 0;
1956
1957 unsigned LegacyOpc;
1958 switch (MI.getOpcode()) {
1959 case AMDGPU::V_MAD_U16_gfx9_e64:
1960 LegacyOpc = AMDGPU::V_MAD_U16_e64;
1961 break;
1962 case AMDGPU::V_MAD_I16_gfx9_e64:
1963 LegacyOpc = AMDGPU::V_MAD_I16_e64;
1964 break;
1965 default:
1966 return 0;
1967 }
1968
1969 for (AMDGPU::OpName OpName : OpSelOnlyOpNames) {
1970 if (MI.getOperand(AMDGPU::getNamedOperandIdx(MI.getOpcode(), OpName))
1971 .getImm() != 0)
1972 return 0;
1973 }
1974
1975 return LegacyOpc;
1976}
1977
1978// Eliminate redundant 32-bit AND operations by detecting when ChildMI's mask
1979// contains ParentMI's mask.
1980//
1981// For example:
1982// ParentMI: %1 = AND %0, 0x7fff
1983// ChildMI: %2 = AND %1, 0xffff
1984//
1985// This also handles cases where ParentMI implicitly zeros high bits (e.g., f16
1986// operations that write 16-bit results into 32-bit registers), making a
1987// subsequent AND with 0xffff redundant. On GFX9, ParentMI may be switched to a
1988// legacy opcode that zeros the high bits for this purpose.
1989bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI) const {
1990 // Ensure implicit defs (e.g., $scc) are not live.
1991 if (!ChildMI.allImplicitDefsAreDead())
1992 return false;
1993
1994 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1995 if (!ChildResult)
1996 return false;
1997
1998 if (!ChildResult->Reg.isVirtual())
1999 return false;
2000
2001 MachineInstr *ParentMI = MRI->getVRegDef(ChildResult->Reg);
2002 if (!ParentMI)
2003 return false;
2004
2005 int64_t ParentMask = 0;
2006 unsigned LegacyOpc = 0;
2007 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
2008 if (ParentResult) {
2009 // Parent is an AND - extract its mask.
2010 ParentMask = ParentResult->Mask;
2011 } else if (ST->zeroesHigh16BitsOfDest(ParentMI->getOpcode())) {
2012 // Parent instruction implicitly zeros high 16 bits.
2013 ParentMask = 0xffff;
2014 } else if ((LegacyOpc = getZeroHi16LegacyOpcode(*ST, *ParentMI))) {
2015 // Parent instruction can be switched to a legacy opcode that implicitly
2016 // zeros high 16 bits.
2017 ParentMask = 0xffff;
2018 } else {
2019 return false;
2020 }
2021
2022 // Check if ChildMI is not redundant.
2023 if ((ParentMask & ChildResult->Mask) != ParentMask)
2024 return false;
2025
2026 Register Dst = ChildMI.getOperand(0).getReg();
2027 Register Src = ChildResult->Reg;
2028
2029 // Src must be legal in every use of Dst. An S_AND_B32 parent with a
2030 // V_AND_B32 child defines Src in the scalar bank, and a use that requires a
2031 // VGPR does not accept it.
2032 if (!Dst.isVirtual() || !MRI->constrainRegClass(Src, MRI->getRegClass(Dst)))
2033 return false;
2034
2035 if (LegacyOpc) {
2036 unsigned Opc = ParentMI->getOpcode();
2037 for (AMDGPU::OpName OpName : reverse(OpSelOnlyOpNames))
2038 ParentMI->removeOperand(AMDGPU::getNamedOperandIdx(Opc, OpName));
2039 TII->mutateAndCleanupImplicit(*ParentMI, TII->get(LegacyOpc));
2040 }
2041
2042 MRI->replaceRegWith(Dst, Src);
2043
2044 ChildMI.eraseFromParent();
2045 return true;
2046}
2047
2048/// Remove S_AND of a lane mask with EXEC, when the lane mask is already known
2049/// to have 0 in the bits of all inactive lanes.
2050///
2051/// Instruction selection inserts these unconditionally because it has not
2052/// analysed what produced the lane mask.
2053bool SIFoldOperandsImpl::tryFoldAndExec(MachineInstr &MI) const {
2054 const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(*ST);
2055 if (MI.getOpcode() != LMC.AndOpc)
2056 return false;
2057
2058 // The AND is going to be removed, so nothing may use the SCC it defines.
2059 if (!MI.allImplicitDefsAreDead())
2060 return false;
2061
2062 // Find the EXEC operand, and the lane mask it is being ANDed with.
2063 unsigned ExecIdx = 0;
2064 for (unsigned I : {1u, 2u}) {
2065 const MachineOperand &MO = MI.getOperand(I);
2066 if (MO.isReg() && MO.getReg() == LMC.ExecReg)
2067 ExecIdx = I;
2068 }
2069 if (!ExecIdx)
2070 return false;
2071 MachineOperand &Src = MI.getOperand(3 - ExecIdx);
2072 if (!Src.isReg() || !Src.getReg().isVirtual() || Src.getSubReg())
2073 return false;
2074
2075 Register SrcReg = Src.getReg();
2076 if (!TII->isMaskedByExec(SrcReg, MI, *MRI))
2077 return false;
2078
2079 LLVM_DEBUG(dbgs() << "Folding redundant AND with EXEC: " << MI);
2080
2081 Register DstReg = MI.getOperand(0).getReg();
2082 if (DstReg.isVirtual()) {
2083 if (!MRI->constrainRegClass(SrcReg, MRI->getRegClass(DstReg)))
2084 return false;
2085 MRI->replaceRegWith(DstReg, SrcReg);
2086 } else {
2087 // A physical destination, e.g. the $vcc written by moveToVALU. Register
2088 // allocation will usually make this copy an identity copy.
2089 MachineBasicBlock *MBB = MI.getParent();
2090 BuildMI(*MBB, MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY), DstReg)
2091 .addReg(SrcReg);
2092 }
2093
2094 MI.eraseFromParent();
2095 return true;
2096}
2097
2098bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &MI,
2099 const FoldableDef &OpToFold) const {
2100 // We need mutate the operands of new mov instructions to add implicit
2101 // uses of EXEC, but adding them invalidates the use_iterator, so defer
2102 // this.
2103 SmallVector<MachineInstr *, 4> CopiesToReplace;
2105 MachineOperand &Dst = MI.getOperand(0);
2106 bool Changed = false;
2107
2110 for (auto *U : UsesToProcess) {
2111 MachineInstr *UseMI = U->getParent();
2112
2113 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*TRI, U->getSubReg());
2114 Changed |= foldOperand(SubOpToFold, UseMI, UseMI->getOperandNo(U), FoldList,
2115 CopiesToReplace);
2116 }
2117
2118 if (CopiesToReplace.empty() && FoldList.empty())
2119 return Changed;
2120
2121 // Make sure we add EXEC uses to any new v_mov instructions created.
2122 for (MachineInstr *Copy : CopiesToReplace)
2123 Copy->addImplicitDefUseOperands(*MF);
2124
2125 SetVector<MachineInstr *> ConstantFoldCandidates;
2126 for (FoldCandidate &Fold : FoldList) {
2127 assert(!Fold.isReg() || Fold.Def.OpToFold);
2128 if (Fold.isReg() && Fold.getReg().isVirtual()) {
2129 Register Reg = Fold.getReg();
2130 const MachineInstr *DefMI = Fold.Def.DefMI;
2131 if (DefMI->readsRegister(AMDGPU::EXEC, TRI) &&
2132 execMayBeModifiedBeforeUse(*MRI, Reg, *DefMI, *Fold.UseMI))
2133 continue;
2134 }
2135 if (updateOperand(Fold)) {
2136 LLVM_DEBUG(dbgs() << "Folded source from " << MI << " into OpNo "
2137 << static_cast<int>(Fold.UseOpNo) << " of "
2138 << *Fold.UseMI);
2139
2140 if (Fold.isImm())
2141 ConstantFoldCandidates.insert(Fold.UseMI);
2142
2143 } else if (Fold.Commuted) {
2144 // Restoring instruction's original operand order if fold has failed.
2145 TII->commuteInstruction(*Fold.UseMI, false);
2146 }
2147 }
2148
2149 for (MachineInstr *MI : ConstantFoldCandidates) {
2150 if (tryConstantFoldOp(MI)) {
2151 LLVM_DEBUG(dbgs() << "Constant folded " << *MI);
2152 Changed = true;
2153 }
2154 }
2155 return true;
2156}
2157
2158/// Fold %agpr = COPY (REG_SEQUENCE x_MOV_B32, ...) into REG_SEQUENCE
2159/// (V_ACCVGPR_WRITE_B32_e64) ... depending on the reg_sequence input values.
2160bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI) const {
2161 // It is very tricky to store a value into an AGPR. v_accvgpr_write_b32 can
2162 // only accept VGPR or inline immediate. Recreate a reg_sequence with its
2163 // initializers right here, so we will rematerialize immediates and avoid
2164 // copies via different reg classes.
2165 const TargetRegisterClass *DefRC =
2166 MRI->getRegClass(CopyMI->getOperand(0).getReg());
2167 if (!TRI->isAGPRClass(DefRC))
2168 return false;
2169
2170 Register UseReg = CopyMI->getOperand(1).getReg();
2171 MachineInstr *RegSeq = MRI->getVRegDef(UseReg);
2172 if (!RegSeq || !RegSeq->isRegSequence())
2173 return false;
2174
2175 const DebugLoc &DL = CopyMI->getDebugLoc();
2176 MachineBasicBlock &MBB = *CopyMI->getParent();
2177
2178 MachineInstrBuilder B(*MBB.getParent(), CopyMI);
2179 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2180
2181 const TargetRegisterClass *UseRC =
2182 MRI->getRegClass(CopyMI->getOperand(1).getReg());
2183
2184 // Value, subregindex for new REG_SEQUENCE
2186
2187 unsigned NumRegSeqOperands = RegSeq->getNumOperands();
2188 unsigned NumFoldable = 0;
2189
2190 for (unsigned I = 1; I != NumRegSeqOperands; I += 2) {
2191 MachineOperand &RegOp = RegSeq->getOperand(I);
2192 unsigned SubRegIdx = RegSeq->getOperand(I + 1).getImm();
2193
2194 if (RegOp.getSubReg()) {
2195 // TODO: Handle subregister compose
2196 NewDefs.emplace_back(&RegOp, SubRegIdx);
2197 continue;
2198 }
2199
2200 MachineOperand *Lookup = lookUpCopyChain(*TII, *MRI, RegOp.getReg());
2201 if (!Lookup)
2202 Lookup = &RegOp;
2203
2204 if (Lookup->isImm()) {
2205 // Check if this is an agpr_32 subregister.
2206 const TargetRegisterClass *DestSuperRC = TRI->getMatchingSuperRegClass(
2207 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2208 if (DestSuperRC &&
2209 TII->isInlineConstant(*Lookup, AMDGPU::OPERAND_REG_INLINE_C_INT32)) {
2210 ++NumFoldable;
2211 NewDefs.emplace_back(Lookup, SubRegIdx);
2212 continue;
2213 }
2214 }
2215
2216 const TargetRegisterClass *InputRC =
2217 Lookup->isReg() ? MRI->getRegClass(Lookup->getReg())
2218 : MRI->getRegClass(RegOp.getReg());
2219
2220 // TODO: Account for Lookup->getSubReg()
2221
2222 // If we can't find a matching super class, this is an SGPR->AGPR or
2223 // VGPR->AGPR subreg copy (or something constant-like we have to materialize
2224 // in the AGPR). We can't directly copy from SGPR to AGPR on gfx908, so we
2225 // want to rewrite to copy to an intermediate VGPR class.
2226 const TargetRegisterClass *MatchRC =
2227 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2228 if (!MatchRC) {
2229 ++NumFoldable;
2230 NewDefs.emplace_back(&RegOp, SubRegIdx);
2231 continue;
2232 }
2233
2234 NewDefs.emplace_back(&RegOp, SubRegIdx);
2235 }
2236
2237 // Do not clone a reg_sequence and merely change the result register class.
2238 if (NumFoldable == 0)
2239 return false;
2240
2241 CopyMI->setDesc(TII->get(AMDGPU::REG_SEQUENCE));
2242 for (unsigned I = CopyMI->getNumOperands() - 1; I > 0; --I)
2243 CopyMI->removeOperand(I);
2244
2245 for (auto [Def, DestSubIdx] : NewDefs) {
2246 if (!Def->isReg()) {
2247 // TODO: Should we use single write for each repeated value like in
2248 // register case?
2249 Register Tmp = MRI->createVirtualRegister(&AMDGPU::AGPR_32RegClass);
2250 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2251 .add(*Def);
2252 B.addReg(Tmp);
2253 } else {
2254 TargetInstrInfo::RegSubRegPair Src = getRegSubRegPair(*Def);
2255 Def->setIsKill(false);
2256
2257 Register &VGPRCopy = VGPRCopies[Src];
2258 if (!VGPRCopy) {
2259 const TargetRegisterClass *VGPRUseSubRC =
2260 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2261
2262 // We cannot build a reg_sequence out of the same registers, they
2263 // must be copied. Better do it here before copyPhysReg() created
2264 // several reads to do the AGPR->VGPR->AGPR copy.
2265
2266 // Direct copy from SGPR to AGPR is not possible on gfx908. To avoid
2267 // creation of exploded copies SGPR->VGPR->AGPR in the copyPhysReg()
2268 // later, create a copy here and track if we already have such a copy.
2269 const TargetRegisterClass *SubRC =
2270 TRI->getSubRegisterClass(MRI->getRegClass(Src.Reg), Src.SubReg);
2271 if (!VGPRUseSubRC->hasSubClassEq(SubRC)) {
2272 // TODO: Try to reconstrain class
2273 VGPRCopy = MRI->createVirtualRegister(VGPRUseSubRC);
2274 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::COPY), VGPRCopy).add(*Def);
2275 B.addReg(VGPRCopy);
2276 } else {
2277 // If it is already a VGPR, do not copy the register.
2278 B.add(*Def);
2279 }
2280 } else {
2281 B.addReg(VGPRCopy);
2282 }
2283 }
2284
2285 B.addImm(DestSubIdx);
2286 }
2287
2288 LLVM_DEBUG(dbgs() << "Folded " << *CopyMI);
2289 return true;
2290}
2291
2292bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2293 MachineInstr &MI, MachineOperand *&CurrentKnownM0Val) const {
2294 Register DstReg = MI.getOperand(0).getReg();
2295 // Specially track simple redefs of m0 to the same value in a block, so we
2296 // can erase the later ones.
2297 if (DstReg == AMDGPU::M0) {
2298 MachineOperand &NewM0Val = MI.getOperand(1);
2299 if (CurrentKnownM0Val && CurrentKnownM0Val->isIdenticalTo(NewM0Val)) {
2300 MI.eraseFromParent();
2301 return true;
2302 }
2303
2304 // We aren't tracking other physical registers
2305 CurrentKnownM0Val = (NewM0Val.isReg() && NewM0Val.getReg().isPhysical())
2306 ? nullptr
2307 : &NewM0Val;
2308 return false;
2309 }
2310
2311 MachineOperand *OpToFoldPtr;
2312 if (MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2313 // Folding when any src_modifiers are non-zero is unsupported
2314 if (TII->hasAnyModifiersSet(MI))
2315 return false;
2316 OpToFoldPtr = &MI.getOperand(2);
2317 } else
2318 OpToFoldPtr = &MI.getOperand(1);
2319 MachineOperand &OpToFold = *OpToFoldPtr;
2320 bool FoldingImm = OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
2321
2322 // FIXME: We could also be folding things like TargetIndexes.
2323 if (!FoldingImm && !OpToFold.isReg())
2324 return false;
2325
2326 // Fold virtual registers and constant physical registers.
2327 if (OpToFold.isReg() && OpToFold.getReg().isPhysical() &&
2328 !TRI->isConstantPhysReg(OpToFold.getReg()))
2329 return false;
2330
2331 // Prevent folding operands backwards in the function. For example,
2332 // the COPY opcode must not be replaced by 1 in this example:
2333 //
2334 // %3 = COPY %vgpr0; VGPR_32:%3
2335 // ...
2336 // %vgpr0 = V_MOV_B32_e32 1, implicit %exec
2337 if (!DstReg.isVirtual())
2338 return false;
2339
2340 const TargetRegisterClass *DstRC =
2341 MRI->getRegClass(MI.getOperand(0).getReg());
2342
2343 // True16: Fix malformed 16-bit sgpr COPY produced by peephole-opt
2344 // Can remove this code if proper 16-bit SGPRs are implemented
2345 // Example: Pre-peephole-opt
2346 // %29:sgpr_lo16 = COPY %16.lo16:sreg_32
2347 // %32:sreg_32 = COPY %29:sgpr_lo16
2348 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2349 // Post-peephole-opt and DCE
2350 // %32:sreg_32 = COPY %16.lo16:sreg_32
2351 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2352 // After this transform
2353 // %32:sreg_32 = COPY %16:sreg_32
2354 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2355 // After the fold operands pass
2356 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %16:sreg_32
2357 if (MI.getOpcode() == AMDGPU::COPY && OpToFold.isReg() &&
2358 OpToFold.getSubReg()) {
2359 if (DstRC == &AMDGPU::SReg_32RegClass &&
2360 DstRC == MRI->getRegClass(OpToFold.getReg())) {
2361 if (!TRI->getMatchingSuperRegClass(DstRC, &AMDGPU::SGPR_LO16RegClass,
2362 OpToFold.getSubReg()))
2363 return false;
2364 OpToFold.setSubReg(0);
2365 }
2366 }
2367
2368 // Fold copy to AGPR through reg_sequence
2369 // TODO: Handle with subregister extract
2370 if (OpToFold.isReg() && MI.isCopy() && !MI.getOperand(1).getSubReg()) {
2371 if (foldCopyToAGPRRegSequence(&MI))
2372 return true;
2373 }
2374
2375 FoldableDef Def(OpToFold, DstRC);
2376 bool Changed = foldInstOperand(MI, Def);
2377
2378 // If we managed to fold all uses of this copy then we might as well
2379 // delete it now.
2380 // The only reason we need to follow chains of copies here is that
2381 // tryFoldRegSequence looks forward through copies before folding a
2382 // REG_SEQUENCE into its eventual users.
2383 auto *InstToErase = &MI;
2384 while (MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2385 auto &SrcOp = InstToErase->getOperand(1);
2386 auto SrcReg = SrcOp.isReg() ? SrcOp.getReg() : Register();
2387 InstToErase->eraseFromParent();
2388 Changed = true;
2389 InstToErase = nullptr;
2390 if (!SrcReg || SrcReg.isPhysical())
2391 break;
2392 InstToErase = MRI->getVRegDef(SrcReg);
2393 if (!InstToErase || !TII->isFoldableCopy(*InstToErase))
2394 break;
2395 }
2396
2397 if (InstToErase && InstToErase->isRegSequence() &&
2398 MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2399 InstToErase->eraseFromParent();
2400 Changed = true;
2401 }
2402
2403 if (Changed)
2404 return true;
2405
2406 // Run this after foldInstOperand to avoid turning scalar additions into
2407 // vector additions when the result scalar result could just be folded into
2408 // the user(s).
2409 return OpToFold.isReg() &&
2410 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.getReg(), MI);
2411}
2412
2413// Clamp patterns are canonically selected to v_max_* instructions, so only
2414// handle them.
2415const MachineOperand *
2416SIFoldOperandsImpl::isClamp(const MachineInstr &MI) const {
2417 unsigned Op = MI.getOpcode();
2418 switch (Op) {
2419 case AMDGPU::V_MAX_F32_e64:
2420 case AMDGPU::V_MAX_F16_e64:
2421 case AMDGPU::V_MAX_F16_t16_e64:
2422 case AMDGPU::V_MAX_F16_fake16_e64:
2423 case AMDGPU::V_MAX_F64_e64:
2424 case AMDGPU::V_MAX_NUM_F64_e64:
2425 case AMDGPU::V_PK_MAX_F16:
2426 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2427 case AMDGPU::V_PK_MAX_NUM_BF16: {
2428 if (MI.mayRaiseFPException())
2429 return nullptr;
2430
2431 if (!TII->getNamedOperand(MI, AMDGPU::OpName::clamp)->getImm())
2432 return nullptr;
2433
2434 // Make sure sources are identical.
2435 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2436 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2437 if (!Src0->isReg() || !Src1->isReg() ||
2438 Src0->getReg() != Src1->getReg() ||
2439 Src0->getSubReg() != Src1->getSubReg() ||
2440 Src0->getSubReg() != AMDGPU::NoSubRegister)
2441 return nullptr;
2442
2443 // Can't fold up if we have modifiers.
2444 if (TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2445 return nullptr;
2446
2447 unsigned Src0Mods
2448 = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)->getImm();
2449 unsigned Src1Mods
2450 = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers)->getImm();
2451
2452 // Having a 0 op_sel_hi would require swizzling the output in the source
2453 // instruction, which we can't do.
2454 unsigned UnsetMods =
2455 (Op == AMDGPU::V_PK_MAX_F16 || Op == AMDGPU::V_PK_MAX_NUM_BF16)
2457 : 0u;
2458 if (Src0Mods != UnsetMods || Src1Mods != UnsetMods)
2459 return nullptr;
2460 return Src0;
2461 }
2462 default:
2463 return nullptr;
2464 }
2465}
2466
2467// FIXME: Clamp for v_mad_mixhi_f16 handled during isel.
2468bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &MI) {
2469 const MachineOperand *ClampSrc = isClamp(MI);
2470 if (!ClampSrc || !MRI->hasOneNonDBGUser(ClampSrc->getReg()))
2471 return false;
2472
2473 if (!ClampSrc->getReg().isVirtual())
2474 return false;
2475
2476 // Look through COPY. COPY only observed with True16.
2477 Register DefSrcReg = TRI->lookThruCopyLike(ClampSrc->getReg(), MRI);
2478 MachineInstr *Def =
2479 MRI->getVRegDef(DefSrcReg.isVirtual() ? DefSrcReg : ClampSrc->getReg());
2480
2481 // The type of clamp must be compatible.
2482 if (!SIInstrInfo::hasSameClamp(*Def, MI))
2483 return false;
2484
2485 if (Def->mayRaiseFPException())
2486 return false;
2487
2488 MachineOperand *DefClamp = TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2489 if (!DefClamp)
2490 return false;
2491
2492 LLVM_DEBUG(dbgs() << "Folding clamp " << *DefClamp << " into " << *Def);
2493
2494 // Clamp is applied after omod, so it is OK if omod is set.
2495 DefClamp->setImm(1);
2496
2497 Register DefReg = Def->getOperand(0).getReg();
2498 Register MIDstReg = MI.getOperand(0).getReg();
2499 if (TRI->isSGPRReg(*MRI, DefReg)) {
2500 // Pseudo scalar instructions have a SGPR for dst and clamp is a v_max*
2501 // instruction with a VGPR dst.
2502 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY),
2503 MIDstReg)
2504 .addReg(DefReg);
2505 } else {
2506 MRI->replaceRegWith(MIDstReg, DefReg);
2507 }
2508 MI.eraseFromParent();
2509
2510 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2511 // instruction, so we might as well convert it to the more flexible VOP3-only
2512 // mad/fma form.
2513 if (TII->convertToThreeAddress(*Def, /*LIS=*/nullptr))
2514 Def->eraseFromParent();
2515
2516 return true;
2517}
2518
2519static int getOModValue(unsigned Opc, int64_t Val) {
2520 switch (Opc) {
2521 case AMDGPU::V_MUL_F64_e64:
2522 case AMDGPU::V_MUL_F64_pseudo_e64: {
2523 switch (Val) {
2524 case 0x3fe0000000000000: // 0.5
2525 return SIOutMods::DIV2;
2526 case 0x4000000000000000: // 2.0
2527 return SIOutMods::MUL2;
2528 case 0x4010000000000000: // 4.0
2529 return SIOutMods::MUL4;
2530 default:
2531 return SIOutMods::NONE;
2532 }
2533 }
2534 case AMDGPU::V_MUL_F32_e64: {
2535 switch (static_cast<uint32_t>(Val)) {
2536 case 0x3f000000: // 0.5
2537 return SIOutMods::DIV2;
2538 case 0x40000000: // 2.0
2539 return SIOutMods::MUL2;
2540 case 0x40800000: // 4.0
2541 return SIOutMods::MUL4;
2542 default:
2543 return SIOutMods::NONE;
2544 }
2545 }
2546 case AMDGPU::V_MUL_F16_e64:
2547 case AMDGPU::V_MUL_F16_t16_e64:
2548 case AMDGPU::V_MUL_F16_fake16_e64: {
2549 switch (static_cast<uint16_t>(Val)) {
2550 case 0x3800: // 0.5
2551 return SIOutMods::DIV2;
2552 case 0x4000: // 2.0
2553 return SIOutMods::MUL2;
2554 case 0x4400: // 4.0
2555 return SIOutMods::MUL4;
2556 default:
2557 return SIOutMods::NONE;
2558 }
2559 }
2560 case AMDGPU::V_PK_MUL_BF16: {
2561 switch (static_cast<uint16_t>(Val)) {
2562 case 0x3F00: // 0.5 in BF16
2563 return SIOutMods::DIV2;
2564 case 0x4000: // 2.0 in BF16
2565 return SIOutMods::MUL2;
2566 case 0x4080: // 4.0 in BF16
2567 return SIOutMods::MUL4;
2568 default:
2569 return SIOutMods::NONE;
2570 }
2571 }
2572 default:
2573 llvm_unreachable("invalid mul opcode");
2574 }
2575}
2576
2577// FIXME: Does this really not support denormals with f16?
2578// FIXME: Does this need to check IEEE mode bit? SNaNs are generally not
2579// handled, so will anything other than that break?
2580std::pair<const MachineOperand *, int>
2581SIFoldOperandsImpl::isOMod(const MachineInstr &MI) const {
2582 unsigned Op = MI.getOpcode();
2583 switch (Op) {
2584 case AMDGPU::V_MUL_F64_e64:
2585 case AMDGPU::V_MUL_F64_pseudo_e64:
2586 case AMDGPU::V_MUL_F32_e64:
2587 case AMDGPU::V_MUL_F16_t16_e64:
2588 case AMDGPU::V_MUL_F16_fake16_e64:
2589 case AMDGPU::V_MUL_F16_e64: {
2590 // If output denormals are enabled, omod is ignored.
2591 if ((Op == AMDGPU::V_MUL_F32_e64 &&
2593 ((Op == AMDGPU::V_MUL_F64_e64 || Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2594 Op == AMDGPU::V_MUL_F16_e64 || Op == AMDGPU::V_MUL_F16_t16_e64 ||
2595 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2598 MI.mayRaiseFPException())
2599 return {nullptr, SIOutMods::NONE};
2600
2601 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2602 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2603
2604 // If there is an immediate operand, it must be Src1
2605 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
2606 if (!Src1Imm)
2607 return {nullptr, SIOutMods::NONE};
2608
2609 int OMod = getOModValue(Op, *Src1Imm);
2610 if (OMod == SIOutMods::NONE ||
2611 TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
2612 TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) ||
2613 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2614 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2615 return {nullptr, SIOutMods::NONE};
2616
2617 return {Src0, OMod};
2618 }
2619 case AMDGPU::V_ADD_F64_e64:
2620 case AMDGPU::V_ADD_F64_pseudo_e64:
2621 case AMDGPU::V_ADD_F32_e64:
2622 case AMDGPU::V_ADD_F16_e64:
2623 case AMDGPU::V_ADD_F16_t16_e64:
2624 case AMDGPU::V_ADD_F16_fake16_e64: {
2625 // If output denormals are enabled, omod is ignored.
2626 if ((Op == AMDGPU::V_ADD_F32_e64 &&
2628 ((Op == AMDGPU::V_ADD_F64_e64 || Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2629 Op == AMDGPU::V_ADD_F16_e64 || Op == AMDGPU::V_ADD_F16_t16_e64 ||
2630 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2632 return {nullptr, SIOutMods::NONE};
2633
2634 // Look through the DAGCombiner canonicalization fmul x, 2 -> fadd x, x
2635 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2636 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2637
2638 if (Src0->isReg() && Src1->isReg() && Src0->getReg() == Src1->getReg() &&
2639 Src0->getSubReg() == Src1->getSubReg() &&
2640 !TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) &&
2641 !TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) &&
2642 !TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) &&
2643 !TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2644 return {Src0, SIOutMods::MUL2};
2645
2646 return {nullptr, SIOutMods::NONE};
2647 }
2648 case AMDGPU::V_PK_MUL_BF16: {
2649 // OMOD folding for BF16 packed multiply. bf16 has no denormal mode of its
2650 // own; it follows the default ("denormal-fp-math") mode, which is the same
2651 // field as f64/f16.
2653 MI.mayRaiseFPException())
2654 return {nullptr, SIOutMods::NONE};
2655
2656 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2657 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2658
2659 // If there is an immediate operand, it must be Src1
2660 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*MRI, *Src1);
2661 if (!Src1Imm)
2662 return {nullptr, SIOutMods::NONE};
2663
2664 int OMod = getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2665 if (OMod == SIOutMods::NONE)
2666 return {nullptr, SIOutMods::NONE};
2667
2668 // Modifiers other than op_sel_hi block OMOD folding. Per getOModValue
2669 // above, Src1 is an inline constant (0.5/2.0/4.0), which may carry
2670 // op_sel_lo to read it from the upper FP32 half, so allow that on src1.
2671 const MachineOperand *Src0Mods =
2672 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
2673 const MachineOperand *Src1Mods =
2674 TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
2675 if ((Src0Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2676 (Src1Mods->getImm() & ~(SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1)) ||
2677 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2678 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2679 return {nullptr, SIOutMods::NONE};
2680
2681 return {Src0, OMod};
2682 }
2683 case AMDGPU::V_PK_ADD_BF16: {
2684 // OMOD folding for BF16 packed add: x + x -> x * 2. See the bf16 denormal
2685 // mode note in the V_PK_MUL_BF16 case above.
2687 return {nullptr, SIOutMods::NONE};
2688
2689 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2690 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2691
2692 if (!Src0->isReg() || !Src1->isReg() || Src0->getReg() != Src1->getReg() ||
2693 Src0->getSubReg() != Src1->getSubReg())
2694 return {nullptr, SIOutMods::NONE};
2695
2696 // Modifiers other than op_sel_hi block OMOD folding
2697 const MachineOperand *Src0Mods =
2698 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
2699 const MachineOperand *Src1Mods =
2700 TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
2701 if ((Src0Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2702 (Src1Mods->getImm() & ~SISrcMods::OP_SEL_1) ||
2703 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2704 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2705 return {nullptr, SIOutMods::NONE};
2706
2707 return {Src0, SIOutMods::MUL2};
2708 }
2709 default:
2710 return {nullptr, SIOutMods::NONE};
2711 }
2712}
2713
2714// FIXME: Does this need to check IEEE bit on function?
2715bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &MI) {
2716 const MachineOperand *RegOp;
2717 int OMod;
2718 std::tie(RegOp, OMod) = isOMod(MI);
2719 if (OMod == SIOutMods::NONE || !RegOp->isReg() ||
2720 RegOp->getSubReg() != AMDGPU::NoSubRegister ||
2721 !MRI->hasOneNonDBGUser(RegOp->getReg()))
2722 return false;
2723
2724 MachineInstr *Def = MRI->getVRegDef(RegOp->getReg());
2725 Register OModSrcReg = Def->getOperand(0).getReg();
2726
2727 // In real-true16 mode, vgpr_16 results are packed into vgpr_32 via
2728 // REG_SEQUENCE. Look through it to find the actual instruction.
2729 if (Def->isRegSequence() && Def->getNumOperands() == 5 &&
2730 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2731 // Only look through if the high 16 bits are undefined
2732 bool CanLookThrough = true;
2733 MachineInstr *Hi16Def = MRI->getVRegDef(Def->getOperand(3).getReg());
2734 if (!Hi16Def || !Hi16Def->isImplicitDef())
2735 CanLookThrough = false;
2736
2737 if (CanLookThrough) {
2738 Register SrcReg = Def->getOperand(1).getReg();
2739 if (!MRI->hasOneNonDBGUse(SrcReg))
2740 return false;
2741
2742 Def = MRI->getVRegDef(SrcReg);
2743 if (!Def)
2744 return false;
2745 }
2746 }
2747
2748 MachineOperand *DefOMod = TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2749 if (!DefOMod || DefOMod->getImm() != SIOutMods::NONE)
2750 return false;
2751
2752 if (Def->mayRaiseFPException())
2753 return false;
2754
2755 // Clamp is applied after omod. If the source already has clamp set, don't
2756 // fold it.
2757 if (TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2758 return false;
2759
2760 LLVM_DEBUG(dbgs() << "Folding omod " << MI << " into " << *Def);
2761
2762 DefOMod->setImm(OMod);
2763 MRI->replaceRegWith(MI.getOperand(0).getReg(), OModSrcReg);
2764 MI.eraseFromParent();
2765
2766 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2767 // instruction, so we might as well convert it to the more flexible VOP3-only
2768 // mad/fma form.
2769 if (TII->convertToThreeAddress(*Def, /*LIS=*/nullptr))
2770 Def->eraseFromParent();
2771
2772 return true;
2773}
2774
2775// Try to optimize SGPR reg sequences that are splat <s, s> or <s, s, s, s>
2776// where all uses are PackedSingleSGPR64BitInst, replacing with <s, undef, ...>
2777bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &MI) {
2778 assert(MI.isRegSequence());
2779
2780 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2781 return false;
2782
2783 Register Reg = MI.getOperand(0).getReg();
2784
2785 // Only optimize 128-bit SGPR register sequences
2786 const TargetRegisterClass *RegClass = MRI->getRegClass(Reg);
2787 if (!TRI->isSGPRClass(RegClass) || TRI->getRegSizeInBits(*RegClass) != 128)
2788 return false;
2789
2791 if (!getRegSeqInit(Defs, Reg))
2792 return false;
2793
2794 // Check if this is a splat pattern
2795 if (Defs.size() <= 1)
2796 return false;
2797
2798 const auto &[FirstOp, _] = Defs.front();
2799 if (!FirstOp->isReg())
2800 return false;
2801
2802 Register FirstReg = FirstOp->getReg();
2803 unsigned FirstSubReg = FirstOp->getSubReg();
2804
2805 const TargetRegisterClass *FirstRegClass = MRI->getRegClass(FirstReg);
2806 if (!TRI->isSGPRClass(FirstRegClass))
2807 return false;
2808
2809 // Check remaining elements match first
2810 if (!llvm::all_of(llvm::drop_begin(Defs), [&](const auto &Def) {
2811 const auto &[Op, _] = Def;
2812 return Op->isReg() && Op->getReg() == FirstReg &&
2813 Op->getSubReg() == FirstSubReg;
2814 }))
2815 return false;
2816
2817 // Check if all uses are isSingleSGPRReadInst
2818 for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
2820 return false;
2821 }
2822
2823 // Create new reg sequence with <s, undef, undef, ...>
2824 Register NewDst = MRI->createVirtualRegister(RegClass);
2825 MachineInstrBuilder RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2826 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2827
2828 // Add the first operand
2829 FirstOp->setIsKill(false);
2830 RS.add(*FirstOp);
2831 RS.addImm(Defs[0].second);
2832
2833 // Add undef for remaining lanes
2834 // Create an undef virtual register for the same register class
2835 Register UndefReg = MRI->createVirtualRegister(FirstRegClass);
2836 for (unsigned i = 1; i < Defs.size(); ++i) {
2837 RS.addReg(UndefReg, RegState::Undef);
2838 RS.addImm(Defs[i].second);
2839 }
2840
2841 // Replace all uses
2842 MRI->replaceRegWith(Reg, NewDst);
2843
2844 LLVM_DEBUG(dbgs() << "Folded splat SGPR reg_sequence: " << MI << " into "
2845 << *RS);
2846
2847 MI.eraseFromParent();
2848 return true;
2849}
2850
2851// Try to fold a reg_sequence with vgpr output and agpr inputs into an
2852// instruction which can take an agpr. So far that means a store.
2853bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &MI) {
2854 assert(MI.isRegSequence());
2855
2856 // Try to optimize SGPR splat sequences first
2857 if (tryFoldSGPRSplatRegSequence(MI))
2858 return true;
2859
2860 auto Reg = MI.getOperand(0).getReg();
2861
2862 if (!ST->hasGFX90AInsts() || !TRI->isVGPR(*MRI, Reg) ||
2864 return false;
2865
2867 if (!getRegSeqInit(Defs, Reg))
2868 return false;
2869
2870 for (auto &[Op, SubIdx] : Defs) {
2871 if (!Op->isReg())
2872 return false;
2873 if (TRI->isAGPR(*MRI, Op->getReg()))
2874 continue;
2875 // Maybe this is a COPY from AREG
2876 const MachineInstr *SubDef = MRI->getVRegDef(Op->getReg());
2877 if (!SubDef || !SubDef->isCopy() || SubDef->getOperand(1).getSubReg())
2878 return false;
2879 if (!TRI->isAGPR(*MRI, SubDef->getOperand(1).getReg()))
2880 return false;
2881 }
2882
2883 MachineOperand *Op = &*MRI->use_nodbg_begin(Reg);
2884 MachineInstr *UseMI = Op->getParent();
2885 while (UseMI->isCopy() && !Op->getSubReg()) {
2886 Reg = UseMI->getOperand(0).getReg();
2887 if (!TRI->isVGPR(*MRI, Reg) || !MRI->hasOneNonDBGUse(Reg))
2888 return false;
2889 Op = &*MRI->use_nodbg_begin(Reg);
2890 UseMI = Op->getParent();
2891 }
2892
2893 if (Op->getSubReg())
2894 return false;
2895
2896 unsigned OpIdx = Op - &UseMI->getOperand(0);
2897 const MCInstrDesc &InstDesc = UseMI->getDesc();
2898 const TargetRegisterClass *OpRC = TII->getRegClass(InstDesc, OpIdx);
2899 if (!OpRC || !TRI->isVectorSuperClass(OpRC))
2900 return false;
2901
2902 const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg));
2903 auto Dst = MRI->createVirtualRegister(NewDstRC);
2904 auto RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2905 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2906
2907 for (auto &[Def, SubIdx] : Defs) {
2908 Def->setIsKill(false);
2909 if (TRI->isAGPR(*MRI, Def->getReg())) {
2910 RS.add(*Def);
2911 } else { // This is a copy
2912 MachineInstr *SubDef = MRI->getVRegDef(Def->getReg());
2913 SubDef->getOperand(1).setIsKill(false);
2914 RS.addReg(SubDef->getOperand(1).getReg(), {}, Def->getSubReg());
2915 }
2916 RS.addImm(SubIdx);
2917 }
2918
2919 Op->setReg(Dst);
2920 if (!TII->isOperandLegal(*UseMI, OpIdx, Op)) {
2921 Op->setReg(Reg);
2922 RS->eraseFromParent();
2923 return false;
2924 }
2925
2926 LLVM_DEBUG(dbgs() << "Folded " << *RS << " into " << *UseMI);
2927
2928 // Erase the REG_SEQUENCE eagerly, unless we followed a chain of COPY users,
2929 // in which case we can erase them all later in runOnMachineFunction.
2930 if (MRI->use_nodbg_empty(MI.getOperand(0).getReg()))
2931 MI.eraseFromParent();
2932 return true;
2933}
2934
2935/// Checks whether \p Copy is a AGPR -> VGPR copy. Returns `true` on success and
2936/// stores the AGPR register in \p OutReg and the subreg in \p OutSubReg
2937static bool isAGPRCopy(const SIRegisterInfo &TRI,
2938 const MachineRegisterInfo &MRI, const MachineInstr &Copy,
2939 Register &OutReg, unsigned &OutSubReg) {
2940 assert(Copy.isCopy());
2941
2942 const MachineOperand &CopySrc = Copy.getOperand(1);
2943 Register CopySrcReg = CopySrc.getReg();
2944 if (!CopySrcReg.isVirtual())
2945 return false;
2946
2947 // Common case: copy from AGPR directly, e.g.
2948 // %1:vgpr_32 = COPY %0:agpr_32
2949 if (TRI.isAGPR(MRI, CopySrcReg)) {
2950 OutReg = CopySrcReg;
2951 OutSubReg = CopySrc.getSubReg();
2952 return true;
2953 }
2954
2955 // Sometimes it can also involve two copies, e.g.
2956 // %1:vgpr_256 = COPY %0:agpr_256
2957 // %2:vgpr_32 = COPY %1:vgpr_256.sub0
2958 const MachineInstr *CopySrcDef = MRI.getVRegDef(CopySrcReg);
2959 if (!CopySrcDef || !CopySrcDef->isCopy())
2960 return false;
2961
2962 const MachineOperand &OtherCopySrc = CopySrcDef->getOperand(1);
2963 Register OtherCopySrcReg = OtherCopySrc.getReg();
2964 if (!OtherCopySrcReg.isVirtual() ||
2965 CopySrcDef->getOperand(0).getSubReg() != AMDGPU::NoSubRegister ||
2966 OtherCopySrc.getSubReg() != AMDGPU::NoSubRegister ||
2967 !TRI.isAGPR(MRI, OtherCopySrcReg))
2968 return false;
2969
2970 OutReg = OtherCopySrcReg;
2971 OutSubReg = CopySrc.getSubReg();
2972 return true;
2973}
2974
2975// Try to hoist an AGPR to VGPR copy across a PHI.
2976// This should allow folding of an AGPR into a consumer which may support it.
2977//
2978// Example 1: LCSSA PHI
2979// loop:
2980// %1:vreg = COPY %0:areg
2981// exit:
2982// %2:vreg = PHI %1:vreg, %loop
2983// =>
2984// loop:
2985// exit:
2986// %1:areg = PHI %0:areg, %loop
2987// %2:vreg = COPY %1:areg
2988//
2989// Example 2: PHI with multiple incoming values:
2990// entry:
2991// %1:vreg = GLOBAL_LOAD(..)
2992// loop:
2993// %2:vreg = PHI %1:vreg, %entry, %5:vreg, %loop
2994// %3:areg = COPY %2:vreg
2995// %4:areg = (instr using %3:areg)
2996// %5:vreg = COPY %4:areg
2997// =>
2998// entry:
2999// %1:vreg = GLOBAL_LOAD(..)
3000// %2:areg = COPY %1:vreg
3001// loop:
3002// %3:areg = PHI %2:areg, %entry, %X:areg,
3003// %4:areg = (instr using %3:areg)
3004bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &PHI) {
3005 assert(PHI.isPHI());
3006
3007 Register PhiOut = PHI.getOperand(0).getReg();
3008 if (!TRI->isVGPR(*MRI, PhiOut))
3009 return false;
3010
3011 // Iterate once over all incoming values of the PHI to check if this PHI is
3012 // eligible, and determine the exact AGPR RC we'll target.
3013 const TargetRegisterClass *ARC = nullptr;
3014 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
3015 MachineOperand &MO = PHI.getOperand(K);
3016 MachineInstr *Copy = MRI->getVRegDef(MO.getReg());
3017 if (!Copy || !Copy->isCopy())
3018 continue;
3019
3020 Register AGPRSrc;
3021 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
3022 if (!isAGPRCopy(*TRI, *MRI, *Copy, AGPRSrc, AGPRRegMask))
3023 continue;
3024
3025 const TargetRegisterClass *CopyInRC = MRI->getRegClass(AGPRSrc);
3026 if (const auto *SubRC = TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
3027 CopyInRC = SubRC;
3028
3029 if (ARC && !ARC->hasSubClassEq(CopyInRC))
3030 return false;
3031 ARC = CopyInRC;
3032 }
3033
3034 if (!ARC)
3035 return false;
3036
3037 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
3038
3039 // Rewrite the PHI's incoming values to ARC.
3040 LLVM_DEBUG(dbgs() << "Folding AGPR copies into: " << PHI);
3041 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
3042 MachineOperand &MO = PHI.getOperand(K);
3043 Register Reg = MO.getReg();
3044
3046 MachineBasicBlock *InsertMBB = nullptr;
3047
3048 // Look at the def of Reg, ignoring all copies.
3049 unsigned CopyOpc = AMDGPU::COPY;
3050 if (MachineInstr *Def = MRI->getVRegDef(Reg)) {
3051
3052 // Look at pre-existing COPY instructions from ARC: Steal the operand. If
3053 // the copy was single-use, it will be removed by DCE later.
3054 if (Def->isCopy()) {
3055 Register AGPRSrc;
3056 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
3057 if (isAGPRCopy(*TRI, *MRI, *Def, AGPRSrc, AGPRSubReg)) {
3058 MO.setReg(AGPRSrc);
3059 MO.setSubReg(AGPRSubReg);
3060 continue;
3061 }
3062
3063 // If this is a multi-use SGPR -> VGPR copy, use V_ACCVGPR_WRITE on
3064 // GFX908 directly instead of a COPY. Otherwise, SIFoldOperand may try
3065 // to fold the sgpr -> vgpr -> agpr copy into a sgpr -> agpr copy which
3066 // is unlikely to be profitable.
3067 //
3068 // Note that V_ACCVGPR_WRITE is only used for AGPR_32.
3069 MachineOperand &CopyIn = Def->getOperand(1);
3070 if (IsAGPR32 && !ST->hasGFX90AInsts() && !MRI->hasOneNonDBGUse(Reg) &&
3071 TRI->isSGPRReg(*MRI, CopyIn.getReg()))
3072 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
3073 }
3074
3075 InsertMBB = Def->getParent();
3076 InsertPt = InsertMBB->SkipPHIsLabelsAndDebug(++Def->getIterator());
3077 } else {
3078 InsertMBB = PHI.getOperand(MO.getOperandNo() + 1).getMBB();
3079 InsertPt = InsertMBB->getFirstTerminator();
3080 }
3081
3082 Register NewReg = MRI->createVirtualRegister(ARC);
3083 MachineInstr *MI = BuildMI(*InsertMBB, InsertPt, PHI.getDebugLoc(),
3084 TII->get(CopyOpc), NewReg)
3085 .addReg(Reg);
3086 MO.setReg(NewReg);
3087
3088 (void)MI;
3089 LLVM_DEBUG(dbgs() << " Created COPY: " << *MI);
3090 }
3091
3092 // Replace the PHI's result with a new register.
3093 Register NewReg = MRI->createVirtualRegister(ARC);
3094 PHI.getOperand(0).setReg(NewReg);
3095
3096 // COPY that new register back to the original PhiOut register. This COPY will
3097 // usually be folded out later.
3098 MachineBasicBlock *MBB = PHI.getParent();
3099 BuildMI(*MBB, MBB->getFirstNonPHI(), PHI.getDebugLoc(),
3100 TII->get(AMDGPU::COPY), PhiOut)
3101 .addReg(NewReg);
3102
3103 LLVM_DEBUG(dbgs() << " Done: Folded " << PHI);
3104 return true;
3105}
3106
3107// Attempt to convert VGPR load to an AGPR load.
3108bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &MI) {
3109 assert(MI.mayLoad());
3110 if (!ST->hasGFX90AInsts() || MI.getNumExplicitDefs() != 1)
3111 return false;
3112
3113 MachineOperand &Def = MI.getOperand(0);
3114 if (!Def.isDef())
3115 return false;
3116
3117 Register DefReg = Def.getReg();
3118
3119 if (DefReg.isPhysical() || !TRI->isVGPR(*MRI, DefReg))
3120 return false;
3121
3124 SmallVector<Register, 8> MoveRegs;
3125
3126 if (Users.empty())
3127 return false;
3128
3129 // Check that all uses a copy to an agpr or a reg_sequence producing an agpr.
3130 while (!Users.empty()) {
3131 const MachineInstr *I = Users.pop_back_val();
3132 if (!I->isCopy() && !I->isRegSequence())
3133 return false;
3134 Register DstReg = I->getOperand(0).getReg();
3135 // Physical registers may have more than one instruction definitions
3136 if (DstReg.isPhysical())
3137 return false;
3138 if (TRI->isAGPR(*MRI, DstReg))
3139 continue;
3140 MoveRegs.push_back(DstReg);
3141 for (const MachineInstr &U : MRI->use_nodbg_instructions(DstReg))
3142 Users.push_back(&U);
3143 }
3144
3145 const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
3146 MRI->setRegClass(DefReg, TRI->getEquivalentAGPRClass(RC));
3147 if (!TII->isOperandLegal(MI, 0, &Def)) {
3148 MRI->setRegClass(DefReg, RC);
3149 return false;
3150 }
3151
3152 while (!MoveRegs.empty()) {
3153 Register Reg = MoveRegs.pop_back_val();
3154 MRI->setRegClass(Reg, TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)));
3155 }
3156
3157 LLVM_DEBUG(dbgs() << "Folded " << MI);
3158
3159 return true;
3160}
3161
3162// tryFoldPhiAGPR will aggressively try to create AGPR PHIs.
3163// For GFX90A and later, this is pretty much always a good thing, but for GFX908
3164// there's cases where it can create a lot more AGPR-AGPR copies, which are
3165// expensive on this architecture due to the lack of V_ACCVGPR_MOV.
3166//
3167// This function looks at all AGPR PHIs in a basic block and collects their
3168// operands. Then, it checks for register that are used more than once across
3169// all PHIs and caches them in a VGPR. This prevents ExpandPostRAPseudo from
3170// having to create one VGPR temporary per use, which can get very messy if
3171// these PHIs come from a broken-up large PHI (e.g. 32 AGPR phis, one per vector
3172// element).
3173//
3174// Example
3175// a:
3176// %in:agpr_256 = COPY %foo:vgpr_256
3177// c:
3178// %x:agpr_32 = ..
3179// b:
3180// %0:areg = PHI %in.sub0:agpr_32, %a, %x, %c
3181// %1:areg = PHI %in.sub0:agpr_32, %a, %y, %c
3182// %2:areg = PHI %in.sub0:agpr_32, %a, %z, %c
3183// =>
3184// a:
3185// %in:agpr_256 = COPY %foo:vgpr_256
3186// %tmp:vgpr_32 = V_ACCVGPR_READ_B32_e64 %in.sub0:agpr_32
3187// %tmp_agpr:agpr_32 = COPY %tmp
3188// c:
3189// %x:agpr_32 = ..
3190// b:
3191// %0:areg = PHI %tmp_agpr, %a, %x, %c
3192// %1:areg = PHI %tmp_agpr, %a, %y, %c
3193// %2:areg = PHI %tmp_agpr, %a, %z, %c
3194bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &MBB) {
3195 // This is only really needed on GFX908 where AGPR-AGPR copies are
3196 // unreasonably difficult.
3197 if (ST->hasGFX90AInsts())
3198 return false;
3199
3200 // Look at all AGPR Phis and collect the register + subregister used.
3201 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3202 RegToMO;
3203
3204 for (auto &MI : MBB) {
3205 if (!MI.isPHI())
3206 break;
3207
3208 if (!TRI->isAGPR(*MRI, MI.getOperand(0).getReg()))
3209 continue;
3210
3211 for (unsigned K = 1; K < MI.getNumOperands(); K += 2) {
3212 MachineOperand &PhiMO = MI.getOperand(K);
3213 if (!PhiMO.getSubReg())
3214 continue;
3215 RegToMO[{PhiMO.getReg(), PhiMO.getSubReg()}].push_back(&PhiMO);
3216 }
3217 }
3218
3219 // For all (Reg, SubReg) pair that are used more than once, cache the value in
3220 // a VGPR.
3221 bool Changed = false;
3222 for (const auto &[Entry, MOs] : RegToMO) {
3223 if (MOs.size() == 1)
3224 continue;
3225
3226 const auto [Reg, SubReg] = Entry;
3227 MachineInstr *Def = MRI->getVRegDef(Reg);
3228 MachineBasicBlock *DefMBB = Def->getParent();
3229
3230 // Create a copy in a VGPR using V_ACCVGPR_READ_B32_e64 so it's not folded
3231 // out.
3232 const TargetRegisterClass *ARC = getRegOpRC(*MRI, *TRI, *MOs.front());
3233 Register TempVGPR =
3234 MRI->createVirtualRegister(TRI->getEquivalentVGPRClass(ARC));
3235 MachineInstr *VGPRCopy =
3236 BuildMI(*DefMBB, ++Def->getIterator(), Def->getDebugLoc(),
3237 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3238 .addReg(Reg, /* flags */ {}, SubReg);
3239
3240 // Copy back to an AGPR and use that instead of the AGPR subreg in all MOs.
3241 Register TempAGPR = MRI->createVirtualRegister(ARC);
3242 BuildMI(*DefMBB, ++VGPRCopy->getIterator(), Def->getDebugLoc(),
3243 TII->get(AMDGPU::COPY), TempAGPR)
3244 .addReg(TempVGPR);
3245
3246 LLVM_DEBUG(dbgs() << "Caching AGPR into VGPR: " << *VGPRCopy);
3247 for (MachineOperand *MO : MOs) {
3248 MO->setReg(TempAGPR);
3249 MO->setSubReg(AMDGPU::NoSubRegister);
3250 LLVM_DEBUG(dbgs() << " Changed PHI Operand: " << *MO << "\n");
3251 }
3252
3253 Changed = true;
3254 }
3255
3256 return Changed;
3257}
3258
3259bool SIFoldOperandsImpl::run(MachineFunction &MF, const MachineLoopInfo *MLI) {
3260 this->MF = &MF;
3261 MRI = &MF.getRegInfo();
3262 ST = &MF.getSubtarget<GCNSubtarget>();
3263 TII = ST->getInstrInfo();
3264 TRI = &TII->getRegisterInfo();
3265 MFI = MF.getInfo<SIMachineFunctionInfo>();
3266 this->MLI = MLI;
3267
3268 // omod is ignored by hardware if IEEE bit is enabled. omod also does not
3269 // correctly handle signed zeros.
3270 //
3271 // FIXME: Also need to check strictfp
3272 bool IsIEEEMode = MFI->getMode().IEEE;
3273
3274 bool Changed = false;
3275 for (MachineBasicBlock *MBB : depth_first(&MF)) {
3276 MachineOperand *CurrentKnownM0Val = nullptr;
3277 for (auto &MI : make_early_inc_range(*MBB)) {
3278 Changed |= tryFoldCndMask(MI);
3279
3280 // PeepholeOptimizer may have folded an inline immediate directly onto an
3281 // instruction operand without materializing it into a register first.
3282 // Such an instruction is never reached through a def->use edge in
3283 // foldInstOperand, so try to constant fold it here.
3284 if (tryConstantFoldOp(&MI)) {
3285 Changed = true;
3286 continue;
3287 }
3288
3289 if (tryFoldRedundantAND(MI)) {
3290 Changed = true;
3291 continue;
3292 }
3293
3294 if (tryFoldAndExec(MI)) {
3295 Changed = true;
3296 continue;
3297 }
3298
3299 if (MI.isRegSequence() && tryFoldRegSequence(MI)) {
3300 Changed = true;
3301 continue;
3302 }
3303
3304 if (MI.isPHI() && tryFoldPhiAGPR(MI)) {
3305 Changed = true;
3306 continue;
3307 }
3308
3309 if (MI.mayLoad() && tryFoldLoad(MI)) {
3310 Changed = true;
3311 continue;
3312 }
3313
3314 if (TII->isFoldableCopy(MI)) {
3315 Changed |= tryFoldFoldableCopy(MI, CurrentKnownM0Val);
3316 continue;
3317 }
3318
3319 // Saw an unknown clobber of m0, so we no longer know what it is.
3320 if (CurrentKnownM0Val && MI.modifiesRegister(AMDGPU::M0, TRI))
3321 CurrentKnownM0Val = nullptr;
3322
3323 // TODO: Omod might be OK if there is NSZ only on the source
3324 // instruction, and not the omod multiply.
3325 if (IsIEEEMode || !MI.getFlag(MachineInstr::FmNsz) || !tryFoldOMod(MI))
3326 Changed |= tryFoldClamp(MI);
3327 }
3328
3329 Changed |= tryOptimizeAGPRPhis(*MBB);
3330 }
3331
3332 return Changed;
3333}
3334
3335PreservedAnalyses
3338 MFPropsModifier _(*this, MF);
3339
3340 const MachineLoopInfo *MLI = &MFAM.getResult<MachineLoopAnalysis>(MF);
3341 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
3342 if (!Changed) {
3343 return PreservedAnalyses::all();
3344 }
3346 PA.preserveSet<CFGAnalyses>();
3347 PA.preserve<MachineLoopAnalysis>();
3348 return PA;
3349}
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:881
@ 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.