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