1//===-- SIShrinkInstructions.cpp - Shrink Instructions --------------------===//
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/// The pass tries to use the 32-bit encoding for instructions when possible.
8//===----------------------------------------------------------------------===//
9//
10
11#include "SIShrinkInstructions.h"
12#include "AMDGPU.h"
13#include "GCNSubtarget.h"
14#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
15#include "Utils/AMDGPUBaseInfo.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/CodeGen/MachineFunctionPass.h"
18#include "llvm/CodeGen/RegisterClassInfo.h"
19
20#define DEBUG_TYPE "si-shrink-instructions"
21
22STATISTIC(NumInstructionsShrunk,
23 "Number of 64-bit instruction reduced to 32-bit.");
24STATISTIC(NumLiteralConstantsFolded,
25 "Number of literal constants folded into 32-bit instructions.");
26
27using namespace llvm;
28
29namespace {
30
31enum ChangeKind { None, UpdateHint, UpdateInst };
32
33class SIShrinkInstructions {
34 MachineFunction *MF;
35 MachineRegisterInfo *MRI;
36 const GCNSubtarget *ST;
37 const SIInstrInfo *TII;
38 const SIRegisterInfo *TRI;
39 bool IsPostRA;
40
41 bool foldImmediates(MachineInstr &MI, bool TryToCommute = true) const;
42 bool shouldShrinkTrue16(MachineInstr &MI) const;
43 bool isKImmOperand(const MachineInstr &MI, const MachineOperand &Src) const;
44 bool isKUImmOperand(const MachineInstr &MI, const MachineOperand &Src) const;
45 bool isKImmOrKUImmOperand(const MachineOperand &Src, bool &IsUnsigned) const;
46 void copyExtraImplicitOps(MachineInstr &NewMI, MachineInstr &MI) const;
47 bool shrinkScalarCompare(MachineInstr &MI) const;
48 bool shrinkMIMG(MachineInstr &MI) const;
49 bool shrinkMadFma(MachineInstr &MI) const;
50 ChangeKind shrinkScalarLogicOp(MachineInstr &MI) const;
51 bool tryReplaceDeadSDST(MachineInstr &MI) const;
52 bool instAccessReg(MachineInstr::filtered_const_mop_range &&R, Register Reg,
53 unsigned SubReg) const;
54 bool instReadsReg(const MachineInstr *MI, unsigned Reg,
55 unsigned SubReg) const;
56 bool instModifiesReg(const MachineInstr *MI, unsigned Reg,
57 unsigned SubReg) const;
58 TargetInstrInfo::RegSubRegPair getSubRegForIndex(Register Reg, unsigned Sub,
59 unsigned I) const;
60 void dropInstructionKeepingImpDefs(MachineInstr &MI) const;
61 MachineInstr *matchSwap(MachineInstr &MovT) const;
62
63public:
64 SIShrinkInstructions() = default;
65 bool run(MachineFunction &MF);
66};
67
68class SIShrinkInstructionsLegacy : public MachineFunctionPass {
69
70public:
71 static char ID;
72
73 SIShrinkInstructionsLegacy() : MachineFunctionPass(ID) {}
74
75 bool runOnMachineFunction(MachineFunction &MF) override;
76
77 StringRef getPassName() const override { return "SI Shrink Instructions"; }
78
79 void getAnalysisUsage(AnalysisUsage &AU) const override {
80 AU.setPreservesCFG();
81 MachineFunctionPass::getAnalysisUsage(AU);
82 }
83};
84
85} // End anonymous namespace.
86
87INITIALIZE_PASS(SIShrinkInstructionsLegacy, DEBUG_TYPE,
88 "SI Shrink Instructions", false, false)
89
90char SIShrinkInstructionsLegacy::ID = 0;
91
92FunctionPass *llvm::createSIShrinkInstructionsLegacyPass() {
93 return new SIShrinkInstructionsLegacy();
94}
95
96/// This function checks \p MI for operands defined by a move immediate
97/// instruction and then folds the literal constant into the instruction if it
98/// can. This function assumes that \p MI is a VOP1, VOP2, or VOPC instructions.
99bool SIShrinkInstructions::foldImmediates(MachineInstr &MI,
100 bool TryToCommute) const {
101 assert(TII->isVOP1(MI) || TII->isVOP2(MI) || TII->isVOPC(MI));
102
103 int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode: MI.getOpcode(), Name: AMDGPU::OpName::src0);
104
105 // Try to fold Src0
106 MachineOperand &Src0 = MI.getOperand(i: Src0Idx);
107 if (Src0.isReg()) {
108 Register Reg = Src0.getReg();
109 if (Reg.isVirtual()) {
110 MachineInstr *Def = MRI->getUniqueVRegDef(Reg);
111 if (Def && Def->isMoveImmediate()) {
112 MachineOperand &MovSrc = Def->getOperand(i: 1);
113 bool ConstantFolded = false;
114
115 if (TII->isOperandLegal(MI, OpIdx: Src0Idx, MO: &MovSrc)) {
116 if (MovSrc.isImm()) {
117 Src0.ChangeToImmediate(ImmVal: MovSrc.getImm());
118 ConstantFolded = true;
119 } else if (MovSrc.isFI()) {
120 Src0.ChangeToFrameIndex(Idx: MovSrc.getIndex());
121 ConstantFolded = true;
122 } else if (MovSrc.isGlobal()) {
123 Src0.ChangeToGA(GV: MovSrc.getGlobal(), Offset: MovSrc.getOffset(),
124 TargetFlags: MovSrc.getTargetFlags());
125 ConstantFolded = true;
126 }
127 }
128
129 if (ConstantFolded) {
130 if (MRI->use_nodbg_empty(RegNo: Reg))
131 Def->eraseFromParent();
132 ++NumLiteralConstantsFolded;
133 return true;
134 }
135 }
136 }
137 }
138
139 // We have failed to fold src0, so commute the instruction and try again.
140 if (TryToCommute && MI.isCommutable()) {
141 if (TII->commuteInstruction(MI)) {
142 if (foldImmediates(MI, TryToCommute: false))
143 return true;
144
145 // Commute back.
146 TII->commuteInstruction(MI);
147 }
148 }
149
150 return false;
151}
152
153/// Do not shrink the instruction if its registers are not expressible in the
154/// shrunk encoding.
155bool SIShrinkInstructions::shouldShrinkTrue16(MachineInstr &MI) const {
156 for (unsigned I = 0, E = MI.getNumExplicitOperands(); I != E; ++I) {
157 const MachineOperand &MO = MI.getOperand(i: I);
158 if (MO.isReg()) {
159 Register Reg = MO.getReg();
160 assert(!Reg.isVirtual() && "Prior checks should ensure we only shrink "
161 "True16 Instructions post-RA");
162 if (AMDGPU::VGPR_32RegClass.contains(Reg) &&
163 !AMDGPU::VGPR_32_Lo128RegClass.contains(Reg))
164 return false;
165
166 if (AMDGPU::VGPR_16RegClass.contains(Reg) &&
167 !AMDGPU::VGPR_16_Lo128RegClass.contains(Reg))
168 return false;
169 }
170 }
171 return true;
172}
173
174bool SIShrinkInstructions::isKImmOperand(const MachineInstr &MI,
175 const MachineOperand &Src) const {
176 return isInt<16>(x: SignExtend64(X: Src.getImm(), B: 32)) &&
177 !TII->isInlineConstant(MI, OpIdx: MI.getOperandNo(I: &Src));
178}
179
180bool SIShrinkInstructions::isKUImmOperand(const MachineInstr &MI,
181 const MachineOperand &Src) const {
182 return isUInt<16>(x: Src.getImm()) &&
183 !TII->isInlineConstant(MI, OpIdx: MI.getOperandNo(I: &Src));
184}
185
186bool SIShrinkInstructions::isKImmOrKUImmOperand(const MachineOperand &Src,
187 bool &IsUnsigned) const {
188 if (isInt<16>(x: SignExtend64(X: Src.getImm(), B: 32))) {
189 IsUnsigned = false;
190 return !TII->isInlineConstant(MO: Src);
191 }
192
193 if (isUInt<16>(x: Src.getImm())) {
194 IsUnsigned = true;
195 return !TII->isInlineConstant(MO: Src);
196 }
197
198 return false;
199}
200
201/// \returns the opcode of an instruction a move immediate of the constant \p
202/// Src can be replaced with if the constant is replaced with \p ModifiedImm.
203/// i.e.
204///
205/// If the bitreverse of a constant is an inline immediate, reverse the
206/// immediate and return the bitreverse opcode.
207///
208/// If the bitwise negation of a constant is an inline immediate, reverse the
209/// immediate and return the bitwise not opcode.
210static unsigned canModifyToInlineImmOp32(const SIInstrInfo *TII,
211 const MachineOperand &Src,
212 int32_t &ModifiedImm, bool Scalar) {
213 if (TII->isInlineConstant(MO: Src))
214 return 0;
215 int32_t SrcImm = static_cast<int32_t>(Src.getImm());
216
217 if (!Scalar) {
218 // We could handle the scalar case with here, but we would need to check
219 // that SCC is not live as S_NOT_B32 clobbers it. It's probably not worth
220 // it, as the reasonable values are already covered by s_movk_i32.
221 ModifiedImm = ~SrcImm;
222 if (TII->isInlineConstant(Imm: APInt(32, ModifiedImm, true)))
223 return AMDGPU::V_NOT_B32_e32;
224 }
225
226 ModifiedImm = reverseBits<int32_t>(Val: SrcImm);
227 if (TII->isInlineConstant(Imm: APInt(32, ModifiedImm, true)))
228 return Scalar ? AMDGPU::S_BREV_B32 : AMDGPU::V_BFREV_B32_e32;
229
230 return 0;
231}
232
233/// Copy implicit register operands from specified instruction to this
234/// instruction that are not part of the instruction definition.
235void SIShrinkInstructions::copyExtraImplicitOps(MachineInstr &NewMI,
236 MachineInstr &MI) const {
237 MachineFunction &MF = *MI.getMF();
238 for (unsigned i = MI.getDesc().getNumOperands() +
239 MI.getDesc().implicit_uses().size() +
240 MI.getDesc().implicit_defs().size(),
241 e = MI.getNumOperands();
242 i != e; ++i) {
243 const MachineOperand &MO = MI.getOperand(i);
244 if ((MO.isReg() && MO.isImplicit()) || MO.isRegMask())
245 NewMI.addOperand(MF, Op: MO);
246 }
247}
248
249bool SIShrinkInstructions::shrinkScalarCompare(MachineInstr &MI) const {
250 if (!ST->hasSCmpK())
251 return false;
252
253 // cmpk instructions do scc = dst <cc op> imm16, so commute the instruction to
254 // get constants on the RHS.
255 bool Changed = false;
256 if (!MI.getOperand(i: 0).isReg()) {
257 if (TII->commuteInstruction(MI, NewMI: false, OpIdx1: 0, OpIdx2: 1))
258 Changed = true;
259 }
260
261 // cmpk requires src0 to be a register
262 const MachineOperand &Src0 = MI.getOperand(i: 0);
263 if (!Src0.isReg())
264 return Changed;
265
266 MachineOperand &Src1 = MI.getOperand(i: 1);
267 if (!Src1.isImm())
268 return Changed;
269
270 int SOPKOpc = AMDGPU::getSOPKOp(Opcode: MI.getOpcode());
271 if (SOPKOpc == -1)
272 return Changed;
273
274 // eq/ne is special because the imm16 can be treated as signed or unsigned,
275 // and initially selected to the unsigned versions.
276 if (SOPKOpc == AMDGPU::S_CMPK_EQ_U32 || SOPKOpc == AMDGPU::S_CMPK_LG_U32) {
277 bool HasUImm;
278 if (isKImmOrKUImmOperand(Src: Src1, IsUnsigned&: HasUImm)) {
279 if (!HasUImm) {
280 SOPKOpc = (SOPKOpc == AMDGPU::S_CMPK_EQ_U32) ?
281 AMDGPU::S_CMPK_EQ_I32 : AMDGPU::S_CMPK_LG_I32;
282 Src1.setImm(SignExtend32(X: Src1.getImm(), B: 32));
283 }
284
285 MI.setDesc(TII->get(Opcode: SOPKOpc));
286 Changed = true;
287 }
288
289 return Changed;
290 }
291
292 const MCInstrDesc &NewDesc = TII->get(Opcode: SOPKOpc);
293
294 if ((SIInstrInfo::sopkIsZext(Opcode: SOPKOpc) && isKUImmOperand(MI, Src: Src1)) ||
295 (!SIInstrInfo::sopkIsZext(Opcode: SOPKOpc) && isKImmOperand(MI, Src: Src1))) {
296 if (!SIInstrInfo::sopkIsZext(Opcode: SOPKOpc))
297 Src1.setImm(SignExtend64(X: Src1.getImm(), B: 32));
298 MI.setDesc(NewDesc);
299 Changed = true;
300 }
301 return Changed;
302}
303
304// Shrink NSA encoded instructions with contiguous VGPRs to non-NSA encoding.
305bool SIShrinkInstructions::shrinkMIMG(MachineInstr &MI) const {
306 const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opc: MI.getOpcode());
307 if (!Info)
308 return false;
309
310 uint8_t NewEncoding;
311 switch (Info->MIMGEncoding) {
312 case AMDGPU::MIMGEncGfx10NSA:
313 NewEncoding = AMDGPU::MIMGEncGfx10Default;
314 break;
315 case AMDGPU::MIMGEncGfx11NSA:
316 NewEncoding = AMDGPU::MIMGEncGfx11Default;
317 break;
318 default:
319 return false;
320 }
321
322 int VAddr0Idx =
323 AMDGPU::getNamedOperandIdx(Opcode: MI.getOpcode(), Name: AMDGPU::OpName::vaddr0);
324 unsigned NewAddrDwords = Info->VAddrDwords;
325 const TargetRegisterClass *RC;
326
327 if (Info->VAddrDwords == 2) {
328 RC = &AMDGPU::VReg_64RegClass;
329 } else if (Info->VAddrDwords == 3) {
330 RC = &AMDGPU::VReg_96RegClass;
331 } else if (Info->VAddrDwords == 4) {
332 RC = &AMDGPU::VReg_128RegClass;
333 } else if (Info->VAddrDwords == 5) {
334 RC = &AMDGPU::VReg_160RegClass;
335 } else if (Info->VAddrDwords == 6) {
336 RC = &AMDGPU::VReg_192RegClass;
337 } else if (Info->VAddrDwords == 7) {
338 RC = &AMDGPU::VReg_224RegClass;
339 } else if (Info->VAddrDwords == 8) {
340 RC = &AMDGPU::VReg_256RegClass;
341 } else if (Info->VAddrDwords == 9) {
342 RC = &AMDGPU::VReg_288RegClass;
343 } else if (Info->VAddrDwords == 10) {
344 RC = &AMDGPU::VReg_320RegClass;
345 } else if (Info->VAddrDwords == 11) {
346 RC = &AMDGPU::VReg_352RegClass;
347 } else if (Info->VAddrDwords == 12) {
348 RC = &AMDGPU::VReg_384RegClass;
349 } else {
350 RC = &AMDGPU::VReg_512RegClass;
351 NewAddrDwords = 16;
352 }
353
354 unsigned VgprBase = 0;
355 unsigned NextVgpr = 0;
356 bool IsUndef = true;
357 bool IsKill = NewAddrDwords == Info->VAddrDwords;
358 const unsigned NSAMaxSize = ST->getNSAMaxSize();
359 const bool IsPartialNSA = NewAddrDwords > NSAMaxSize;
360 const unsigned EndVAddr = IsPartialNSA ? NSAMaxSize : Info->VAddrOperands;
361 for (unsigned Idx = 0; Idx < EndVAddr; ++Idx) {
362 const MachineOperand &Op = MI.getOperand(i: VAddr0Idx + Idx);
363 unsigned Vgpr = TRI->getHWRegIndex(Reg: Op.getReg());
364 unsigned Dwords = TRI->getRegSizeInBits(Reg: Op.getReg(), MRI: *MRI) / 32;
365 assert(Dwords > 0 && "Un-implemented for less than 32 bit regs");
366
367 if (Idx == 0) {
368 VgprBase = Vgpr;
369 NextVgpr = Vgpr + Dwords;
370 } else if (Vgpr == NextVgpr) {
371 NextVgpr = Vgpr + Dwords;
372 } else {
373 return false;
374 }
375
376 if (!Op.isUndef())
377 IsUndef = false;
378 if (!Op.isKill())
379 IsKill = false;
380 }
381
382 if (VgprBase + NewAddrDwords > 256)
383 return false;
384
385 // Further check for implicit tied operands - this may be present if TFE is
386 // enabled
387 int TFEIdx = AMDGPU::getNamedOperandIdx(Opcode: MI.getOpcode(), Name: AMDGPU::OpName::tfe);
388 int LWEIdx = AMDGPU::getNamedOperandIdx(Opcode: MI.getOpcode(), Name: AMDGPU::OpName::lwe);
389 unsigned TFEVal = (TFEIdx == -1) ? 0 : MI.getOperand(i: TFEIdx).getImm();
390 unsigned LWEVal = (LWEIdx == -1) ? 0 : MI.getOperand(i: LWEIdx).getImm();
391 int ToUntie = -1;
392 if (TFEVal || LWEVal) {
393 // TFE/LWE is enabled so we need to deal with an implicit tied operand
394 for (unsigned i = LWEIdx + 1, e = MI.getNumOperands(); i != e; ++i) {
395 if (MI.getOperand(i).isReg() && MI.getOperand(i).isTied() &&
396 MI.getOperand(i).isImplicit()) {
397 // This is the tied operand
398 assert(
399 ToUntie == -1 &&
400 "found more than one tied implicit operand when expecting only 1");
401 ToUntie = i;
402 MI.untieRegOperand(OpIdx: ToUntie);
403 }
404 }
405 }
406
407 unsigned NewOpcode = AMDGPU::getMIMGOpcode(BaseOpcode: Info->BaseOpcode, MIMGEncoding: NewEncoding,
408 VDataDwords: Info->VDataDwords, VAddrDwords: NewAddrDwords);
409 MI.setDesc(TII->get(Opcode: NewOpcode));
410 MI.getOperand(i: VAddr0Idx).setReg(RC->getRegister(i: VgprBase));
411 MI.getOperand(i: VAddr0Idx).setIsUndef(IsUndef);
412 MI.getOperand(i: VAddr0Idx).setIsKill(IsKill);
413
414 for (unsigned i = 1; i < EndVAddr; ++i)
415 MI.removeOperand(OpNo: VAddr0Idx + 1);
416
417 if (ToUntie >= 0) {
418 MI.tieOperands(
419 DefIdx: AMDGPU::getNamedOperandIdx(Opcode: MI.getOpcode(), Name: AMDGPU::OpName::vdata),
420 UseIdx: ToUntie - (EndVAddr - 1));
421 }
422 return true;
423}
424
425// Shrink MAD to MADAK/MADMK and FMA to FMAAK/FMAMK.
426bool SIShrinkInstructions::shrinkMadFma(MachineInstr &MI) const {
427 // Pre-GFX10 VOP3 instructions like MAD/FMA cannot take a literal operand so
428 // there is no reason to try to shrink them.
429 if (!ST->hasVOP3Literal())
430 return false;
431
432 // There is no advantage to doing this pre-RA.
433 if (!IsPostRA)
434 return false;
435
436 if (TII->hasAnyModifiersSet(MI))
437 return false;
438
439 const unsigned Opcode = MI.getOpcode();
440 MachineOperand &Src0 = *TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::src0);
441 MachineOperand &Src1 = *TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::src1);
442 MachineOperand &Src2 = *TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::src2);
443 unsigned NewOpcode = AMDGPU::INSTRUCTION_LIST_END;
444
445 bool Swap;
446
447 // Detect "Dst = VSrc * VGPR + Imm" and convert to AK form.
448 if (Src2.isImm() && !TII->isInlineConstant(MO: Src2)) {
449 if (Src1.isReg() && TRI->isVGPR(MRI: *MRI, Reg: Src1.getReg()))
450 Swap = false;
451 else if (Src0.isReg() && TRI->isVGPR(MRI: *MRI, Reg: Src0.getReg()))
452 Swap = true;
453 else
454 return false;
455
456 switch (Opcode) {
457 default:
458 llvm_unreachable("Unexpected mad/fma opcode!");
459 case AMDGPU::V_MAD_F32_e64:
460 NewOpcode = AMDGPU::V_MADAK_F32;
461 break;
462 case AMDGPU::V_FMA_F32_e64:
463 NewOpcode = AMDGPU::V_FMAAK_F32;
464 break;
465 case AMDGPU::V_MAD_F16_e64:
466 NewOpcode = AMDGPU::V_MADAK_F16;
467 break;
468 case AMDGPU::V_FMA_F16_e64:
469 case AMDGPU::V_FMA_F16_gfx9_e64:
470 NewOpcode = AMDGPU::V_FMAAK_F16;
471 break;
472 case AMDGPU::V_FMA_F16_gfx9_t16_e64:
473 NewOpcode = AMDGPU::V_FMAAK_F16_t16;
474 break;
475 case AMDGPU::V_FMA_F16_gfx9_fake16_e64:
476 NewOpcode = AMDGPU::V_FMAAK_F16_fake16;
477 break;
478 case AMDGPU::V_FMA_F64_e64:
479 if (ST->hasFmaakFmamkF64Insts())
480 NewOpcode = AMDGPU::V_FMAAK_F64;
481 break;
482 }
483 }
484
485 // Detect "Dst = VSrc * Imm + VGPR" and convert to MK form.
486 if (Src2.isReg() && TRI->isVGPR(MRI: *MRI, Reg: Src2.getReg())) {
487 if (Src1.isImm() && !TII->isInlineConstant(MO: Src1))
488 Swap = false;
489 else if (Src0.isImm() && !TII->isInlineConstant(MO: Src0))
490 Swap = true;
491 else
492 return false;
493
494 switch (Opcode) {
495 default:
496 llvm_unreachable("Unexpected mad/fma opcode!");
497 case AMDGPU::V_MAD_F32_e64:
498 NewOpcode = AMDGPU::V_MADMK_F32;
499 break;
500 case AMDGPU::V_FMA_F32_e64:
501 NewOpcode = AMDGPU::V_FMAMK_F32;
502 break;
503 case AMDGPU::V_MAD_F16_e64:
504 NewOpcode = AMDGPU::V_MADMK_F16;
505 break;
506 case AMDGPU::V_FMA_F16_e64:
507 case AMDGPU::V_FMA_F16_gfx9_e64:
508 NewOpcode = AMDGPU::V_FMAMK_F16;
509 break;
510 case AMDGPU::V_FMA_F16_gfx9_t16_e64:
511 NewOpcode = AMDGPU::V_FMAMK_F16_t16;
512 break;
513 case AMDGPU::V_FMA_F16_gfx9_fake16_e64:
514 NewOpcode = AMDGPU::V_FMAMK_F16_fake16;
515 break;
516 case AMDGPU::V_FMA_F64_e64:
517 if (ST->hasFmaakFmamkF64Insts())
518 NewOpcode = AMDGPU::V_FMAMK_F64;
519 break;
520 }
521 }
522
523 if (NewOpcode == AMDGPU::INSTRUCTION_LIST_END)
524 return false;
525
526 if (AMDGPU::isTrue16Inst(Opc: NewOpcode) && !shouldShrinkTrue16(MI))
527 return false;
528
529 if (Swap) {
530 // Swap Src0 and Src1 by building a new instruction.
531 BuildMI(BB&: *MI.getParent(), I&: MI, MIMD: MI.getDebugLoc(), MCID: TII->get(Opcode: NewOpcode),
532 DestReg: MI.getOperand(i: 0).getReg())
533 .add(MO: Src1)
534 .add(MO: Src0)
535 .add(MO: Src2)
536 .setMIFlags(MI.getFlags());
537 MI.eraseFromParent();
538 } else {
539 TII->removeModOperands(MI);
540 MI.setDesc(TII->get(Opcode: NewOpcode));
541 }
542 return true;
543}
544
545/// Attempt to shrink AND/OR/XOR operations requiring non-inlineable literals.
546/// For AND or OR, try using S_BITSET{0,1} to clear or set bits.
547/// If the inverse of the immediate is legal, use ANDN2, ORN2 or
548/// XNOR (as a ^ b == ~(a ^ ~b)).
549/// \return ChangeKind::None if no changes were made.
550/// ChangeKind::UpdateHint if regalloc hints were updated.
551/// ChangeKind::UpdateInst if the instruction was modified.
552ChangeKind SIShrinkInstructions::shrinkScalarLogicOp(MachineInstr &MI) const {
553 unsigned Opc = MI.getOpcode();
554 const MachineOperand *Dest = &MI.getOperand(i: 0);
555 MachineOperand *Src0 = &MI.getOperand(i: 1);
556 MachineOperand *Src1 = &MI.getOperand(i: 2);
557 MachineOperand *SrcReg = Src0;
558 MachineOperand *SrcImm = Src1;
559
560 if (!SrcImm->isImm() ||
561 AMDGPU::isInlinableLiteral32(Literal: SrcImm->getImm(), HasInv2Pi: ST->hasInv2PiInlineImm()))
562 return ChangeKind::None;
563
564 uint32_t Imm = static_cast<uint32_t>(SrcImm->getImm());
565 uint32_t NewImm = 0;
566
567 if (Opc == AMDGPU::S_AND_B32) {
568 if (isPowerOf2_32(Value: ~Imm) &&
569 MI.findRegisterDefOperand(Reg: AMDGPU::SCC, /*TRI=*/nullptr)->isDead()) {
570 NewImm = llvm::countr_one(Value: Imm);
571 Opc = AMDGPU::S_BITSET0_B32;
572 } else if (AMDGPU::isInlinableLiteral32(Literal: ~Imm, HasInv2Pi: ST->hasInv2PiInlineImm())) {
573 NewImm = ~Imm;
574 Opc = AMDGPU::S_ANDN2_B32;
575 }
576 } else if (Opc == AMDGPU::S_OR_B32) {
577 if (isPowerOf2_32(Value: Imm) &&
578 MI.findRegisterDefOperand(Reg: AMDGPU::SCC, /*TRI=*/nullptr)->isDead()) {
579 NewImm = llvm::countr_zero(Val: Imm);
580 Opc = AMDGPU::S_BITSET1_B32;
581 } else if (AMDGPU::isInlinableLiteral32(Literal: ~Imm, HasInv2Pi: ST->hasInv2PiInlineImm())) {
582 NewImm = ~Imm;
583 Opc = AMDGPU::S_ORN2_B32;
584 }
585 } else if (Opc == AMDGPU::S_XOR_B32) {
586 if (AMDGPU::isInlinableLiteral32(Literal: ~Imm, HasInv2Pi: ST->hasInv2PiInlineImm())) {
587 NewImm = ~Imm;
588 Opc = AMDGPU::S_XNOR_B32;
589 }
590 } else {
591 llvm_unreachable("unexpected opcode");
592 }
593
594 if (NewImm != 0) {
595 if (Dest->getReg().isVirtual() && SrcReg->isReg()) {
596 MRI->setRegAllocationHint(VReg: Dest->getReg(), Type: 0, PrefReg: SrcReg->getReg());
597 MRI->setRegAllocationHint(VReg: SrcReg->getReg(), Type: 0, PrefReg: Dest->getReg());
598 return ChangeKind::UpdateHint;
599 }
600
601 if (SrcReg->isReg() && SrcReg->getReg() == Dest->getReg()) {
602 const bool IsUndef = SrcReg->isUndef();
603 const bool IsKill = SrcReg->isKill();
604 TII->mutateAndCleanupImplicit(MI, NewDesc: TII->get(Opcode: Opc));
605 if (Opc == AMDGPU::S_BITSET0_B32 ||
606 Opc == AMDGPU::S_BITSET1_B32) {
607 Src0->ChangeToImmediate(ImmVal: NewImm);
608 // Remove the immediate and add the tied input.
609 MI.getOperand(i: 2).ChangeToRegister(Reg: Dest->getReg(), /*IsDef*/ isDef: false,
610 /*isImp*/ false, isKill: IsKill,
611 /*isDead*/ false, isUndef: IsUndef);
612 MI.tieOperands(DefIdx: 0, UseIdx: 2);
613 } else {
614 SrcImm->setImm(NewImm);
615 }
616 return ChangeKind::UpdateInst;
617 }
618 }
619
620 return ChangeKind::None;
621}
622
623// This is the same as MachineInstr::readsRegister/modifiesRegister except
624// it takes subregs into account.
625bool SIShrinkInstructions::instAccessReg(
626 MachineInstr::filtered_const_mop_range &&R, Register Reg,
627 unsigned SubReg) const {
628 for (const MachineOperand &MO : R) {
629 if (Reg.isPhysical() && MO.getReg().isPhysical()) {
630 if (TRI->regsOverlap(RegA: Reg, RegB: MO.getReg()))
631 return true;
632 } else if (MO.getReg() == Reg && Reg.isVirtual()) {
633 LaneBitmask Overlap = TRI->getSubRegIndexLaneMask(SubIdx: SubReg) &
634 TRI->getSubRegIndexLaneMask(SubIdx: MO.getSubReg());
635 if (Overlap.any())
636 return true;
637 }
638 }
639 return false;
640}
641
642bool SIShrinkInstructions::instReadsReg(const MachineInstr *MI, unsigned Reg,
643 unsigned SubReg) const {
644 return instAccessReg(R: MI->all_uses(), Reg, SubReg);
645}
646
647bool SIShrinkInstructions::instModifiesReg(const MachineInstr *MI, unsigned Reg,
648 unsigned SubReg) const {
649 return instAccessReg(R: MI->all_defs(), Reg, SubReg);
650}
651
652TargetInstrInfo::RegSubRegPair
653SIShrinkInstructions::getSubRegForIndex(Register Reg, unsigned Sub,
654 unsigned I) const {
655 if (TRI->getRegSizeInBits(Reg, MRI: *MRI) != 32) {
656 if (Reg.isPhysical()) {
657 Reg = TRI->getSubReg(Reg, Idx: TRI->getSubRegFromChannel(Channel: I));
658 } else {
659 Sub = TRI->getSubRegFromChannel(Channel: I + TRI->getChannelFromSubReg(SubReg: Sub));
660 }
661 }
662 return TargetInstrInfo::RegSubRegPair(Reg, Sub);
663}
664
665void SIShrinkInstructions::dropInstructionKeepingImpDefs(
666 MachineInstr &MI) const {
667 for (unsigned i = MI.getDesc().getNumOperands() +
668 MI.getDesc().implicit_uses().size() +
669 MI.getDesc().implicit_defs().size(),
670 e = MI.getNumOperands();
671 i != e; ++i) {
672 const MachineOperand &Op = MI.getOperand(i);
673 if (!Op.isDef())
674 continue;
675 BuildMI(BB&: *MI.getParent(), I: MI.getIterator(), MIMD: MI.getDebugLoc(),
676 MCID: TII->get(Opcode: AMDGPU::IMPLICIT_DEF), DestReg: Op.getReg());
677 }
678
679 MI.eraseFromParent();
680}
681
682// Match:
683// mov t, x
684// mov x, y
685// mov y, t
686//
687// =>
688//
689// mov t, x (t is potentially dead and move eliminated)
690// v_swap_b32 x, y
691//
692// Returns next valid instruction pointer if was able to create v_swap_b32.
693//
694// This shall not be done too early not to prevent possible folding which may
695// remove matched moves, and this should preferably be done before RA to
696// release saved registers and also possibly after RA which can insert copies
697// too.
698//
699// This is really just a generic peephole that is not a canonical shrinking,
700// although requirements match the pass placement and it reduces code size too.
701MachineInstr *SIShrinkInstructions::matchSwap(MachineInstr &MovT) const {
702 assert(MovT.getOpcode() == AMDGPU::V_MOV_B32_e32 ||
703 MovT.getOpcode() == AMDGPU::V_MOV_B16_t16_e32 ||
704 MovT.getOpcode() == AMDGPU::COPY);
705
706 Register T = MovT.getOperand(i: 0).getReg();
707 unsigned Tsub = MovT.getOperand(i: 0).getSubReg();
708 MachineOperand &Xop = MovT.getOperand(i: 1);
709
710 if (!Xop.isReg())
711 return nullptr;
712 Register X = Xop.getReg();
713 unsigned Xsub = Xop.getSubReg();
714 Register Y;
715 unsigned Ysub;
716
717 unsigned Size = TII->getOpSize(MI: MovT, OpNo: 0);
718
719 // We can't match v_swap_b16 pre-RA, because VGPR_16_Lo128 registers
720 // are not allocatble.
721 if (Size == 2 && X.isVirtual())
722 return nullptr;
723
724 if (!TRI->isVGPR(MRI: *MRI, Reg: X))
725 return nullptr;
726
727 const unsigned SearchLimit = 16;
728 unsigned Count = 0;
729
730 MachineInstr *MovX = nullptr;
731 MachineInstr *InsertionPt = nullptr;
732 MachineInstr *MovY = nullptr;
733
734 for (auto Iter = std::next(x: MovT.getIterator()),
735 E = MovT.getParent()->instr_end();
736 Iter != E && Count < SearchLimit; ++Iter) {
737 if (Iter->isDebugInstr())
738 continue;
739 ++Count;
740
741 if (!MovX) {
742 // Search for mov x, y.
743 if ((Iter->getOpcode() == AMDGPU::V_MOV_B32_e32 ||
744 Iter->getOpcode() == AMDGPU::V_MOV_B16_t16_e32 ||
745 Iter->getOpcode() == AMDGPU::COPY) &&
746 Iter->getOperand(i: 0).getReg() == X &&
747 Iter->getOperand(i: 0).getSubReg() == Xsub &&
748 Iter->getOperand(i: 1).isReg()) {
749 MovX = &*Iter;
750 Y = MovX->getOperand(i: 1).getReg();
751 Ysub = MovX->getOperand(i: 1).getSubReg();
752 } else if (instModifiesReg(MI: &*Iter, Reg: X, SubReg: Xsub)) {
753 // Writes to x are not allowed until mov x, y has been found
754 return nullptr;
755 }
756 } else {
757 // mov x, y has been found.
758 // Search for mov y, t.
759 if ((Iter->getOpcode() == AMDGPU::V_MOV_B32_e32 ||
760 Iter->getOpcode() == AMDGPU::V_MOV_B16_t16_e32 ||
761 Iter->getOpcode() == AMDGPU::COPY) &&
762 Iter->getOperand(i: 0).getReg() == Y &&
763 Iter->getOperand(i: 0).getSubReg() == Ysub &&
764 Iter->getOperand(i: 1).isReg() && Iter->getOperand(i: 1).getReg() == T &&
765 Iter->getOperand(i: 1).getSubReg() == Tsub) {
766 MovY = &*Iter;
767 break;
768 }
769
770 // Effectively, mov x, y must be moved downward
771 // and mov y, t must be moved upward so that they can be fused into a
772 // swap. A write to y creates a barrier that prevents the two moves from
773 // being moved adjacent to each other.
774 if (instModifiesReg(MI: &*Iter, Reg: Y, SubReg: Ysub))
775 return nullptr;
776
777 // Reads or writes to x prevent mov x, y from being moved farther
778 // downward. Select this to be the insertion point.
779 if (!InsertionPt &&
780 (instReadsReg(MI: &*Iter, Reg: X, SubReg: Xsub) || instModifiesReg(MI: &*Iter, Reg: X, SubReg: Xsub))) {
781 InsertionPt = &*Iter;
782 }
783 // If the insertion point has been found, then mov y, t must be moved
784 // upward past all subsequent instructions. A read of y will block this
785 // movement.
786 if (InsertionPt) {
787 if (instReadsReg(MI: &*Iter, Reg: Y, SubReg: Ysub))
788 return nullptr;
789 }
790 }
791
792 if (instModifiesReg(MI: &*Iter, Reg: T, SubReg: Tsub))
793 return nullptr;
794 }
795 if (MovY) {
796 LLVM_DEBUG(dbgs() << "Matched v_swap:\n" << MovT << *MovX << *MovY);
797
798 MachineBasicBlock &MBB = *MovT.getParent();
799 SmallVector<MachineInstr *, 4> Swaps;
800
801 if (!InsertionPt)
802 InsertionPt = MovY;
803 if (Size == 2) {
804 auto *MIB = BuildMI(BB&: MBB, I: InsertionPt->getIterator(), MIMD: MovT.getDebugLoc(),
805 MCID: TII->get(Opcode: AMDGPU::V_SWAP_B16))
806 .addDef(RegNo: X)
807 .addDef(RegNo: Y)
808 .addReg(RegNo: Y)
809 .addReg(RegNo: X)
810 .getInstr();
811 Swaps.push_back(Elt: MIB);
812 } else {
813 assert(Size > 0 && Size % 4 == 0);
814 for (unsigned I = 0; I < Size / 4; ++I) {
815 TargetInstrInfo::RegSubRegPair X1, Y1;
816 X1 = getSubRegForIndex(Reg: X, Sub: Xsub, I);
817 Y1 = getSubRegForIndex(Reg: Y, Sub: Ysub, I);
818 auto *MIB = BuildMI(BB&: MBB, I: InsertionPt->getIterator(), MIMD: MovT.getDebugLoc(),
819 MCID: TII->get(Opcode: AMDGPU::V_SWAP_B32))
820 .addDef(RegNo: X1.Reg, Flags: {}, SubReg: X1.SubReg)
821 .addDef(RegNo: Y1.Reg, Flags: {}, SubReg: Y1.SubReg)
822 .addReg(RegNo: Y1.Reg, Flags: {}, SubReg: Y1.SubReg)
823 .addReg(RegNo: X1.Reg, Flags: {}, SubReg: X1.SubReg)
824 .getInstr();
825 Swaps.push_back(Elt: MIB);
826 }
827 }
828 // Drop implicit EXEC.
829 if (MovX->hasRegisterImplicitUseOperand(Reg: AMDGPU::EXEC)) {
830 for (MachineInstr *Swap : Swaps) {
831 Swap->removeOperand(OpNo: Swap->getNumExplicitOperands());
832 Swap->copyImplicitOps(MF&: *MBB.getParent(), MI: *MovX);
833 }
834 }
835 MovX->eraseFromParent();
836 dropInstructionKeepingImpDefs(MI&: *MovY);
837 MachineInstr *Next = &*std::next(x: MovT.getIterator());
838
839 if (T.isVirtual() && MRI->use_nodbg_empty(RegNo: T)) {
840 dropInstructionKeepingImpDefs(MI&: MovT);
841 } else {
842 Xop.setIsKill(false);
843 for (int I = MovT.getNumImplicitOperands() - 1; I >= 0; --I ) {
844 unsigned OpNo = MovT.getNumExplicitOperands() + I;
845 const MachineOperand &Op = MovT.getOperand(i: OpNo);
846 if (Op.isKill() && TRI->regsOverlap(RegA: X, RegB: Op.getReg()))
847 MovT.removeOperand(OpNo);
848 }
849 }
850
851 return Next;
852 }
853 return nullptr;
854}
855
856// If an instruction has dead sdst replace it with NULL register on gfx1030+
857bool SIShrinkInstructions::tryReplaceDeadSDST(MachineInstr &MI) const {
858 if (!ST->hasGFX10_3Insts())
859 return false;
860
861 MachineOperand *Op = TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::sdst);
862 if (!Op)
863 return false;
864 Register SDstReg = Op->getReg();
865 if (SDstReg.isPhysical() || !MRI->use_nodbg_empty(RegNo: SDstReg))
866 return false;
867
868 Op->setReg(ST->isWave32() ? AMDGPU::SGPR_NULL : AMDGPU::SGPR_NULL64);
869 return true;
870}
871
872bool SIShrinkInstructions::run(MachineFunction &MF) {
873
874 this->MF = &MF;
875 MRI = &MF.getRegInfo();
876 ST = &MF.getSubtarget<GCNSubtarget>();
877 TII = ST->getInstrInfo();
878 TRI = &TII->getRegisterInfo();
879 IsPostRA = MF.getProperties().hasNoVRegs();
880
881 unsigned VCCReg = ST->isWave32() ? AMDGPU::VCC_LO : AMDGPU::VCC;
882 bool Changed = false;
883
884 for (MachineBasicBlock &MBB : MF) {
885 MachineBasicBlock::iterator I, Next;
886 for (I = MBB.begin(); I != MBB.end(); I = Next) {
887 Next = std::next(x: I);
888 MachineInstr &MI = *I;
889
890 if (MI.getOpcode() == AMDGPU::V_MOV_B32_e32) {
891 // If this has a literal constant source that is the same as the
892 // reversed bits of an inline immediate, replace with a bitreverse of
893 // that constant. This saves 4 bytes in the common case of materializing
894 // sign bits.
895
896 // Test if we are after regalloc. We only want to do this after any
897 // optimizations happen because this will confuse them.
898 MachineOperand &Src = MI.getOperand(i: 1);
899 if (Src.isImm() && IsPostRA) {
900 int32_t ModImm;
901 unsigned ModOpcode =
902 canModifyToInlineImmOp32(TII, Src, ModifiedImm&: ModImm, /*Scalar=*/false);
903 if (ModOpcode != 0) {
904 MI.setDesc(TII->get(Opcode: ModOpcode));
905 Src.setImm(static_cast<int64_t>(ModImm));
906 Changed = true;
907 continue;
908 }
909 }
910 }
911
912 if (ST->hasSwap() && (MI.getOpcode() == AMDGPU::V_MOV_B32_e32 ||
913 MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e32 ||
914 MI.getOpcode() == AMDGPU::COPY)) {
915 if (auto *NextMI = matchSwap(MovT&: MI)) {
916 Next = NextMI->getIterator();
917 Changed = true;
918 continue;
919 }
920 }
921
922 // Shrink scalar logic operations.
923 if (MI.getOpcode() == AMDGPU::S_AND_B32 ||
924 MI.getOpcode() == AMDGPU::S_OR_B32 ||
925 MI.getOpcode() == AMDGPU::S_XOR_B32) {
926 ChangeKind CK = shrinkScalarLogicOp(MI);
927 if (CK == ChangeKind::UpdateHint)
928 continue;
929 Changed |= (CK == ChangeKind::UpdateInst);
930 }
931
932 // Try to use S_ADDK_I32 and S_MULK_I32.
933 if (MI.getOpcode() == AMDGPU::S_ADD_I32 ||
934 MI.getOpcode() == AMDGPU::S_MUL_I32 ||
935 (MI.getOpcode() == AMDGPU::S_OR_B32 &&
936 MI.getFlag(Flag: MachineInstr::MIFlag::Disjoint))) {
937 const MachineOperand *Dest = &MI.getOperand(i: 0);
938 MachineOperand *Src0 = &MI.getOperand(i: 1);
939 MachineOperand *Src1 = &MI.getOperand(i: 2);
940
941 if (!Src0->isReg() && Src1->isReg()) {
942 if (TII->commuteInstruction(MI, NewMI: false, OpIdx1: 1, OpIdx2: 2)) {
943 std::swap(a&: Src0, b&: Src1);
944 Changed = true;
945 }
946 }
947
948 // FIXME: This could work better if hints worked with subregisters. If
949 // we have a vector add of a constant, we usually don't get the correct
950 // allocation due to the subregister usage.
951 if (Dest->getReg().isVirtual() && Src0->isReg()) {
952 MRI->setRegAllocationHint(VReg: Dest->getReg(), Type: 0, PrefReg: Src0->getReg());
953 MRI->setRegAllocationHint(VReg: Src0->getReg(), Type: 0, PrefReg: Dest->getReg());
954 continue;
955 }
956 if (Src0->isReg() && Src0->getReg() == Dest->getReg()) {
957 if (Src1->isImm() && isKImmOperand(MI, Src: *Src1)) {
958 unsigned Opc = (MI.getOpcode() == AMDGPU::S_MUL_I32)
959 ? AMDGPU::S_MULK_I32
960 : AMDGPU::S_ADDK_I32;
961 Src1->setImm(SignExtend64(X: Src1->getImm(), B: 32));
962 MI.setDesc(TII->get(Opcode: Opc));
963 MI.tieOperands(DefIdx: 0, UseIdx: 1);
964 Changed = true;
965 }
966 }
967 }
968
969 // Try to use s_cmpk_*
970 if (MI.isCompare() && TII->isSOPC(MI)) {
971 Changed |= shrinkScalarCompare(MI);
972 continue;
973 }
974
975 // Try to use S_MOVK_I32, which will save 4 bytes for small immediates.
976 if (MI.getOpcode() == AMDGPU::S_MOV_B32) {
977 const MachineOperand &Dst = MI.getOperand(i: 0);
978 MachineOperand &Src = MI.getOperand(i: 1);
979
980 if (Src.isImm() && Dst.getReg().isPhysical()) {
981 unsigned ModOpc;
982 int32_t ModImm;
983 if (isKImmOperand(MI, Src)) {
984 MI.setDesc(TII->get(Opcode: AMDGPU::S_MOVK_I32));
985 Src.setImm(SignExtend64(X: Src.getImm(), B: 32));
986 Changed = true;
987 } else if ((ModOpc = canModifyToInlineImmOp32(TII, Src, ModifiedImm&: ModImm,
988 /*Scalar=*/true))) {
989 MI.setDesc(TII->get(Opcode: ModOpc));
990 Src.setImm(static_cast<int64_t>(ModImm));
991 Changed = true;
992 }
993 }
994
995 continue;
996 }
997
998 if (IsPostRA && TII->isMIMG(Opcode: MI.getOpcode()) &&
999 ST->getGeneration() >= AMDGPUSubtarget::GFX10) {
1000 Changed |= shrinkMIMG(MI);
1001 continue;
1002 }
1003
1004 if (!TII->isVOP3(MI))
1005 continue;
1006
1007 if (MI.getOpcode() == AMDGPU::V_MAD_F32_e64 ||
1008 MI.getOpcode() == AMDGPU::V_FMA_F32_e64 ||
1009 MI.getOpcode() == AMDGPU::V_MAD_F16_e64 ||
1010 MI.getOpcode() == AMDGPU::V_FMA_F16_e64 ||
1011 MI.getOpcode() == AMDGPU::V_FMA_F16_gfx9_e64 ||
1012 MI.getOpcode() == AMDGPU::V_FMA_F16_gfx9_t16_e64 ||
1013 MI.getOpcode() == AMDGPU::V_FMA_F16_gfx9_fake16_e64 ||
1014 (MI.getOpcode() == AMDGPU::V_FMA_F64_e64 &&
1015 ST->hasFmaakFmamkF64Insts())) {
1016 Changed |= shrinkMadFma(MI);
1017 continue;
1018 }
1019
1020 // If there is no chance we will shrink it and use VCC as sdst to get
1021 // a 32 bit form try to replace dead sdst with NULL.
1022 if (TII->isVOP3(Opcode: MI.getOpcode())) {
1023 Changed |= tryReplaceDeadSDST(MI);
1024 if (!TII->hasVALU32BitEncoding(Opcode: MI.getOpcode())) {
1025 continue;
1026 }
1027 }
1028
1029 if (!TII->canShrink(MI, MRI: *MRI)) {
1030 // Try commuting the instruction and see if that enables us to shrink
1031 // it.
1032 if (!MI.isCommutable() || !TII->commuteInstruction(MI) ||
1033 !TII->canShrink(MI, MRI: *MRI)) {
1034 Changed |= tryReplaceDeadSDST(MI);
1035 continue;
1036 }
1037
1038 // Operands were commuted.
1039 Changed = true;
1040 }
1041
1042 int Op32 = AMDGPU::getVOPe32(Opcode: MI.getOpcode());
1043
1044 if (Op32 == AMDGPU::V_CNDMASK_B32_e32) {
1045 // We shrink V_CNDMASK_B32_e64 using regalloc hints like we do for VOPC
1046 // instructions.
1047 const MachineOperand *Src2 =
1048 TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::src2);
1049 if (!Src2->isReg())
1050 continue;
1051 Register SReg = Src2->getReg();
1052 if (SReg.isVirtual()) {
1053 MRI->setRegAllocationHint(VReg: SReg, Type: 0, PrefReg: VCCReg);
1054 continue;
1055 }
1056 if (SReg != VCCReg)
1057 continue;
1058 }
1059
1060 // Check for the bool flag output for instructions like V_ADD_I32_e64.
1061 // For VOPC e64 this is also the dst operand. VOPCX (nosdst) variants
1062 // have no sdst, so they fall through to be shrunk directly.
1063 const MachineOperand *SDst =
1064 TII->getNamedOperand(MI, OperandName: AMDGPU::OpName::sdst);
1065
1066 if (SDst) {
1067 bool Next = false;
1068
1069 if (SDst->getReg() != VCCReg) {
1070 // VOPC instructions can only write to the VCC register. We can't
1071 // force them to use VCC here, because this is only one register and
1072 // cannot deal with sequences which would require multiple copies of
1073 // VCC, e.g. S_AND_B64 (vcc = V_CMP_...), (vcc = V_CMP_...)
1074 //
1075 // So, instead of forcing the instruction to write to VCC, we
1076 // provide a hint to the register allocator to use VCC and then we
1077 // will run this pass again after RA and shrink it if it outputs to
1078 // VCC.
1079 if (SDst->getReg().isVirtual())
1080 MRI->setRegAllocationHint(VReg: SDst->getReg(), Type: 0, PrefReg: VCCReg);
1081 Next = true;
1082 }
1083
1084 // All of the instructions with carry outs also have an SGPR input in
1085 // src2.
1086 const MachineOperand *Src2 = TII->getNamedOperand(MI,
1087 OperandName: AMDGPU::OpName::src2);
1088 if (Src2 && Src2->getReg() != VCCReg) {
1089 if (Src2->getReg().isVirtual())
1090 MRI->setRegAllocationHint(VReg: Src2->getReg(), Type: 0, PrefReg: VCCReg);
1091 Next = true;
1092 }
1093
1094 if (Next)
1095 continue;
1096 }
1097
1098 // Pre-GFX10, shrinking VOP3 instructions pre-RA gave us the chance to
1099 // fold an immediate into the shrunk instruction as a literal operand. In
1100 // GFX10 VOP3 instructions can take a literal operand anyway, so there is
1101 // no advantage to doing this.
1102 // However, if 64-bit literals are allowed we still need to shrink it
1103 // for such literal to be able to fold.
1104 if (ST->hasVOP3Literal() &&
1105 (!ST->has64BitLiterals() || AMDGPU::isTrue16Inst(Opc: MI.getOpcode())) &&
1106 !IsPostRA)
1107 continue;
1108
1109 if (ST->hasTrue16BitInsts() && AMDGPU::isTrue16Inst(Opc: MI.getOpcode()) &&
1110 !shouldShrinkTrue16(MI))
1111 continue;
1112
1113 // We can shrink this instruction
1114 LLVM_DEBUG(dbgs() << "Shrinking " << MI);
1115
1116 MachineInstr *Inst32 = TII->buildShrunkInst(MI, NewOpcode: Op32);
1117 ++NumInstructionsShrunk;
1118
1119 // Copy extra operands not present in the instruction definition.
1120 copyExtraImplicitOps(NewMI&: *Inst32, MI);
1121
1122 // Copy deadness from the old explicit vcc def to the new implicit def.
1123 if (SDst && SDst->isDead())
1124 Inst32->findRegisterDefOperand(Reg: VCCReg, /*TRI=*/nullptr)->setIsDead();
1125
1126 MI.eraseFromParent();
1127 foldImmediates(MI&: *Inst32);
1128
1129 LLVM_DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');
1130 Changed = true;
1131 }
1132 }
1133 return Changed;
1134}
1135
1136bool SIShrinkInstructionsLegacy::runOnMachineFunction(MachineFunction &MF) {
1137 if (skipFunction(F: MF.getFunction()))
1138 return false;
1139
1140 return SIShrinkInstructions().run(MF);
1141}
1142
1143PreservedAnalyses
1144SIShrinkInstructionsPass::run(MachineFunction &MF,
1145 MachineFunctionAnalysisManager &) {
1146 if (MF.getFunction().hasOptNone() || !SIShrinkInstructions().run(MF))
1147 return PreservedAnalyses::all();
1148
1149 auto PA = getMachineFunctionPassPreservedAnalyses();
1150 PA.preserveSet<CFGAnalyses>();
1151 return PA;
1152}
1153