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