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 Old.ChangeToImmediate(*ImmVal);
714 return true;
715 }
716
717 if (Fold.isGlobal()) {
718 Old.ChangeToGA(Fold.Def.OpToFold->getGlobal(),
719 Fold.Def.OpToFold->getOffset(),
720 Fold.Def.OpToFold->getTargetFlags());
721 return true;
722 }
723
724 if (Fold.isFI()) {
725 Old.ChangeToFrameIndex(Fold.getFI());
726 return true;
727 }
728
729 MachineOperand *New = Fold.Def.OpToFold;
730
731 // Verify the register is compatible with the operand.
732 if (const TargetRegisterClass *OpRC =
733 TII->getRegClass(MI->getDesc(), Fold.UseOpNo)) {
734 const TargetRegisterClass *NewRC =
735 TRI->getRegClassForReg(*MRI, New->getReg());
736
737 const TargetRegisterClass *ConstrainRC = OpRC;
738 if (New->getSubReg()) {
739 ConstrainRC =
740 TRI->getMatchingSuperRegClass(NewRC, OpRC, New->getSubReg());
741
742 if (!ConstrainRC)
743 return false;
744 }
745
746 if (New->getReg().isVirtual() &&
747 !MRI->constrainRegClass(New->getReg(), ConstrainRC)) {
748 LLVM_DEBUG(dbgs() << "Cannot constrain " << printReg(New->getReg(), TRI)
749 << TRI->getRegClassName(ConstrainRC) << '\n');
750 return false;
751 }
752 }
753
754 // Rework once the VS_16 register class is updated to include proper
755 // 16-bit SGPRs instead of 32-bit ones.
756 if (Old.getSubReg() == AMDGPU::lo16 && TRI->isSGPRReg(*MRI, New->getReg()))
757 Old.setSubReg(AMDGPU::NoSubRegister);
758 if (New->getReg().isPhysical()) {
759 Old.substPhysReg(New->getReg(), *TRI);
760 } else {
761 Register OldReg = Old.getReg();
762 Old.substVirtReg(New->getReg(), New->getSubReg(), *TRI);
763 Old.setIsUndef(New->isUndef());
764
765 // If MI is in a BUNDLE, also update header's matching implicit use.
766 if (MI->isBundledWithPred()) {
767 MachineInstr &Header = *getBundleStart(MI->getIterator());
768 for (MachineOperand &MO : Header.operands()) {
769 if (MO.getReg() == OldReg) {
770 MO.setReg(New->getReg());
771 MO.setSubReg(New->getSubReg());
772 }
773 }
774 }
775 }
776 return true;
777}
778
780 FoldCandidate &&Entry) {
781 // Skip additional folding on the same operand.
782 for (FoldCandidate &Fold : FoldList)
783 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
784 return;
785 LLVM_DEBUG(dbgs() << "Append " << (Entry.Commuted ? "commuted" : "normal")
786 << " operand " << Entry.UseOpNo << "\n " << *Entry.UseMI);
787 FoldList.push_back(Entry);
788}
789
791 MachineInstr *MI, unsigned OpNo,
792 const FoldableDef &FoldOp,
793 bool Commuted = false, int ShrinkOp = -1) {
794 appendFoldCandidate(FoldList,
795 FoldCandidate(MI, OpNo, FoldOp, Commuted, ShrinkOp));
796}
797
798// Returns true if the instruction is a packed F32 instruction and the
799// corresponding scalar operand reads 32 bits and replicates the bits to both
800// channels.
802 const GCNSubtarget *ST, MachineInstr *MI, unsigned OpNo) {
803 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
804 return false;
805 const MCOperandInfo &OpDesc = MI->getDesc().operands()[OpNo];
807}
808
809// Packed FP32 instructions only read 32 bits from a scalar operand (SGPR or
810// literal) and replicates the bits to both channels. Therefore, if the hi and
811// lo are not same, we can't fold it.
813 const FoldableDef &OpToFold) {
814 assert(OpToFold.isImm() && "Expected immediate operand");
815 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
816 uint32_t Lo = Lo_32(ImmVal);
817 uint32_t Hi = Hi_32(ImmVal);
818 return Lo == Hi;
819}
820
821bool SIFoldOperandsImpl::tryAddToFoldList(
822 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *MI, unsigned OpNo,
823 const FoldableDef &OpToFold) const {
824 const unsigned Opc = MI->getOpcode();
825
826 auto tryToFoldAsFMAAKorMK = [&]() {
827 if (!OpToFold.isImm())
828 return false;
829
830 const bool TryAK = OpNo == 3;
831 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
832 MI->setDesc(TII->get(NewOpc));
833
834 // We have to fold into operand which would be Imm not into OpNo.
835 bool FoldAsFMAAKorMK =
836 tryAddToFoldList(FoldList, MI, TryAK ? 3 : 2, OpToFold);
837 if (FoldAsFMAAKorMK) {
838 // Untie Src2 of fmac.
839 MI->untieRegOperand(3);
840 // For fmamk swap operands 1 and 2 if OpToFold was meant for operand 1.
841 if (OpNo == 1) {
842 MachineOperand &Op1 = MI->getOperand(1);
843 MachineOperand &Op2 = MI->getOperand(2);
844 Register OldReg = Op1.getReg();
845 // Operand 2 might be an inlinable constant
846 if (Op2.isImm()) {
847 Op1.ChangeToImmediate(Op2.getImm());
848 Op2.ChangeToRegister(OldReg, false);
849 } else {
850 Op1.setReg(Op2.getReg());
851 Op2.setReg(OldReg);
852 }
853 }
854 return true;
855 }
856 MI->setDesc(TII->get(Opc));
857 return false;
858 };
859
860 bool IsLegal = OpToFold.isOperandLegal(*TII, *MI, OpNo);
861 if (!IsLegal && OpToFold.isImm()) {
862 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
863 IsLegal = canUseImmWithOpSel(MI, OpNo, *ImmVal);
864 }
865
866 if (!IsLegal) {
867 // Special case for v_mac_{f16, f32}_e64 if we are trying to fold into src2
868 unsigned NewOpc = macToMad(Opc);
869 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
870 // Check if changing this to a v_mad_{f16, f32} instruction will allow us
871 // to fold the operand.
872 MI->setDesc(TII->get(NewOpc));
873 bool AddOpSel = !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::op_sel) &&
874 AMDGPU::hasNamedOperand(NewOpc, AMDGPU::OpName::op_sel);
875 if (AddOpSel)
876 MI->addOperand(MachineOperand::CreateImm(0));
877 bool FoldAsMAD = tryAddToFoldList(FoldList, MI, OpNo, OpToFold);
878 if (FoldAsMAD) {
879 MI->untieRegOperand(OpNo);
880 return true;
881 }
882 if (AddOpSel)
883 MI->removeOperand(MI->getNumExplicitOperands() - 1);
884 MI->setDesc(TII->get(Opc));
885 }
886
887 // Special case for s_fmac_f32 if we are trying to fold into Src2.
888 // By transforming into fmaak we can untie Src2 and make folding legal.
889 if (Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
890 if (tryToFoldAsFMAAKorMK())
891 return true;
892 }
893
894 // Special case for s_setreg_b32
895 if (OpToFold.isImm()) {
896 unsigned ImmOpc = 0;
897 if (Opc == AMDGPU::S_SETREG_B32)
898 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
899 else if (Opc == AMDGPU::S_SETREG_B32_mode)
900 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
901 if (ImmOpc) {
902 MI->setDesc(TII->get(ImmOpc));
903 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
904 return true;
905 }
906 }
907
908 // Operand is not legal, so try to commute the instruction to
909 // see if this makes it possible to fold.
910 unsigned CommuteOpNo = TargetInstrInfo::CommuteAnyOperandIndex;
911 bool CanCommute = TII->findCommutedOpIndices(*MI, OpNo, CommuteOpNo);
912 if (!CanCommute)
913 return false;
914
915 MachineOperand &Op = MI->getOperand(OpNo);
916 MachineOperand &CommutedOp = MI->getOperand(CommuteOpNo);
917
918 // One of operands might be an Imm operand, and OpNo may refer to it after
919 // the call of commuteInstruction() below. Such situations are avoided
920 // here explicitly as OpNo must be a register operand to be a candidate
921 // for memory folding.
922 if (!Op.isReg() || !CommutedOp.isReg())
923 return false;
924
925 // The same situation with an immediate could reproduce if both inputs are
926 // the same register.
927 if (Op.isReg() && CommutedOp.isReg() &&
928 (Op.getReg() == CommutedOp.getReg() &&
929 Op.getSubReg() == CommutedOp.getSubReg()))
930 return false;
931
932 if (!TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo))
933 return false;
934
935 int Op32 = -1;
936 if (!OpToFold.isOperandLegal(*TII, *MI, CommuteOpNo)) {
937 if ((Opc != AMDGPU::V_ADD_CO_U32_e64 && Opc != AMDGPU::V_SUB_CO_U32_e64 &&
938 Opc != AMDGPU::V_SUBREV_CO_U32_e64) || // FIXME
939 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
940 TII->commuteInstruction(*MI, false, OpNo, CommuteOpNo);
941 return false;
942 }
943
944 // Verify the other operand is a VGPR, otherwise we would violate the
945 // constant bus restriction.
946 MachineOperand &OtherOp = MI->getOperand(OpNo);
947 if (!OtherOp.isReg() ||
948 !TII->getRegisterInfo().isVGPR(*MRI, OtherOp.getReg()))
949 return false;
950
951 assert(MI->getOperand(1).isDef());
952
953 // Make sure to get the 32-bit version of the commuted opcode.
954 unsigned MaybeCommutedOpc = MI->getOpcode();
955 Op32 = AMDGPU::getVOPe32(MaybeCommutedOpc);
956 }
957
958 appendFoldCandidate(FoldList, MI, CommuteOpNo, OpToFold, /*Commuted=*/true,
959 Op32);
960 return true;
961 }
962
963 // Special case for s_fmac_f32 if we are trying to fold into Src0 or Src1.
964 // By changing into fmamk we can untie Src2.
965 // If folding for Src0 happens first and it is identical operand to Src1 we
966 // should avoid transforming into fmamk which requires commuting as it would
967 // cause folding into Src1 to fail later on due to wrong OpNo used.
968 if (Opc == AMDGPU::S_FMAC_F32 &&
969 (OpNo != 1 || !MI->getOperand(1).isIdenticalTo(MI->getOperand(2)))) {
970 if (tryToFoldAsFMAAKorMK())
971 return true;
972 }
973
974 // Special case for PK_F32 instructions if we are trying to fold an imm to
975 // src0 or src1.
976 if (OpToFold.isImm() &&
979 return false;
980
981 appendFoldCandidate(FoldList, MI, OpNo, OpToFold);
982 return true;
983}
984
985bool SIFoldOperandsImpl::isUseSafeToFold(const MachineInstr &MI,
986 const MachineOperand &UseMO) const {
987 // Operands of SDWA instructions must be registers.
988 return !TII->isSDWA(MI);
989}
990
991// Returns true if any instruction in \p L modifies EXEC.
992static bool loopModifiesExec(const MachineLoop &L, const SIRegisterInfo &TRI) {
993 for (const MachineBasicBlock *MBB : L.getBlocks())
994 for (const MachineInstr &MI : *MBB)
995 if (MI.modifiesRegister(TRI.getExec(), &TRI))
996 return true;
997 return false;
998}
999
1000// An SGPR->VGPR copy inside a divergent loop latches each lane value as it
1001// exits. Folding its scalar source into a use after the loop would make every
1002// lane read the same reconverged value, so do not fold across the loop exit.
1003bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1004 const FoldableDef &OpToFold, const MachineInstr &UseMI) const {
1005 if (!OpToFold.isReg())
1006 return false;
1007 const MachineInstr *DefMI = OpToFold.DefMI;
1008 if (!DefMI || !DefMI->isCopy() ||
1009 TRI->isSGPRReg(*MRI, DefMI->getOperand(0).getReg()) ||
1010 !TRI->isSGPRReg(*MRI, OpToFold.getReg()))
1011 return false;
1012 const MachineLoop *DefLoop = MLI->getLoopFor(DefMI->getParent());
1013 return DefLoop && !DefLoop->contains(UseMI.getParent()) &&
1014 loopModifiesExec(*DefLoop, *TRI);
1015}
1016
1018 const MachineRegisterInfo &MRI,
1019 Register SrcReg) {
1020 MachineOperand *Sub = nullptr;
1021 for (MachineInstr *SubDef = MRI.getVRegDef(SrcReg);
1022 SubDef && TII.isFoldableCopy(*SubDef);
1023 SubDef = MRI.getVRegDef(Sub->getReg())) {
1024 unsigned SrcIdx = TII.getFoldableCopySrcIdx(*SubDef);
1025 MachineOperand &SrcOp = SubDef->getOperand(SrcIdx);
1026
1027 if (SrcOp.isImm())
1028 return &SrcOp;
1029 if (!SrcOp.isReg() || SrcOp.getReg().isPhysical())
1030 break;
1031 Sub = &SrcOp;
1032 // TODO: Support compose
1033 if (SrcOp.getSubReg())
1034 break;
1035 }
1036
1037 return Sub;
1038}
1039
1040const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
1041 MachineInstr &RegSeq,
1042 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs) const {
1043
1044 assert(RegSeq.isRegSequence());
1045
1046 const TargetRegisterClass *RC = nullptr;
1047
1048 for (unsigned I = 1, E = RegSeq.getNumExplicitOperands(); I != E; I += 2) {
1049 MachineOperand &SrcOp = RegSeq.getOperand(I);
1050 if (SrcOp.getReg().isPhysical())
1051 return nullptr;
1052 unsigned SubRegIdx = RegSeq.getOperand(I + 1).getImm();
1053
1054 // Only accept reg_sequence with uniform reg class inputs for simplicity.
1055 const TargetRegisterClass *OpRC = getRegOpRC(*MRI, *TRI, SrcOp);
1056 if (!RC)
1057 RC = OpRC;
1058 else if (!TRI->getCommonSubClass(RC, OpRC))
1059 return nullptr;
1060
1061 if (SrcOp.getSubReg()) {
1062 // TODO: Handle subregister compose
1063 Defs.emplace_back(&SrcOp, SubRegIdx);
1064 continue;
1065 }
1066
1067 MachineOperand *DefSrc = lookUpCopyChain(*TII, *MRI, SrcOp.getReg());
1068 if (DefSrc && (DefSrc->isReg() || DefSrc->isImm())) {
1069 Defs.emplace_back(DefSrc, SubRegIdx);
1070 continue;
1071 }
1072
1073 Defs.emplace_back(&SrcOp, SubRegIdx);
1074 }
1075
1076 return RC;
1077}
1078
1079// Find a def of the UseReg, check if it is a reg_sequence and find initializers
1080// for each subreg, tracking it to an immediate if possible. Returns the
1081// register class of the inputs on success.
1082const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit(
1083 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1084 Register UseReg) const {
1085 MachineInstr *Def = MRI->getVRegDef(UseReg);
1086 if (!Def || !Def->isRegSequence())
1087 return nullptr;
1088
1089 return getRegSeqInit(*Def, Defs);
1090}
1091
1092std::pair<int64_t, const TargetRegisterClass *>
1093SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const {
1095 const TargetRegisterClass *SrcRC = getRegSeqInit(RegSeq, Defs);
1096 if (!SrcRC)
1097 return {};
1098
1099 bool TryToMatchSplat64 = false;
1100
1101 std::optional<int64_t> Imm;
1102 for (unsigned I = 0, E = Defs.size(); I != E; ++I) {
1103 const MachineOperand *Op = Defs[I].first;
1104 if (!Op->isImm()) {
1105 if (Op->isReg()) {
1106 MachineInstr *Def = MRI->getVRegDef(Op->getReg());
1107 if (!Def || Def->isImplicitDef())
1108 continue;
1109 }
1110 return {};
1111 }
1112
1113 int64_t SubImm = Op->getImm();
1114 if (!Imm) {
1115 Imm = SubImm;
1116 continue;
1117 }
1118
1119 if (Imm != SubImm) {
1120 if (I == 1 && (E & 1) == 0) {
1121 // If we have an even number of inputs, there's a chance this is a
1122 // 64-bit element splat broken into 32-bit pieces.
1123 TryToMatchSplat64 = true;
1124 break;
1125 }
1126
1127 return {}; // Can only fold splat constants
1128 }
1129 }
1130
1131 if (!TryToMatchSplat64) {
1132 if (Imm)
1133 return {*Imm, SrcRC};
1134 return {};
1135 }
1136
1137 // Fallback to recognizing 64-bit splats broken into 32-bit pieces
1138 // (i.e. recognize every other other element is 0 for 64-bit immediates)
1139 int64_t SplatVal64;
1140 for (unsigned I = 0, E = Defs.size(); I != E; I += 2) {
1141 const MachineOperand *Op0 = Defs[I].first;
1142 const MachineOperand *Op1 = Defs[I + 1].first;
1143
1144 if (!Op0->isImm() || !Op1->isImm())
1145 return {};
1146
1147 unsigned SubReg0 = Defs[I].second;
1148 unsigned SubReg1 = Defs[I + 1].second;
1149
1150 // Assume we're going to generally encounter reg_sequences with sorted
1151 // subreg indexes, so reject any that aren't consecutive.
1152 if (TRI->getChannelFromSubReg(SubReg0) + 1 !=
1153 TRI->getChannelFromSubReg(SubReg1))
1154 return {};
1155
1156 if (TRI->getSubRegIdxSize(SubReg0) != 32)
1157 return {};
1158
1159 int64_t MergedVal = Make_64(Op1->getImm(), Op0->getImm());
1160 if (I == 0)
1161 SplatVal64 = MergedVal;
1162 else if (SplatVal64 != MergedVal)
1163 return {};
1164 }
1165
1166 const TargetRegisterClass *RC64 = TRI->getSubRegisterClass(
1167 MRI->getRegClass(RegSeq.getOperand(0).getReg()), AMDGPU::sub0_sub1);
1168
1169 return {SplatVal64, RC64};
1170}
1171
1172bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1173 MachineInstr *UseMI, unsigned UseOpIdx, int64_t SplatVal,
1174 const TargetRegisterClass *SplatRC) const {
1175 const MCInstrDesc &Desc = UseMI->getDesc();
1176 if (UseOpIdx >= Desc.getNumOperands())
1177 return false;
1178
1179 // Filter out unhandled pseudos.
1180 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1181 return false;
1182
1183 int16_t RCID = TII->getOpRegClassID(Desc.operands()[UseOpIdx]);
1184 if (RCID == -1)
1185 return false;
1186
1187 const TargetRegisterClass *OpRC = TRI->getRegClass(RCID);
1188
1189 // Special case 0/-1, since when interpreted as a 64-bit element both halves
1190 // have the same bits. These are the only cases where a splat has the same
1191 // interpretation for 32-bit and 64-bit splats.
1192 if (SplatVal != 0 && SplatVal != -1) {
1193 // We need to figure out the scalar type read by the operand. e.g. the MFMA
1194 // operand will be AReg_128, and we want to check if it's compatible with an
1195 // AReg_32 constant.
1196 uint8_t OpTy = Desc.operands()[UseOpIdx].OperandType;
1197 switch (OpTy) {
1203 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1204 break;
1210 OpRC = TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1211 break;
1212 default:
1213 return false;
1214 }
1215
1216 if (!TRI->getCommonSubClass(OpRC, SplatRC))
1217 return false;
1218 }
1219
1220 MachineOperand TmpOp = MachineOperand::CreateImm(SplatVal);
1221 if (!TII->isOperandLegal(*UseMI, UseOpIdx, &TmpOp))
1222 return false;
1223
1224 return true;
1225}
1226
1227bool SIFoldOperandsImpl::tryToFoldACImm(
1228 const FoldableDef &OpToFold, MachineInstr *UseMI, unsigned UseOpIdx,
1229 SmallVectorImpl<FoldCandidate> &FoldList) const {
1230 const MCInstrDesc &Desc = UseMI->getDesc();
1231 if (UseOpIdx >= Desc.getNumOperands())
1232 return false;
1233
1234 // Filter out unhandled pseudos.
1235 if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx))
1236 return false;
1237
1238 if (OpToFold.isImm() && OpToFold.isOperandLegal(*TII, *UseMI, UseOpIdx)) {
1241 return false;
1242 appendFoldCandidate(FoldList, UseMI, UseOpIdx, OpToFold);
1243 return true;
1244 }
1245
1246 return false;
1247}
1248
1249bool SIFoldOperandsImpl::foldOperand(
1250 FoldableDef OpToFold, MachineInstr *UseMI, int UseOpIdx,
1251 SmallVectorImpl<FoldCandidate> &FoldList,
1252 SmallVectorImpl<MachineInstr *> &CopiesToReplace) const {
1253 bool Changed = false;
1254 const MachineOperand *UseOp = &UseMI->getOperand(UseOpIdx);
1255
1256 if (!isUseSafeToFold(*UseMI, *UseOp))
1257 return Changed;
1258
1259 if (isTemporallyDivergentUse(OpToFold, *UseMI))
1260 return Changed;
1261
1262 // FIXME: Fold operands with subregs.
1263 if (UseOp->isReg() && OpToFold.isReg()) {
1264 if (UseOp->isImplicit())
1265 return Changed;
1266 // Allow folding from SGPRs to 16-bit VGPRs.
1267 if (UseOp->getSubReg() != AMDGPU::NoSubRegister &&
1268 (UseOp->getSubReg() != AMDGPU::lo16 ||
1269 !TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1270 return Changed;
1271 }
1272
1273 // Special case for REG_SEQUENCE: We can't fold literals into
1274 // REG_SEQUENCE instructions, so we have to fold them into the
1275 // uses of REG_SEQUENCE.
1276 if (UseMI->isRegSequence()) {
1277 Register RegSeqDstReg = UseMI->getOperand(0).getReg();
1278 unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
1279
1280 int64_t SplatVal;
1281 const TargetRegisterClass *SplatRC;
1282 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*UseMI);
1283
1284 // Grab the use operands first
1286 llvm::make_pointer_range(MRI->use_nodbg_operands(RegSeqDstReg)));
1287 for (unsigned I = 0; I != UsesToProcess.size(); ++I) {
1288 MachineOperand *RSUse = UsesToProcess[I];
1289 MachineInstr *RSUseMI = RSUse->getParent();
1290 unsigned OpNo = RSUseMI->getOperandNo(RSUse);
1291
1292 if (SplatRC) {
1293 if (RSUseMI->isCopy()) {
1294 Register DstReg = RSUseMI->getOperand(0).getReg();
1295 append_range(UsesToProcess,
1297 continue;
1298 }
1299 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1300 FoldableDef SplatDef(SplatVal, SplatRC);
1301 appendFoldCandidate(FoldList, RSUseMI, OpNo, SplatDef);
1302 Changed = true;
1303 continue;
1304 }
1305 }
1306
1307 // TODO: Handle general compose
1308 if (RSUse->getSubReg() != RegSeqDstSubReg)
1309 continue;
1310
1311 // FIXME: We should avoid recursing here. There should be a cleaner split
1312 // between the in-place mutations and adding to the fold list.
1313 Changed |= foldOperand(OpToFold, RSUseMI, RSUseMI->getOperandNo(RSUse),
1314 FoldList, CopiesToReplace);
1315 }
1316
1317 return Changed;
1318 }
1319
1320 if (tryToFoldACImm(OpToFold, UseMI, UseOpIdx, FoldList))
1321 return true;
1322
1323 if (frameIndexMayFold(*UseMI, UseOpIdx, OpToFold)) {
1324 // Verify that this is a stack access.
1325 // FIXME: Should probably use stack pseudos before frame lowering.
1326
1327 if (TII->isMUBUF(*UseMI)) {
1328 if (TII->getNamedOperand(*UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1329 MFI->getScratchRSrcReg())
1330 return Changed;
1331
1332 // Ensure this is either relative to the current frame or the current
1333 // wave.
1334 MachineOperand &SOff =
1335 *TII->getNamedOperand(*UseMI, AMDGPU::OpName::soffset);
1336 if (!SOff.isImm() || SOff.getImm() != 0)
1337 return Changed;
1338 }
1339
1340 const unsigned Opc = UseMI->getOpcode();
1341 if (TII->isFLATScratch(*UseMI) &&
1342 AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr) &&
1343 !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::saddr)) {
1344 unsigned NewOpc = AMDGPU::getFlatScratchInstSSfromSV(Opc);
1345 unsigned CPol =
1346 TII->getNamedOperand(*UseMI, AMDGPU::OpName::cpol)->getImm();
1347 if ((CPol & AMDGPU::CPol::SCAL) &&
1349 return Changed;
1350
1351 UseMI->setDesc(TII->get(NewOpc));
1352 }
1353
1354 // A frame index will resolve to a positive constant, so it should always be
1355 // safe to fold the addressing mode, even pre-GFX9.
1356 UseMI->getOperand(UseOpIdx).ChangeToFrameIndex(OpToFold.getFI());
1357
1358 return true;
1359 }
1360
1361 bool FoldingImmLike =
1362 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1363
1364 if (FoldingImmLike && UseMI->isCopy()) {
1365 Register DestReg = UseMI->getOperand(0).getReg();
1366 Register SrcReg = UseMI->getOperand(1).getReg();
1367 unsigned UseSubReg = UseMI->getOperand(1).getSubReg();
1368 assert(SrcReg.isVirtual());
1369
1370 const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg);
1371
1372 // Don't fold into a copy to a physical register with the same class. Doing
1373 // so would interfere with the register coalescer's logic which would avoid
1374 // redundant initializations.
1375 if (DestReg.isPhysical() && SrcRC->contains(DestReg))
1376 return Changed;
1377
1378 const TargetRegisterClass *DestRC = TRI->getRegClassForReg(*MRI, DestReg);
1379 // In order to fold immediates into copies, we need to change the copy to a
1380 // MOV. Find a compatible mov instruction with the value.
1381 for (unsigned MovOp :
1382 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1383 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1384 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1385 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1386 const MCInstrDesc &MovDesc = TII->get(MovOp);
1387 const TargetRegisterClass *MovDstRC =
1388 TRI->getRegClass(TII->getOpRegClassID(MovDesc.operands()[0]));
1389
1390 // Fold if the destination register class of the MOV instruction (ResRC)
1391 // is a superclass of (or equal to) the destination register class of the
1392 // COPY (DestRC). If this condition fails, folding would be illegal.
1393 if (!DestRC->hasSuperClassEq(MovDstRC))
1394 continue;
1395
1396 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1397
1398 int16_t RegClassID = TII->getOpRegClassID(MovDesc.operands()[SrcIdx]);
1399 if (RegClassID != -1) {
1400 const TargetRegisterClass *MovSrcRC = TRI->getRegClass(RegClassID);
1401
1402 if (UseSubReg)
1403 MovSrcRC = TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1404
1405 // FIXME: We should be able to directly check immediate operand legality
1406 // for all cases, but gfx908 hacks break.
1407 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1408 (!OpToFold.isImm() ||
1409 !TII->isImmOperandLegal(MovDesc, SrcIdx,
1410 *OpToFold.getEffectiveImmVal())))
1411 break;
1412
1413 if (!MRI->constrainRegClass(SrcReg, MovSrcRC))
1414 break;
1415
1416 // FIXME: This is mutating the instruction only and deferring the actual
1417 // fold of the immediate
1418 } else {
1419 // For the _IMM_PSEUDO cases, there can be value restrictions on the
1420 // immediate to verify. Technically we should always verify this, but it
1421 // only matters for these concrete cases.
1422 // TODO: Handle non-imm case if it's useful.
1423 if (!OpToFold.isImm() ||
1424 !TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1425 break;
1426 }
1427
1430 while (ImpOpI != ImpOpE) {
1431 MachineInstr::mop_iterator Tmp = ImpOpI;
1432 ImpOpI++;
1434 }
1435 UseMI->setDesc(MovDesc);
1436
1437 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1438 const auto &SrcOp = UseMI->getOperand(UseOpIdx);
1439 MachineOperand NewSrcOp(SrcOp);
1440 UseMI->removeOperand(1);
1441 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // src0_modifiers
1442 UseMI->addOperand(NewSrcOp); // src0
1443 UseMI->addOperand(*MF, MachineOperand::CreateImm(0)); // op_sel
1444 UseOpIdx = SrcIdx;
1445 UseOp = &UseMI->getOperand(UseOpIdx);
1446 }
1447 CopiesToReplace.push_back(UseMI);
1448 Changed = true;
1449 break;
1450 }
1451
1452 // We failed to replace the copy, so give up.
1453 if (UseMI->getOpcode() == AMDGPU::COPY)
1454 return Changed;
1455
1456 } else {
1457 if (UseMI->isCopy() && OpToFold.isReg() &&
1458 UseMI->getOperand(0).getReg().isVirtual() &&
1459 !UseMI->getOperand(1).getSubReg() &&
1460 OpToFold.DefMI->implicit_operands().empty()) {
1461 LLVM_DEBUG(dbgs() << "Folding " << *OpToFold.OpToFold << "\n into "
1462 << *UseMI);
1463 unsigned Size = TII->getOpSize(*UseMI, 1);
1464 Register UseReg = OpToFold.getReg();
1466 unsigned SubRegIdx = OpToFold.getSubReg();
1467 // Hack to allow 32-bit SGPRs to be folded into True16 instructions
1468 // Remove this if 16-bit SGPRs (i.e. SGPR_LO16) are added to the
1469 // VS_16RegClass
1470 //
1471 // Excerpt from AMDGPUGenRegisterInfoEnums.inc
1472 // NoSubRegister, //0
1473 // hi16, // 1
1474 // lo16, // 2
1475 // sub0, // 3
1476 // ...
1477 // sub1, // 11
1478 // sub1_hi16, // 12
1479 // sub1_lo16, // 13
1480 static_assert(AMDGPU::sub1_hi16 == 12, "Subregister layout has changed");
1481 if (Size == 2 && TRI->isVGPR(*MRI, UseMI->getOperand(0).getReg()) &&
1482 TRI->isSGPRReg(*MRI, UseReg)) {
1483 // Produce the 32 bit subregister index to which the 16-bit subregister
1484 // is aligned.
1485 if (SubRegIdx > AMDGPU::sub1) {
1486 LaneBitmask M = TRI->getSubRegIndexLaneMask(SubRegIdx);
1487 M |= M.getLane(M.getHighestLane() - 1);
1488 SmallVector<unsigned, 4> Indexes;
1489 TRI->getCoveringSubRegIndexes(TRI->getRegClassForReg(*MRI, UseReg), M,
1490 Indexes);
1491 assert(Indexes.size() == 1 && "Expected one 32-bit subreg to cover");
1492 SubRegIdx = Indexes[0];
1493 // 32-bit registers do not have a sub0 index
1494 } else if (TII->getOpSize(*UseMI, 1) == 4)
1495 SubRegIdx = 0;
1496 else
1497 SubRegIdx = AMDGPU::sub0;
1498 }
1499 UseMI->getOperand(1).setSubReg(SubRegIdx);
1500 UseMI->getOperand(1).setIsKill(false);
1501 CopiesToReplace.push_back(UseMI);
1502 OpToFold.OpToFold->setIsKill(false);
1503 Changed = true;
1504
1505 // Remove kill flags as kills may now be out of order with uses.
1506 MRI->clearKillFlags(UseReg);
1507 if (foldCopyToAGPRRegSequence(UseMI))
1508 return true;
1509 }
1510
1511 unsigned UseOpc = UseMI->getOpcode();
1512 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1513 (UseOpc == AMDGPU::V_READLANE_B32 &&
1514 (int)UseOpIdx ==
1515 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1516 // %vgpr = V_MOV_B32 imm
1517 // %sgpr = V_READFIRSTLANE_B32 %vgpr
1518 // =>
1519 // %sgpr = S_MOV_B32 imm
1520 if (FoldingImmLike) {
1522 UseMI->getOperand(UseOpIdx).getReg(),
1523 *OpToFold.DefMI, *UseMI))
1524 return Changed;
1525
1526 UseMI->setDesc(TII->get(AMDGPU::S_MOV_B32));
1528
1529 if (OpToFold.isImm()) {
1531 *OpToFold.getEffectiveImmVal());
1532 } else if (OpToFold.isFI())
1533 UseMI->getOperand(1).ChangeToFrameIndex(OpToFold.getFI());
1534 else {
1535 assert(OpToFold.isGlobal());
1536 UseMI->getOperand(1).ChangeToGA(OpToFold.OpToFold->getGlobal(),
1537 OpToFold.OpToFold->getOffset(),
1538 OpToFold.OpToFold->getTargetFlags());
1539 }
1540 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1541 return true;
1542 }
1543
1544 if (OpToFold.isReg() && TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1546 UseMI->getOperand(UseOpIdx).getReg(),
1547 *OpToFold.DefMI, *UseMI))
1548 return Changed;
1549
1550 // %vgpr = COPY %sgpr0
1551 // %sgpr1 = V_READFIRSTLANE_B32 %vgpr
1552 // =>
1553 // %sgpr1 = COPY %sgpr0
1554 UseMI->setDesc(TII->get(AMDGPU::COPY));
1555 UseMI->getOperand(1).setReg(OpToFold.getReg());
1556 UseMI->getOperand(1).setSubReg(OpToFold.getSubReg());
1557 UseMI->getOperand(1).setIsKill(false);
1558 UseMI->removeOperand(2); // Remove exec read (or src1 for readlane)
1560 return true;
1561 }
1562 }
1563
1564 const MCInstrDesc &UseDesc = UseMI->getDesc();
1565
1566 // Don't fold into target independent nodes. Target independent opcodes
1567 // don't have defined register classes.
1568 if (UseDesc.isVariadic() || UseOp->isImplicit() ||
1569 UseDesc.operands()[UseOpIdx].RegClass == -1)
1570 return Changed;
1571 }
1572
1573 // FIXME: We could try to change the instruction from 64-bit to 32-bit
1574 // to enable more folding opportunities. The shrink operands pass
1575 // already does this.
1576
1577 Changed |= tryAddToFoldList(FoldList, UseMI, UseOpIdx, OpToFold);
1578 return Changed;
1579}
1580
1581static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result,
1583 switch (Opcode) {
1584 case AMDGPU::S_ADD_I32:
1585 case AMDGPU::S_ADD_U32:
1586 Result = LHS + RHS;
1587 return true;
1588 case AMDGPU::S_SUB_I32:
1589 case AMDGPU::S_SUB_U32:
1590 Result = LHS - RHS;
1591 return true;
1592 case AMDGPU::V_AND_B32_e64:
1593 case AMDGPU::V_AND_B32_e32:
1594 case AMDGPU::S_AND_B32:
1595 Result = LHS & RHS;
1596 return true;
1597 case AMDGPU::V_OR_B32_e64:
1598 case AMDGPU::V_OR_B32_e32:
1599 case AMDGPU::S_OR_B32:
1600 Result = LHS | RHS;
1601 return true;
1602 case AMDGPU::V_XOR_B32_e64:
1603 case AMDGPU::V_XOR_B32_e32:
1604 case AMDGPU::S_XOR_B32:
1605 Result = LHS ^ RHS;
1606 return true;
1607 case AMDGPU::S_XNOR_B32:
1608 Result = ~(LHS ^ RHS);
1609 return true;
1610 case AMDGPU::S_NAND_B32:
1611 Result = ~(LHS & RHS);
1612 return true;
1613 case AMDGPU::S_NOR_B32:
1614 Result = ~(LHS | RHS);
1615 return true;
1616 case AMDGPU::S_ANDN2_B32:
1617 Result = LHS & ~RHS;
1618 return true;
1619 case AMDGPU::S_ORN2_B32:
1620 Result = LHS | ~RHS;
1621 return true;
1622 case AMDGPU::V_LSHL_B32_e64:
1623 case AMDGPU::V_LSHL_B32_e32:
1624 case AMDGPU::S_LSHL_B32:
1625 // The instruction ignores the high bits for out of bounds shifts.
1626 Result = LHS << (RHS & 31);
1627 return true;
1628 case AMDGPU::V_LSHLREV_B32_e64:
1629 case AMDGPU::V_LSHLREV_B32_e32:
1630 Result = RHS << (LHS & 31);
1631 return true;
1632 case AMDGPU::V_LSHR_B32_e64:
1633 case AMDGPU::V_LSHR_B32_e32:
1634 case AMDGPU::S_LSHR_B32:
1635 Result = LHS >> (RHS & 31);
1636 return true;
1637 case AMDGPU::V_LSHRREV_B32_e64:
1638 case AMDGPU::V_LSHRREV_B32_e32:
1639 Result = RHS >> (LHS & 31);
1640 return true;
1641 case AMDGPU::V_ASHR_I32_e64:
1642 case AMDGPU::V_ASHR_I32_e32:
1643 case AMDGPU::S_ASHR_I32:
1644 Result = static_cast<int32_t>(LHS) >> (RHS & 31);
1645 return true;
1646 case AMDGPU::V_ASHRREV_I32_e64:
1647 case AMDGPU::V_ASHRREV_I32_e32:
1648 Result = static_cast<int32_t>(RHS) >> (LHS & 31);
1649 return true;
1650 default:
1651 return false;
1652 }
1653}
1654
1655static unsigned getMovOpc(bool IsScalar) {
1656 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1657}
1658
1659// Try to simplify operations with a constant that may appear after instruction
1660// selection.
1661// TODO: See if a frame index with a fixed offset can fold.
1662bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *MI) const {
1663 if (!MI->allImplicitDefsAreDead())
1664 return false;
1665
1666 unsigned Opc = MI->getOpcode();
1667
1668 int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
1669 if (Src0Idx == -1)
1670 return false;
1671
1672 MachineOperand *Src0 = &MI->getOperand(Src0Idx);
1673 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*Src0);
1674
1675 if ((Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
1676 Opc == AMDGPU::S_NOT_B32) &&
1677 Src0Imm) {
1678 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1679 TII->mutateAndCleanupImplicit(
1680 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
1681 return true;
1682 }
1683
1684 int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
1685 if (Src1Idx == -1)
1686 return false;
1687
1688 MachineOperand *Src1 = &MI->getOperand(Src1Idx);
1689 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*Src1);
1690
1691 if (!Src0Imm && !Src1Imm)
1692 return false;
1693
1694 // and k0, k1 -> v_mov_b32 (k0 & k1)
1695 // or k0, k1 -> v_mov_b32 (k0 | k1)
1696 // xor k0, k1 -> v_mov_b32 (k0 ^ k1)
1697 if (Src0Imm && Src1Imm) {
1698 int32_t NewImm;
1699 if (!evalBinaryInstruction(Opc, NewImm, *Src0Imm, *Src1Imm))
1700 return false;
1701
1702 bool IsSGPR = TRI->isSGPRReg(*MRI, MI->getOperand(0).getReg());
1703
1704 // Be careful to change the right operand, src0 may belong to a different
1705 // instruction.
1706 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1707 MI->removeOperand(Src1Idx);
1708 TII->mutateAndCleanupImplicit(*MI, TII->get(getMovOpc(IsSGPR)));
1709 return true;
1710 }
1711
1712 // S_SUB_* is not commutable, so handle it before the commutability gate.
1713 // Only `x - 0 -> copy x` is valid; `0 - x` is a negation, not a copy.
1714 if (Opc == AMDGPU::S_SUB_I32 || Opc == AMDGPU::S_SUB_U32) {
1715 if (Src1Imm && static_cast<int32_t>(*Src1Imm) == 0) {
1716 // y = sub x, 0 => y = copy x
1717 MI->removeOperand(Src1Idx);
1718 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1719 return true;
1720 }
1721 return false;
1722 }
1723
1724 if (!MI->isCommutable())
1725 return false;
1726
1727 if (Src0Imm && !Src1Imm) {
1728 std::swap(Src0, Src1);
1729 std::swap(Src0Idx, Src1Idx);
1730 std::swap(Src0Imm, Src1Imm);
1731 }
1732
1733 int32_t Src1Val = static_cast<int32_t>(*Src1Imm);
1734 if (Opc == AMDGPU::S_ADD_I32 || Opc == AMDGPU::S_ADD_U32) {
1735 if (Src1Val == 0) {
1736 // y = add 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 (Opc == AMDGPU::V_OR_B32_e64 ||
1745 Opc == AMDGPU::V_OR_B32_e32 ||
1746 Opc == AMDGPU::S_OR_B32) {
1747 if (Src1Val == 0) {
1748 // y = or x, 0 => y = copy x
1749 MI->removeOperand(Src1Idx);
1750 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1751 } else if (Src1Val == -1) {
1752 // y = or x, -1 => y = v_mov_b32 -1
1753 MI->removeOperand(Src0Idx);
1754 TII->mutateAndCleanupImplicit(
1755 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
1756 } else
1757 return false;
1758
1759 return true;
1760 }
1761
1762 if (Opc == AMDGPU::V_AND_B32_e64 || Opc == AMDGPU::V_AND_B32_e32 ||
1763 Opc == AMDGPU::S_AND_B32) {
1764 if (Src1Val == 0) {
1765 // y = and x, 0 => y = v_mov_b32 0
1766 MI->removeOperand(Src0Idx);
1767 TII->mutateAndCleanupImplicit(
1768 *MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
1769 } else if (Src1Val == -1) {
1770 // y = and x, -1 => y = copy x
1771 MI->removeOperand(Src1Idx);
1772 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1773 } else
1774 return false;
1775
1776 return true;
1777 }
1778
1779 if (Opc == AMDGPU::V_XOR_B32_e64 || Opc == AMDGPU::V_XOR_B32_e32 ||
1780 Opc == AMDGPU::S_XOR_B32) {
1781 if (Src1Val == 0) {
1782 // y = xor x, 0 => y = copy x
1783 MI->removeOperand(Src1Idx);
1784 TII->mutateAndCleanupImplicit(*MI, TII->get(AMDGPU::COPY));
1785 return true;
1786 }
1787 }
1788
1789 return false;
1790}
1791
1792// Try to fold an instruction into a simpler one
1793bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &MI) const {
1794 unsigned Opc = MI.getOpcode();
1795 if (Opc != AMDGPU::V_CNDMASK_B32_e32 && Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1796 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1797 return false;
1798
1799 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1800 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1801 if (!Src1->isIdenticalTo(*Src0)) {
1802 std::optional<int64_t> Src1Imm = TII->getImmOrMaterializedImm(*Src1);
1803 if (!Src1Imm)
1804 return false;
1805
1806 std::optional<int64_t> Src0Imm = TII->getImmOrMaterializedImm(*Src0);
1807 if (!Src0Imm || *Src0Imm != *Src1Imm)
1808 return false;
1809 }
1810
1811 int Src1ModIdx =
1812 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1_modifiers);
1813 int Src0ModIdx =
1814 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers);
1815 if ((Src1ModIdx != -1 && MI.getOperand(Src1ModIdx).getImm() != 0) ||
1816 (Src0ModIdx != -1 && MI.getOperand(Src0ModIdx).getImm() != 0))
1817 return false;
1818
1819 LLVM_DEBUG(dbgs() << "Folded " << MI << " into ");
1820 auto &NewDesc =
1821 TII->get(Src0->isReg() ? (unsigned)AMDGPU::COPY : getMovOpc(false));
1822 int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
1823 if (Src2Idx != -1)
1824 MI.removeOperand(Src2Idx);
1825 MI.removeOperand(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1));
1826 if (Src1ModIdx != -1)
1827 MI.removeOperand(Src1ModIdx);
1828 if (Src0ModIdx != -1)
1829 MI.removeOperand(Src0ModIdx);
1830 TII->mutateAndCleanupImplicit(MI, NewDesc);
1831 LLVM_DEBUG(dbgs() << MI);
1832 return true;
1833}
1834
1835bool SIFoldOperandsImpl::tryFoldZeroHighBits(MachineInstr &MI) const {
1836 if (MI.getOpcode() != AMDGPU::V_AND_B32_e64 &&
1837 MI.getOpcode() != AMDGPU::V_AND_B32_e32)
1838 return false;
1839
1840 std::optional<int64_t> Src0Imm =
1841 TII->getImmOrMaterializedImm(MI.getOperand(1));
1842 if (!Src0Imm || *Src0Imm != 0xffff || !MI.getOperand(2).isReg())
1843 return false;
1844
1845 Register Src1 = MI.getOperand(2).getReg();
1846 MachineInstr *SrcDef = MRI->getVRegDef(Src1);
1847 if (!ST->zeroesHigh16BitsOfDest(SrcDef->getOpcode()))
1848 return false;
1849
1850 Register Dst = MI.getOperand(0).getReg();
1851 MRI->replaceRegWith(Dst, Src1);
1852 if (!MI.getOperand(2).isKill())
1853 MRI->clearKillFlags(Src1);
1854 MI.eraseFromParent();
1855 return true;
1856}
1857
1858bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &MI,
1859 const FoldableDef &OpToFold) const {
1860 // We need mutate the operands of new mov instructions to add implicit
1861 // uses of EXEC, but adding them invalidates the use_iterator, so defer
1862 // this.
1863 SmallVector<MachineInstr *, 4> CopiesToReplace;
1865 MachineOperand &Dst = MI.getOperand(0);
1866 bool Changed = false;
1867
1869 llvm::make_pointer_range(MRI->use_nodbg_operands(Dst.getReg())));
1870 for (auto *U : UsesToProcess) {
1871 MachineInstr *UseMI = U->getParent();
1872
1873 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*TRI, U->getSubReg());
1874 Changed |= foldOperand(SubOpToFold, UseMI, UseMI->getOperandNo(U), FoldList,
1875 CopiesToReplace);
1876 }
1877
1878 if (CopiesToReplace.empty() && FoldList.empty())
1879 return Changed;
1880
1881 // Make sure we add EXEC uses to any new v_mov instructions created.
1882 for (MachineInstr *Copy : CopiesToReplace)
1883 Copy->addImplicitDefUseOperands(*MF);
1884
1885 SetVector<MachineInstr *> ConstantFoldCandidates;
1886 for (FoldCandidate &Fold : FoldList) {
1887 assert(!Fold.isReg() || Fold.Def.OpToFold);
1888 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1889 Register Reg = Fold.getReg();
1890 const MachineInstr *DefMI = Fold.Def.DefMI;
1891 if (DefMI->readsRegister(AMDGPU::EXEC, TRI) &&
1892 execMayBeModifiedBeforeUse(*MRI, Reg, *DefMI, *Fold.UseMI))
1893 continue;
1894 }
1895 if (updateOperand(Fold)) {
1896 // Clear kill flags.
1897 if (Fold.isReg()) {
1898 assert(Fold.Def.OpToFold && Fold.isReg());
1899 // FIXME: Probably shouldn't bother trying to fold if not an
1900 // SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
1901 // copies.
1902 MRI->clearKillFlags(Fold.getReg());
1903 }
1904 LLVM_DEBUG(dbgs() << "Folded source from " << MI << " into OpNo "
1905 << static_cast<int>(Fold.UseOpNo) << " of "
1906 << *Fold.UseMI);
1907
1908 if (Fold.isImm())
1909 ConstantFoldCandidates.insert(Fold.UseMI);
1910
1911 } else if (Fold.Commuted) {
1912 // Restoring instruction's original operand order if fold has failed.
1913 TII->commuteInstruction(*Fold.UseMI, false);
1914 }
1915 }
1916
1917 for (MachineInstr *MI : ConstantFoldCandidates) {
1918 if (tryConstantFoldOp(MI)) {
1919 LLVM_DEBUG(dbgs() << "Constant folded " << *MI);
1920 Changed = true;
1921 }
1922 }
1923 return true;
1924}
1925
1926/// Fold %agpr = COPY (REG_SEQUENCE x_MOV_B32, ...) into REG_SEQUENCE
1927/// (V_ACCVGPR_WRITE_B32_e64) ... depending on the reg_sequence input values.
1928bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI) const {
1929 // It is very tricky to store a value into an AGPR. v_accvgpr_write_b32 can
1930 // only accept VGPR or inline immediate. Recreate a reg_sequence with its
1931 // initializers right here, so we will rematerialize immediates and avoid
1932 // copies via different reg classes.
1933 const TargetRegisterClass *DefRC =
1934 MRI->getRegClass(CopyMI->getOperand(0).getReg());
1935 if (!TRI->isAGPRClass(DefRC))
1936 return false;
1937
1938 Register UseReg = CopyMI->getOperand(1).getReg();
1939 MachineInstr *RegSeq = MRI->getVRegDef(UseReg);
1940 if (!RegSeq || !RegSeq->isRegSequence())
1941 return false;
1942
1943 const DebugLoc &DL = CopyMI->getDebugLoc();
1944 MachineBasicBlock &MBB = *CopyMI->getParent();
1945
1946 MachineInstrBuilder B(*MBB.getParent(), CopyMI);
1947 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
1948
1949 const TargetRegisterClass *UseRC =
1950 MRI->getRegClass(CopyMI->getOperand(1).getReg());
1951
1952 // Value, subregindex for new REG_SEQUENCE
1954
1955 unsigned NumRegSeqOperands = RegSeq->getNumOperands();
1956 unsigned NumFoldable = 0;
1957
1958 for (unsigned I = 1; I != NumRegSeqOperands; I += 2) {
1959 MachineOperand &RegOp = RegSeq->getOperand(I);
1960 unsigned SubRegIdx = RegSeq->getOperand(I + 1).getImm();
1961
1962 if (RegOp.getSubReg()) {
1963 // TODO: Handle subregister compose
1964 NewDefs.emplace_back(&RegOp, SubRegIdx);
1965 continue;
1966 }
1967
1968 MachineOperand *Lookup = lookUpCopyChain(*TII, *MRI, RegOp.getReg());
1969 if (!Lookup)
1970 Lookup = &RegOp;
1971
1972 if (Lookup->isImm()) {
1973 // Check if this is an agpr_32 subregister.
1974 const TargetRegisterClass *DestSuperRC = TRI->getMatchingSuperRegClass(
1975 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
1976 if (DestSuperRC &&
1977 TII->isInlineConstant(*Lookup, AMDGPU::OPERAND_REG_INLINE_C_INT32)) {
1978 ++NumFoldable;
1979 NewDefs.emplace_back(Lookup, SubRegIdx);
1980 continue;
1981 }
1982 }
1983
1984 const TargetRegisterClass *InputRC =
1985 Lookup->isReg() ? MRI->getRegClass(Lookup->getReg())
1986 : MRI->getRegClass(RegOp.getReg());
1987
1988 // TODO: Account for Lookup->getSubReg()
1989
1990 // If we can't find a matching super class, this is an SGPR->AGPR or
1991 // VGPR->AGPR subreg copy (or something constant-like we have to materialize
1992 // in the AGPR). We can't directly copy from SGPR to AGPR on gfx908, so we
1993 // want to rewrite to copy to an intermediate VGPR class.
1994 const TargetRegisterClass *MatchRC =
1995 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
1996 if (!MatchRC) {
1997 ++NumFoldable;
1998 NewDefs.emplace_back(&RegOp, SubRegIdx);
1999 continue;
2000 }
2001
2002 NewDefs.emplace_back(&RegOp, SubRegIdx);
2003 }
2004
2005 // Do not clone a reg_sequence and merely change the result register class.
2006 if (NumFoldable == 0)
2007 return false;
2008
2009 CopyMI->setDesc(TII->get(AMDGPU::REG_SEQUENCE));
2010 for (unsigned I = CopyMI->getNumOperands() - 1; I > 0; --I)
2011 CopyMI->removeOperand(I);
2012
2013 for (auto [Def, DestSubIdx] : NewDefs) {
2014 if (!Def->isReg()) {
2015 // TODO: Should we use single write for each repeated value like in
2016 // register case?
2017 Register Tmp = MRI->createVirtualRegister(&AMDGPU::AGPR_32RegClass);
2018 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2019 .add(*Def);
2020 B.addReg(Tmp);
2021 } else {
2022 TargetInstrInfo::RegSubRegPair Src = getRegSubRegPair(*Def);
2023 Def->setIsKill(false);
2024
2025 Register &VGPRCopy = VGPRCopies[Src];
2026 if (!VGPRCopy) {
2027 const TargetRegisterClass *VGPRUseSubRC =
2028 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2029
2030 // We cannot build a reg_sequence out of the same registers, they
2031 // must be copied. Better do it here before copyPhysReg() created
2032 // several reads to do the AGPR->VGPR->AGPR copy.
2033
2034 // Direct copy from SGPR to AGPR is not possible on gfx908. To avoid
2035 // creation of exploded copies SGPR->VGPR->AGPR in the copyPhysReg()
2036 // later, create a copy here and track if we already have such a copy.
2037 const TargetRegisterClass *SubRC =
2038 TRI->getSubRegisterClass(MRI->getRegClass(Src.Reg), Src.SubReg);
2039 if (!VGPRUseSubRC->hasSubClassEq(SubRC)) {
2040 // TODO: Try to reconstrain class
2041 VGPRCopy = MRI->createVirtualRegister(VGPRUseSubRC);
2042 BuildMI(MBB, CopyMI, DL, TII->get(AMDGPU::COPY), VGPRCopy).add(*Def);
2043 B.addReg(VGPRCopy);
2044 } else {
2045 // If it is already a VGPR, do not copy the register.
2046 B.add(*Def);
2047 }
2048 } else {
2049 B.addReg(VGPRCopy);
2050 }
2051 }
2052
2053 B.addImm(DestSubIdx);
2054 }
2055
2056 LLVM_DEBUG(dbgs() << "Folded " << *CopyMI);
2057 return true;
2058}
2059
2060bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2061 MachineInstr &MI, MachineOperand *&CurrentKnownM0Val) const {
2062 Register DstReg = MI.getOperand(0).getReg();
2063 // Specially track simple redefs of m0 to the same value in a block, so we
2064 // can erase the later ones.
2065 if (DstReg == AMDGPU::M0) {
2066 MachineOperand &NewM0Val = MI.getOperand(1);
2067 if (CurrentKnownM0Val && CurrentKnownM0Val->isIdenticalTo(NewM0Val)) {
2068 MI.eraseFromParent();
2069 return true;
2070 }
2071
2072 // We aren't tracking other physical registers
2073 CurrentKnownM0Val = (NewM0Val.isReg() && NewM0Val.getReg().isPhysical())
2074 ? nullptr
2075 : &NewM0Val;
2076 return false;
2077 }
2078
2079 MachineOperand *OpToFoldPtr;
2080 if (MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2081 // Folding when any src_modifiers are non-zero is unsupported
2082 if (TII->hasAnyModifiersSet(MI))
2083 return false;
2084 OpToFoldPtr = &MI.getOperand(2);
2085 } else
2086 OpToFoldPtr = &MI.getOperand(1);
2087 MachineOperand &OpToFold = *OpToFoldPtr;
2088 bool FoldingImm = OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
2089
2090 // FIXME: We could also be folding things like TargetIndexes.
2091 if (!FoldingImm && !OpToFold.isReg())
2092 return false;
2093
2094 // Fold virtual registers and constant physical registers.
2095 if (OpToFold.isReg() && OpToFold.getReg().isPhysical() &&
2096 !TRI->isConstantPhysReg(OpToFold.getReg()))
2097 return false;
2098
2099 // Prevent folding operands backwards in the function. For example,
2100 // the COPY opcode must not be replaced by 1 in this example:
2101 //
2102 // %3 = COPY %vgpr0; VGPR_32:%3
2103 // ...
2104 // %vgpr0 = V_MOV_B32_e32 1, implicit %exec
2105 if (!DstReg.isVirtual())
2106 return false;
2107
2108 const TargetRegisterClass *DstRC =
2109 MRI->getRegClass(MI.getOperand(0).getReg());
2110
2111 // True16: Fix malformed 16-bit sgpr COPY produced by peephole-opt
2112 // Can remove this code if proper 16-bit SGPRs are implemented
2113 // Example: Pre-peephole-opt
2114 // %29:sgpr_lo16 = COPY %16.lo16:sreg_32
2115 // %32:sreg_32 = COPY %29:sgpr_lo16
2116 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2117 // Post-peephole-opt and DCE
2118 // %32:sreg_32 = COPY %16.lo16:sreg_32
2119 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2120 // After this transform
2121 // %32:sreg_32 = COPY %16:sreg_32
2122 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %32:sreg_32
2123 // After the fold operands pass
2124 // %30:sreg_32 = S_PACK_LL_B32_B16 killed %31:sreg_32, killed %16:sreg_32
2125 if (MI.getOpcode() == AMDGPU::COPY && OpToFold.isReg() &&
2126 OpToFold.getSubReg()) {
2127 if (DstRC == &AMDGPU::SReg_32RegClass &&
2128 DstRC == MRI->getRegClass(OpToFold.getReg())) {
2129 assert(OpToFold.getSubReg() == AMDGPU::lo16);
2130 OpToFold.setSubReg(0);
2131 }
2132 }
2133
2134 // Fold copy to AGPR through reg_sequence
2135 // TODO: Handle with subregister extract
2136 if (OpToFold.isReg() && MI.isCopy() && !MI.getOperand(1).getSubReg()) {
2137 if (foldCopyToAGPRRegSequence(&MI))
2138 return true;
2139 }
2140
2141 FoldableDef Def(OpToFold, DstRC);
2142 bool Changed = foldInstOperand(MI, Def);
2143
2144 // If we managed to fold all uses of this copy then we might as well
2145 // delete it now.
2146 // The only reason we need to follow chains of copies here is that
2147 // tryFoldRegSequence looks forward through copies before folding a
2148 // REG_SEQUENCE into its eventual users.
2149 auto *InstToErase = &MI;
2150 while (MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2151 auto &SrcOp = InstToErase->getOperand(1);
2152 auto SrcReg = SrcOp.isReg() ? SrcOp.getReg() : Register();
2153 InstToErase->eraseFromParent();
2154 Changed = true;
2155 InstToErase = nullptr;
2156 if (!SrcReg || SrcReg.isPhysical())
2157 break;
2158 InstToErase = MRI->getVRegDef(SrcReg);
2159 if (!InstToErase || !TII->isFoldableCopy(*InstToErase))
2160 break;
2161 }
2162
2163 if (InstToErase && InstToErase->isRegSequence() &&
2164 MRI->use_nodbg_empty(InstToErase->getOperand(0).getReg())) {
2165 InstToErase->eraseFromParent();
2166 Changed = true;
2167 }
2168
2169 if (Changed)
2170 return true;
2171
2172 // Run this after foldInstOperand to avoid turning scalar additions into
2173 // vector additions when the result scalar result could just be folded into
2174 // the user(s).
2175 return OpToFold.isReg() &&
2176 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.getReg(), MI);
2177}
2178
2179// Clamp patterns are canonically selected to v_max_* instructions, so only
2180// handle them.
2181const MachineOperand *
2182SIFoldOperandsImpl::isClamp(const MachineInstr &MI) const {
2183 unsigned Op = MI.getOpcode();
2184 switch (Op) {
2185 case AMDGPU::V_MAX_F32_e64:
2186 case AMDGPU::V_MAX_F16_e64:
2187 case AMDGPU::V_MAX_F16_t16_e64:
2188 case AMDGPU::V_MAX_F16_fake16_e64:
2189 case AMDGPU::V_MAX_F64_e64:
2190 case AMDGPU::V_MAX_NUM_F64_e64:
2191 case AMDGPU::V_PK_MAX_F16:
2192 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2193 case AMDGPU::V_PK_MAX_NUM_BF16: {
2194 if (MI.mayRaiseFPException())
2195 return nullptr;
2196
2197 if (!TII->getNamedOperand(MI, AMDGPU::OpName::clamp)->getImm())
2198 return nullptr;
2199
2200 // Make sure sources are identical.
2201 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2202 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2203 if (!Src0->isReg() || !Src1->isReg() ||
2204 Src0->getReg() != Src1->getReg() ||
2205 Src0->getSubReg() != Src1->getSubReg() ||
2206 Src0->getSubReg() != AMDGPU::NoSubRegister)
2207 return nullptr;
2208
2209 // Can't fold up if we have modifiers.
2210 if (TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2211 return nullptr;
2212
2213 unsigned Src0Mods
2214 = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)->getImm();
2215 unsigned Src1Mods
2216 = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers)->getImm();
2217
2218 // Having a 0 op_sel_hi would require swizzling the output in the source
2219 // instruction, which we can't do.
2220 unsigned UnsetMods =
2221 (Op == AMDGPU::V_PK_MAX_F16 || Op == AMDGPU::V_PK_MAX_NUM_BF16)
2223 : 0u;
2224 if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
2225 return nullptr;
2226 return Src0;
2227 }
2228 default:
2229 return nullptr;
2230 }
2231}
2232
2233// FIXME: Clamp for v_mad_mixhi_f16 handled during isel.
2234bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &MI) {
2235 const MachineOperand *ClampSrc = isClamp(MI);
2236 if (!ClampSrc || !MRI->hasOneNonDBGUser(ClampSrc->getReg()))
2237 return false;
2238
2239 if (!ClampSrc->getReg().isVirtual())
2240 return false;
2241
2242 // Look through COPY. COPY only observed with True16.
2243 Register DefSrcReg = TRI->lookThruCopyLike(ClampSrc->getReg(), MRI);
2244 MachineInstr *Def =
2245 MRI->getVRegDef(DefSrcReg.isVirtual() ? DefSrcReg : ClampSrc->getReg());
2246
2247 // The type of clamp must be compatible.
2248 if (!SIInstrInfo::hasSameClamp(*Def, MI))
2249 return false;
2250
2251 if (Def->mayRaiseFPException())
2252 return false;
2253
2254 MachineOperand *DefClamp = TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2255 if (!DefClamp)
2256 return false;
2257
2258 LLVM_DEBUG(dbgs() << "Folding clamp " << *DefClamp << " into " << *Def);
2259
2260 // Clamp is applied after omod, so it is OK if omod is set.
2261 DefClamp->setImm(1);
2262
2263 Register DefReg = Def->getOperand(0).getReg();
2264 Register MIDstReg = MI.getOperand(0).getReg();
2265 if (TRI->isSGPRReg(*MRI, DefReg)) {
2266 // Pseudo scalar instructions have a SGPR for dst and clamp is a v_max*
2267 // instruction with a VGPR dst.
2268 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY),
2269 MIDstReg)
2270 .addReg(DefReg);
2271 } else {
2272 MRI->replaceRegWith(MIDstReg, DefReg);
2273 }
2274 MI.eraseFromParent();
2275
2276 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2277 // instruction, so we might as well convert it to the more flexible VOP3-only
2278 // mad/fma form.
2279 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2280 Def->eraseFromParent();
2281
2282 return true;
2283}
2284
2285static int getOModValue(unsigned Opc, int64_t Val) {
2286 switch (Opc) {
2287 case AMDGPU::V_MUL_F64_e64:
2288 case AMDGPU::V_MUL_F64_pseudo_e64: {
2289 switch (Val) {
2290 case 0x3fe0000000000000: // 0.5
2291 return SIOutMods::DIV2;
2292 case 0x4000000000000000: // 2.0
2293 return SIOutMods::MUL2;
2294 case 0x4010000000000000: // 4.0
2295 return SIOutMods::MUL4;
2296 default:
2297 return SIOutMods::NONE;
2298 }
2299 }
2300 case AMDGPU::V_MUL_F32_e64: {
2301 switch (static_cast<uint32_t>(Val)) {
2302 case 0x3f000000: // 0.5
2303 return SIOutMods::DIV2;
2304 case 0x40000000: // 2.0
2305 return SIOutMods::MUL2;
2306 case 0x40800000: // 4.0
2307 return SIOutMods::MUL4;
2308 default:
2309 return SIOutMods::NONE;
2310 }
2311 }
2312 case AMDGPU::V_MUL_F16_e64:
2313 case AMDGPU::V_MUL_F16_t16_e64:
2314 case AMDGPU::V_MUL_F16_fake16_e64: {
2315 switch (static_cast<uint16_t>(Val)) {
2316 case 0x3800: // 0.5
2317 return SIOutMods::DIV2;
2318 case 0x4000: // 2.0
2319 return SIOutMods::MUL2;
2320 case 0x4400: // 4.0
2321 return SIOutMods::MUL4;
2322 default:
2323 return SIOutMods::NONE;
2324 }
2325 }
2326 default:
2327 llvm_unreachable("invalid mul opcode");
2328 }
2329}
2330
2331// FIXME: Does this really not support denormals with f16?
2332// FIXME: Does this need to check IEEE mode bit? SNaNs are generally not
2333// handled, so will anything other than that break?
2334std::pair<const MachineOperand *, int>
2335SIFoldOperandsImpl::isOMod(const MachineInstr &MI) const {
2336 unsigned Op = MI.getOpcode();
2337 switch (Op) {
2338 case AMDGPU::V_MUL_F64_e64:
2339 case AMDGPU::V_MUL_F64_pseudo_e64:
2340 case AMDGPU::V_MUL_F32_e64:
2341 case AMDGPU::V_MUL_F16_t16_e64:
2342 case AMDGPU::V_MUL_F16_fake16_e64:
2343 case AMDGPU::V_MUL_F16_e64: {
2344 // If output denormals are enabled, omod is ignored.
2345 if ((Op == AMDGPU::V_MUL_F32_e64 &&
2347 ((Op == AMDGPU::V_MUL_F64_e64 || Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2348 Op == AMDGPU::V_MUL_F16_e64 || Op == AMDGPU::V_MUL_F16_t16_e64 ||
2349 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2352 MI.mayRaiseFPException())
2353 return std::pair(nullptr, SIOutMods::NONE);
2354
2355 const MachineOperand *RegOp = nullptr;
2356 const MachineOperand *ImmOp = nullptr;
2357 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2358 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2359 if (Src0->isImm()) {
2360 ImmOp = Src0;
2361 RegOp = Src1;
2362 } else if (Src1->isImm()) {
2363 ImmOp = Src1;
2364 RegOp = Src0;
2365 } else
2366 return std::pair(nullptr, SIOutMods::NONE);
2367
2368 int OMod = getOModValue(Op, ImmOp->getImm());
2369 if (OMod == SIOutMods::NONE ||
2370 TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
2371 TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) ||
2372 TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
2373 TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
2374 return std::pair(nullptr, SIOutMods::NONE);
2375
2376 return std::pair(RegOp, OMod);
2377 }
2378 case AMDGPU::V_ADD_F64_e64:
2379 case AMDGPU::V_ADD_F64_pseudo_e64:
2380 case AMDGPU::V_ADD_F32_e64:
2381 case AMDGPU::V_ADD_F16_e64:
2382 case AMDGPU::V_ADD_F16_t16_e64:
2383 case AMDGPU::V_ADD_F16_fake16_e64: {
2384 // If output denormals are enabled, omod is ignored.
2385 if ((Op == AMDGPU::V_ADD_F32_e64 &&
2387 ((Op == AMDGPU::V_ADD_F64_e64 || Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2388 Op == AMDGPU::V_ADD_F16_e64 || Op == AMDGPU::V_ADD_F16_t16_e64 ||
2389 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2391 return std::pair(nullptr, SIOutMods::NONE);
2392
2393 // Look through the DAGCombiner canonicalization fmul x, 2 -> fadd x, x
2394 const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
2395 const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
2396
2397 if (Src0->isReg() && Src1->isReg() && Src0->getReg() == Src1->getReg() &&
2398 Src0->getSubReg() == Src1->getSubReg() &&
2399 !TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) &&
2400 !TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) &&
2401 !TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) &&
2402 !TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
2403 return std::pair(Src0, SIOutMods::MUL2);
2404
2405 return std::pair(nullptr, SIOutMods::NONE);
2406 }
2407 default:
2408 return std::pair(nullptr, SIOutMods::NONE);
2409 }
2410}
2411
2412// FIXME: Does this need to check IEEE bit on function?
2413bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &MI) {
2414 const MachineOperand *RegOp;
2415 int OMod;
2416 std::tie(RegOp, OMod) = isOMod(MI);
2417 if (OMod == SIOutMods::NONE || !RegOp->isReg() ||
2418 RegOp->getSubReg() != AMDGPU::NoSubRegister ||
2419 !MRI->hasOneNonDBGUser(RegOp->getReg()))
2420 return false;
2421
2422 MachineInstr *Def = MRI->getVRegDef(RegOp->getReg());
2423 MachineOperand *DefOMod = TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2424 if (!DefOMod || DefOMod->getImm() != SIOutMods::NONE)
2425 return false;
2426
2427 if (Def->mayRaiseFPException())
2428 return false;
2429
2430 // Clamp is applied after omod. If the source already has clamp set, don't
2431 // fold it.
2432 if (TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2433 return false;
2434
2435 LLVM_DEBUG(dbgs() << "Folding omod " << MI << " into " << *Def);
2436
2437 DefOMod->setImm(OMod);
2438 MRI->replaceRegWith(MI.getOperand(0).getReg(), Def->getOperand(0).getReg());
2439 // Kill flags can be wrong if we replaced a def inside a loop with a def
2440 // outside the loop.
2441 MRI->clearKillFlags(Def->getOperand(0).getReg());
2442 MI.eraseFromParent();
2443
2444 // Use of output modifiers forces VOP3 encoding for a VOP2 mac/fmac
2445 // instruction, so we might as well convert it to the more flexible VOP3-only
2446 // mad/fma form.
2447 if (TII->convertToThreeAddress(*Def, nullptr, nullptr))
2448 Def->eraseFromParent();
2449
2450 return true;
2451}
2452
2453// Try to fold a reg_sequence with vgpr output and agpr inputs into an
2454// instruction which can take an agpr. So far that means a store.
2455bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &MI) {
2456 assert(MI.isRegSequence());
2457 auto Reg = MI.getOperand(0).getReg();
2458
2459 if (!ST->hasGFX90AInsts() || !TRI->isVGPR(*MRI, Reg) ||
2460 !MRI->hasOneNonDBGUse(Reg))
2461 return false;
2462
2464 if (!getRegSeqInit(Defs, Reg))
2465 return false;
2466
2467 for (auto &[Op, SubIdx] : Defs) {
2468 if (!Op->isReg())
2469 return false;
2470 if (TRI->isAGPR(*MRI, Op->getReg()))
2471 continue;
2472 // Maybe this is a COPY from AREG
2473 const MachineInstr *SubDef = MRI->getVRegDef(Op->getReg());
2474 if (!SubDef || !SubDef->isCopy() || SubDef->getOperand(1).getSubReg())
2475 return false;
2476 if (!TRI->isAGPR(*MRI, SubDef->getOperand(1).getReg()))
2477 return false;
2478 }
2479
2480 MachineOperand *Op = &*MRI->use_nodbg_begin(Reg);
2481 MachineInstr *UseMI = Op->getParent();
2482 while (UseMI->isCopy() && !Op->getSubReg()) {
2483 Reg = UseMI->getOperand(0).getReg();
2484 if (!TRI->isVGPR(*MRI, Reg) || !MRI->hasOneNonDBGUse(Reg))
2485 return false;
2486 Op = &*MRI->use_nodbg_begin(Reg);
2487 UseMI = Op->getParent();
2488 }
2489
2490 if (Op->getSubReg())
2491 return false;
2492
2493 unsigned OpIdx = Op - &UseMI->getOperand(0);
2494 const MCInstrDesc &InstDesc = UseMI->getDesc();
2495 const TargetRegisterClass *OpRC = TII->getRegClass(InstDesc, OpIdx);
2496 if (!OpRC || !TRI->isVectorSuperClass(OpRC))
2497 return false;
2498
2499 const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg));
2500 auto Dst = MRI->createVirtualRegister(NewDstRC);
2501 auto RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
2502 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2503
2504 for (auto &[Def, SubIdx] : Defs) {
2505 Def->setIsKill(false);
2506 if (TRI->isAGPR(*MRI, Def->getReg())) {
2507 RS.add(*Def);
2508 } else { // This is a copy
2509 MachineInstr *SubDef = MRI->getVRegDef(Def->getReg());
2510 SubDef->getOperand(1).setIsKill(false);
2511 RS.addReg(SubDef->getOperand(1).getReg(), {}, Def->getSubReg());
2512 }
2513 RS.addImm(SubIdx);
2514 }
2515
2516 Op->setReg(Dst);
2517 if (!TII->isOperandLegal(*UseMI, OpIdx, Op)) {
2518 Op->setReg(Reg);
2519 RS->eraseFromParent();
2520 return false;
2521 }
2522
2523 LLVM_DEBUG(dbgs() << "Folded " << *RS << " into " << *UseMI);
2524
2525 // Erase the REG_SEQUENCE eagerly, unless we followed a chain of COPY users,
2526 // in which case we can erase them all later in runOnMachineFunction.
2527 if (MRI->use_nodbg_empty(MI.getOperand(0).getReg()))
2528 MI.eraseFromParent();
2529 return true;
2530}
2531
2532/// Checks whether \p Copy is a AGPR -> VGPR copy. Returns `true` on success and
2533/// stores the AGPR register in \p OutReg and the subreg in \p OutSubReg
2534static bool isAGPRCopy(const SIRegisterInfo &TRI,
2535 const MachineRegisterInfo &MRI, const MachineInstr &Copy,
2536 Register &OutReg, unsigned &OutSubReg) {
2537 assert(Copy.isCopy());
2538
2539 const MachineOperand &CopySrc = Copy.getOperand(1);
2540 Register CopySrcReg = CopySrc.getReg();
2541 if (!CopySrcReg.isVirtual())
2542 return false;
2543
2544 // Common case: copy from AGPR directly, e.g.
2545 // %1:vgpr_32 = COPY %0:agpr_32
2546 if (TRI.isAGPR(MRI, CopySrcReg)) {
2547 OutReg = CopySrcReg;
2548 OutSubReg = CopySrc.getSubReg();
2549 return true;
2550 }
2551
2552 // Sometimes it can also involve two copies, e.g.
2553 // %1:vgpr_256 = COPY %0:agpr_256
2554 // %2:vgpr_32 = COPY %1:vgpr_256.sub0
2555 const MachineInstr *CopySrcDef = MRI.getVRegDef(CopySrcReg);
2556 if (!CopySrcDef || !CopySrcDef->isCopy())
2557 return false;
2558
2559 const MachineOperand &OtherCopySrc = CopySrcDef->getOperand(1);
2560 Register OtherCopySrcReg = OtherCopySrc.getReg();
2561 if (!OtherCopySrcReg.isVirtual() ||
2562 CopySrcDef->getOperand(0).getSubReg() != AMDGPU::NoSubRegister ||
2563 OtherCopySrc.getSubReg() != AMDGPU::NoSubRegister ||
2564 !TRI.isAGPR(MRI, OtherCopySrcReg))
2565 return false;
2566
2567 OutReg = OtherCopySrcReg;
2568 OutSubReg = CopySrc.getSubReg();
2569 return true;
2570}
2571
2572// Try to hoist an AGPR to VGPR copy across a PHI.
2573// This should allow folding of an AGPR into a consumer which may support it.
2574//
2575// Example 1: LCSSA PHI
2576// loop:
2577// %1:vreg = COPY %0:areg
2578// exit:
2579// %2:vreg = PHI %1:vreg, %loop
2580// =>
2581// loop:
2582// exit:
2583// %1:areg = PHI %0:areg, %loop
2584// %2:vreg = COPY %1:areg
2585//
2586// Example 2: PHI with multiple incoming values:
2587// entry:
2588// %1:vreg = GLOBAL_LOAD(..)
2589// loop:
2590// %2:vreg = PHI %1:vreg, %entry, %5:vreg, %loop
2591// %3:areg = COPY %2:vreg
2592// %4:areg = (instr using %3:areg)
2593// %5:vreg = COPY %4:areg
2594// =>
2595// entry:
2596// %1:vreg = GLOBAL_LOAD(..)
2597// %2:areg = COPY %1:vreg
2598// loop:
2599// %3:areg = PHI %2:areg, %entry, %X:areg,
2600// %4:areg = (instr using %3:areg)
2601bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &PHI) {
2602 assert(PHI.isPHI());
2603
2604 Register PhiOut = PHI.getOperand(0).getReg();
2605 if (!TRI->isVGPR(*MRI, PhiOut))
2606 return false;
2607
2608 // Iterate once over all incoming values of the PHI to check if this PHI is
2609 // eligible, and determine the exact AGPR RC we'll target.
2610 const TargetRegisterClass *ARC = nullptr;
2611 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2612 MachineOperand &MO = PHI.getOperand(K);
2613 MachineInstr *Copy = MRI->getVRegDef(MO.getReg());
2614 if (!Copy || !Copy->isCopy())
2615 continue;
2616
2617 Register AGPRSrc;
2618 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2619 if (!isAGPRCopy(*TRI, *MRI, *Copy, AGPRSrc, AGPRRegMask))
2620 continue;
2621
2622 const TargetRegisterClass *CopyInRC = MRI->getRegClass(AGPRSrc);
2623 if (const auto *SubRC = TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2624 CopyInRC = SubRC;
2625
2626 if (ARC && !ARC->hasSubClassEq(CopyInRC))
2627 return false;
2628 ARC = CopyInRC;
2629 }
2630
2631 if (!ARC)
2632 return false;
2633
2634 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2635
2636 // Rewrite the PHI's incoming values to ARC.
2637 LLVM_DEBUG(dbgs() << "Folding AGPR copies into: " << PHI);
2638 for (unsigned K = 1; K < PHI.getNumExplicitOperands(); K += 2) {
2639 MachineOperand &MO = PHI.getOperand(K);
2640 Register Reg = MO.getReg();
2641
2643 MachineBasicBlock *InsertMBB = nullptr;
2644
2645 // Look at the def of Reg, ignoring all copies.
2646 unsigned CopyOpc = AMDGPU::COPY;
2647 if (MachineInstr *Def = MRI->getVRegDef(Reg)) {
2648
2649 // Look at pre-existing COPY instructions from ARC: Steal the operand. If
2650 // the copy was single-use, it will be removed by DCE later.
2651 if (Def->isCopy()) {
2652 Register AGPRSrc;
2653 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2654 if (isAGPRCopy(*TRI, *MRI, *Def, AGPRSrc, AGPRSubReg)) {
2655 MO.setReg(AGPRSrc);
2656 MO.setSubReg(AGPRSubReg);
2657 continue;
2658 }
2659
2660 // If this is a multi-use SGPR -> VGPR copy, use V_ACCVGPR_WRITE on
2661 // GFX908 directly instead of a COPY. Otherwise, SIFoldOperand may try
2662 // to fold the sgpr -> vgpr -> agpr copy into a sgpr -> agpr copy which
2663 // is unlikely to be profitable.
2664 //
2665 // Note that V_ACCVGPR_WRITE is only used for AGPR_32.
2666 MachineOperand &CopyIn = Def->getOperand(1);
2667 if (IsAGPR32 && !ST->hasGFX90AInsts() && !MRI->hasOneNonDBGUse(Reg) &&
2668 TRI->isSGPRReg(*MRI, CopyIn.getReg()))
2669 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2670 }
2671
2672 InsertMBB = Def->getParent();
2673 InsertPt = InsertMBB->SkipPHIsLabelsAndDebug(++Def->getIterator());
2674 } else {
2675 InsertMBB = PHI.getOperand(MO.getOperandNo() + 1).getMBB();
2676 InsertPt = InsertMBB->getFirstTerminator();
2677 }
2678
2679 Register NewReg = MRI->createVirtualRegister(ARC);
2680 MachineInstr *MI = BuildMI(*InsertMBB, InsertPt, PHI.getDebugLoc(),
2681 TII->get(CopyOpc), NewReg)
2682 .addReg(Reg);
2683 MO.setReg(NewReg);
2684
2685 (void)MI;
2686 LLVM_DEBUG(dbgs() << " Created COPY: " << *MI);
2687 }
2688
2689 // Replace the PHI's result with a new register.
2690 Register NewReg = MRI->createVirtualRegister(ARC);
2691 PHI.getOperand(0).setReg(NewReg);
2692
2693 // COPY that new register back to the original PhiOut register. This COPY will
2694 // usually be folded out later.
2695 MachineBasicBlock *MBB = PHI.getParent();
2696 BuildMI(*MBB, MBB->getFirstNonPHI(), PHI.getDebugLoc(),
2697 TII->get(AMDGPU::COPY), PhiOut)
2698 .addReg(NewReg);
2699
2700 LLVM_DEBUG(dbgs() << " Done: Folded " << PHI);
2701 return true;
2702}
2703
2704// Attempt to convert VGPR load to an AGPR load.
2705bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &MI) {
2706 assert(MI.mayLoad());
2707 if (!ST->hasGFX90AInsts() || MI.getNumExplicitDefs() != 1)
2708 return false;
2709
2710 MachineOperand &Def = MI.getOperand(0);
2711 if (!Def.isDef())
2712 return false;
2713
2714 Register DefReg = Def.getReg();
2715
2716 if (DefReg.isPhysical() || !TRI->isVGPR(*MRI, DefReg))
2717 return false;
2718
2721 SmallVector<Register, 8> MoveRegs;
2722
2723 if (Users.empty())
2724 return false;
2725
2726 // Check that all uses a copy to an agpr or a reg_sequence producing an agpr.
2727 while (!Users.empty()) {
2728 const MachineInstr *I = Users.pop_back_val();
2729 if (!I->isCopy() && !I->isRegSequence())
2730 return false;
2731 Register DstReg = I->getOperand(0).getReg();
2732 // Physical registers may have more than one instruction definitions
2733 if (DstReg.isPhysical())
2734 return false;
2735 if (TRI->isAGPR(*MRI, DstReg))
2736 continue;
2737 MoveRegs.push_back(DstReg);
2738 for (const MachineInstr &U : MRI->use_nodbg_instructions(DstReg))
2739 Users.push_back(&U);
2740 }
2741
2742 const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
2743 MRI->setRegClass(DefReg, TRI->getEquivalentAGPRClass(RC));
2744 if (!TII->isOperandLegal(MI, 0, &Def)) {
2745 MRI->setRegClass(DefReg, RC);
2746 return false;
2747 }
2748
2749 while (!MoveRegs.empty()) {
2750 Register Reg = MoveRegs.pop_back_val();
2751 MRI->setRegClass(Reg, TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)));
2752 }
2753
2754 LLVM_DEBUG(dbgs() << "Folded " << MI);
2755
2756 return true;
2757}
2758
2759// tryFoldPhiAGPR will aggressively try to create AGPR PHIs.
2760// For GFX90A and later, this is pretty much always a good thing, but for GFX908
2761// there's cases where it can create a lot more AGPR-AGPR copies, which are
2762// expensive on this architecture due to the lack of V_ACCVGPR_MOV.
2763//
2764// This function looks at all AGPR PHIs in a basic block and collects their
2765// operands. Then, it checks for register that are used more than once across
2766// all PHIs and caches them in a VGPR. This prevents ExpandPostRAPseudo from
2767// having to create one VGPR temporary per use, which can get very messy if
2768// these PHIs come from a broken-up large PHI (e.g. 32 AGPR phis, one per vector
2769// element).
2770//
2771// Example
2772// a:
2773// %in:agpr_256 = COPY %foo:vgpr_256
2774// c:
2775// %x:agpr_32 = ..
2776// b:
2777// %0:areg = PHI %in.sub0:agpr_32, %a, %x, %c
2778// %1:areg = PHI %in.sub0:agpr_32, %a, %y, %c
2779// %2:areg = PHI %in.sub0:agpr_32, %a, %z, %c
2780// =>
2781// a:
2782// %in:agpr_256 = COPY %foo:vgpr_256
2783// %tmp:vgpr_32 = V_ACCVGPR_READ_B32_e64 %in.sub0:agpr_32
2784// %tmp_agpr:agpr_32 = COPY %tmp
2785// c:
2786// %x:agpr_32 = ..
2787// b:
2788// %0:areg = PHI %tmp_agpr, %a, %x, %c
2789// %1:areg = PHI %tmp_agpr, %a, %y, %c
2790// %2:areg = PHI %tmp_agpr, %a, %z, %c
2791bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &MBB) {
2792 // This is only really needed on GFX908 where AGPR-AGPR copies are
2793 // unreasonably difficult.
2794 if (ST->hasGFX90AInsts())
2795 return false;
2796
2797 // Look at all AGPR Phis and collect the register + subregister used.
2798 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
2799 RegToMO;
2800
2801 for (auto &MI : MBB) {
2802 if (!MI.isPHI())
2803 break;
2804
2805 if (!TRI->isAGPR(*MRI, MI.getOperand(0).getReg()))
2806 continue;
2807
2808 for (unsigned K = 1; K < MI.getNumOperands(); K += 2) {
2809 MachineOperand &PhiMO = MI.getOperand(K);
2810 if (!PhiMO.getSubReg())
2811 continue;
2812 RegToMO[{PhiMO.getReg(), PhiMO.getSubReg()}].push_back(&PhiMO);
2813 }
2814 }
2815
2816 // For all (Reg, SubReg) pair that are used more than once, cache the value in
2817 // a VGPR.
2818 bool Changed = false;
2819 for (const auto &[Entry, MOs] : RegToMO) {
2820 if (MOs.size() == 1)
2821 continue;
2822
2823 const auto [Reg, SubReg] = Entry;
2824 MachineInstr *Def = MRI->getVRegDef(Reg);
2825 MachineBasicBlock *DefMBB = Def->getParent();
2826
2827 // Create a copy in a VGPR using V_ACCVGPR_READ_B32_e64 so it's not folded
2828 // out.
2829 const TargetRegisterClass *ARC = getRegOpRC(*MRI, *TRI, *MOs.front());
2830 Register TempVGPR =
2831 MRI->createVirtualRegister(TRI->getEquivalentVGPRClass(ARC));
2832 MachineInstr *VGPRCopy =
2833 BuildMI(*DefMBB, ++Def->getIterator(), Def->getDebugLoc(),
2834 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
2835 .addReg(Reg, /* flags */ {}, SubReg);
2836
2837 // Copy back to an AGPR and use that instead of the AGPR subreg in all MOs.
2838 Register TempAGPR = MRI->createVirtualRegister(ARC);
2839 BuildMI(*DefMBB, ++VGPRCopy->getIterator(), Def->getDebugLoc(),
2840 TII->get(AMDGPU::COPY), TempAGPR)
2841 .addReg(TempVGPR);
2842
2843 LLVM_DEBUG(dbgs() << "Caching AGPR into VGPR: " << *VGPRCopy);
2844 for (MachineOperand *MO : MOs) {
2845 MO->setReg(TempAGPR);
2846 MO->setSubReg(AMDGPU::NoSubRegister);
2847 LLVM_DEBUG(dbgs() << " Changed PHI Operand: " << *MO << "\n");
2848 }
2849
2850 Changed = true;
2851 }
2852
2853 return Changed;
2854}
2855
2856bool SIFoldOperandsImpl::run(MachineFunction &MF, const MachineLoopInfo *MLI) {
2857 this->MF = &MF;
2858 MRI = &MF.getRegInfo();
2859 ST = &MF.getSubtarget<GCNSubtarget>();
2860 TII = ST->getInstrInfo();
2861 TRI = &TII->getRegisterInfo();
2862 MFI = MF.getInfo<SIMachineFunctionInfo>();
2863 this->MLI = MLI;
2864
2865 // omod is ignored by hardware if IEEE bit is enabled. omod also does not
2866 // correctly handle signed zeros.
2867 //
2868 // FIXME: Also need to check strictfp
2869 bool IsIEEEMode = MFI->getMode().IEEE;
2870
2871 bool Changed = false;
2872 for (MachineBasicBlock *MBB : depth_first(&MF)) {
2873 MachineOperand *CurrentKnownM0Val = nullptr;
2874 for (auto &MI : make_early_inc_range(*MBB)) {
2875 Changed |= tryFoldCndMask(MI);
2876
2877 // PeepholeOptimizer may have folded an inline immediate directly onto an
2878 // instruction operand without materializing it into a register first.
2879 // Such an instruction is never reached through a def->use edge in
2880 // foldInstOperand, so try to constant fold it here.
2881 if (tryConstantFoldOp(&MI)) {
2882 Changed = true;
2883 continue;
2884 }
2885
2886 if (tryFoldZeroHighBits(MI)) {
2887 Changed = true;
2888 continue;
2889 }
2890
2891 if (MI.isRegSequence() && tryFoldRegSequence(MI)) {
2892 Changed = true;
2893 continue;
2894 }
2895
2896 if (MI.isPHI() && tryFoldPhiAGPR(MI)) {
2897 Changed = true;
2898 continue;
2899 }
2900
2901 if (MI.mayLoad() && tryFoldLoad(MI)) {
2902 Changed = true;
2903 continue;
2904 }
2905
2906 if (TII->isFoldableCopy(MI)) {
2907 Changed |= tryFoldFoldableCopy(MI, CurrentKnownM0Val);
2908 continue;
2909 }
2910
2911 // Saw an unknown clobber of m0, so we no longer know what it is.
2912 if (CurrentKnownM0Val && MI.modifiesRegister(AMDGPU::M0, TRI))
2913 CurrentKnownM0Val = nullptr;
2914
2915 // TODO: Omod might be OK if there is NSZ only on the source
2916 // instruction, and not the omod multiply.
2917 if (IsIEEEMode || !MI.getFlag(MachineInstr::FmNsz) || !tryFoldOMod(MI))
2918 Changed |= tryFoldClamp(MI);
2919 }
2920
2921 Changed |= tryOptimizeAGPRPhis(*MBB);
2922 }
2923
2924 return Changed;
2925}
2926
2927PreservedAnalyses
2930 MFPropsModifier _(*this, MF);
2931
2932 const MachineLoopInfo *MLI = &MFAM.getResult<MachineLoopAnalysis>(MF);
2933 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
2934 if (!Changed) {
2935 return PreservedAnalyses::all();
2936 }
2938 PA.preserveSet<CFGAnalyses>();
2939 PA.preserve<MachineLoopAnalysis>();
2940 return PA;
2941}
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)
MachineInstr unsigned OpIdx
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:439
@ OPERAND_REG_IMM_V2FP16
Definition SIDefines.h:432
@ OPERAND_REG_INLINE_C_FP64
Definition SIDefines.h:448
@ OPERAND_REG_INLINE_C_V2BF16
Definition SIDefines.h:450
@ OPERAND_REG_IMM_V2INT64
Definition SIDefines.h:435
@ OPERAND_REG_IMM_V2INT16
Definition SIDefines.h:434
@ OPERAND_REG_IMM_V2BF16
Definition SIDefines.h:431
@ OPERAND_REG_INLINE_C_INT64
Definition SIDefines.h:444
@ OPERAND_REG_IMM_NOINLINE_V2FP16
Definition SIDefines.h:436
@ OPERAND_REG_INLINE_C_V2FP16
Definition SIDefines.h:451
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
Definition SIDefines.h:462
@ OPERAND_REG_INLINE_AC_FP32
Definition SIDefines.h:463
@ OPERAND_REG_INLINE_C_FP32
Definition SIDefines.h:447
@ OPERAND_REG_INLINE_C_INT32
Definition SIDefines.h:443
@ OPERAND_REG_INLINE_C_V2INT16
Definition SIDefines.h:449
@ OPERAND_REG_IMM_V2FP32
Definition SIDefines.h:438
@ OPERAND_REG_INLINE_AC_FP64
Definition SIDefines.h:464
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:234
constexpr bool isMAI(const T &...O)
Definition SIDefines.h:348
constexpr bool isSWMMAC(const T &...O)
Definition SIDefines.h:375
constexpr bool isVOP3P(const T &...O)
Definition SIDefines.h:237
constexpr bool isWMMA(const T &...O)
Definition SIDefines.h:363
constexpr bool isDOT(const T &...O)
Definition SIDefines.h:351
constexpr bool isPacked(const T &...O)
Definition SIDefines.h:333
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.