[llvm] [AMDGPU] merge 16bit mov pairs in post-RA peephole (PR #208625)
Jay Foad via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 04:11:22 PDT 2026
================
@@ -763,6 +766,229 @@ MachineInstrBuilder SIPreEmitPeephole::createUnpackedMI(MachineInstr &I,
return NewMI;
}
+// Helper: extract the src operand and whether it is from the hi16 half.
+// Post-RA, both V_MOV_B16_t16_e32 and V_MOV_B16_t16_e64 use VGPR_16 physical
+// registers whose encoding already encodes hi/lo (IS_HI16 bit).
+// Returns false if the source is not a physical VGPR_16 or immediate zero.
+//
+// Operand layouts (post-RA, physical registers):
+// V_MOV_B16_t16_e32: dst(0), src0(1)
+// V_MOV_B16_t16_e64: dst(0), src0_mods(1), src0(2), op_sel(3)
+static bool getMovB16Info(const MachineInstr &MI, const SIRegisterInfo *TRI,
+ MCRegister &SrcReg16, MCRegister &SrcReg32,
+ bool &SrcIsHi, bool &SrcIsImm, int64_t &ImmVal) {
+ SrcIsImm = false;
+ SrcIsHi = false;
+ SrcReg16 = MCRegister();
+ SrcReg32 = MCRegister();
+
+ unsigned Opc = MI.getOpcode();
+ const MachineOperand *SrcOp = nullptr;
+
+ if (Opc == AMDGPU::V_MOV_B16_t16_e64)
+ SrcOp = &MI.getOperand(2);
+ else if (Opc == AMDGPU::V_MOV_B16_t16_e32)
+ SrcOp = &MI.getOperand(1);
+ else
+ return false;
+
+ if (SrcOp->isImm()) {
+ SrcIsImm = true;
+ ImmVal = SrcOp->getImm();
+ return true;
+ }
+
+ if (!SrcOp->isReg() || !SrcOp->getReg().isPhysical())
+ return false;
+
+ MCRegister SrcReg = SrcOp->getReg().asMCReg();
+
+ // We require the source to be a 16-bit VGPR so we can determine hi/lo.
+ if (!AMDGPU::VGPR_16RegClass.contains(SrcReg))
+ return false;
+
+ SrcIsHi = AMDGPU::isHi16Reg(SrcReg, *TRI);
+ SrcReg16 = SrcReg;
+ SrcReg32 = TRI->get32BitRegister(SrcReg);
+ return SrcReg32.isValid();
+}
+
+// clang-format off
+// Try to merge a pair of v_mov_b16 instructions targeting the lo16 and hi16
+// halves of the same VGPR into a single 32-bit instruction.
+//
+// Caller guarantee the pair to be two v_mov_b16 and targets the same dst32
+//
+// Patterns:
+// v_mov_b16 v0.h, 0 v_mov_b16 v0.l, v2.l => v_and_b32 v0,0xffff,v2
+// v_mov_b16 v0.h, 0 v_mov_b16 v0.l, v2.h => v_lshrrev_b32 v0,16,v2
+// v_mov_b16 v0.l, 0 v_mov_b16 v0.h, v2.l => v_lshlrev_b32 v0,16,v2
+// v_mov_b16 v0.l, 0 v_mov_b16 v0.h, v2.h => v_and_b32 v0,0xffff0000,v2
+// v_mov_b16 v0.l, v2.x v_mov_b16 v0.h, v3.y => v_pack_b32_f16 v0,v2.x,v3.y
+// clang-format on
+bool SIPreEmitPeephole::mergeSingleMovB16Pair(MachineInstr &Lo,
+ MachineInstr &Hi,
+ bool IsHiFirst) const {
+ // Lo and Hi share the same Dst32
+ MCRegister LoDst = Lo.getOperand(0).getReg().asMCReg();
+ MCRegister Dst32 = TRI->get32BitRegister(LoDst);
+
+ // Extract source info for Lo and Hi.
+ MCRegister LoSrc16, LoSrc32, HiSrc16, HiSrc32;
+ bool LoSrcIsHi, HiSrcIsHi, LoSrcIsImm, HiSrcIsImm;
+ int64_t LoImm = 0, HiImm = 0;
+
+ if (!getMovB16Info(Lo, TRI, LoSrc16, LoSrc32, LoSrcIsHi, LoSrcIsImm, LoImm))
+ return false;
+ if (!getMovB16Info(Hi, TRI, HiSrc16, HiSrc32, HiSrcIsHi, HiSrcIsImm, HiImm))
+ return false;
+
+ MachineInstr &FirstMI = IsHiFirst ? Hi : Lo;
+ MachineInstr &SecondMI = IsHiFirst ? Lo : Hi;
+ bool IsSecondImm = IsHiFirst ? LoSrcIsImm : HiSrcIsImm;
+
+ MachineBasicBlock &MBB = *FirstMI.getParent();
+ const DebugLoc &DL = FirstMI.getDebugLoc();
+
+ // Check that between Lo and Hi, there are no instructions that:
+ // - modify Dst32 (except through Lo/Hi themselves)
----------------
jayfoad wrote:
```suggestion
// - modify Dst32
```
You've already made it clear that we're not talking about Lo and Hi themselves
https://github.com/llvm/llvm-project/pull/208625
More information about the llvm-commits
mailing list