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