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