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