[llvm] [AMDGPU][CodeGen] Don't always create `S_SET_VGPR_MSB` after `S_SETREG_B32` (PR #210042)
Lucas Ramirez via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 05:19:07 PDT 2026
https://github.com/lucas-rami created https://github.com/llvm/llvm-project/pull/210042
On encountering a `S_SETREG_IMM32_B32(MODE)` with size>12, offset==0, and unmatching VGPR MSBS, we currently always insert a `S_NOP`/`S_SET_VGPR_MSB` pair regardless of whether an instruction down the block requires it. These instructions may therefore be useless.
This defers the decision to insert such instructions to the time it is really needed, if such a time happens. Furthermore, if the VGPR MSBs induced by the MODE register mode are appropriate for further instructions, we simply use them without inserting a new `S_SET_VGPR_MSB`.
>From 7a2ba20ff6568232df50513290a2b7bf9729b996 Mon Sep 17 00:00:00 2001
From: Lucas Ramirez <lucas.rami at proton.me>
Date: Thu, 16 Jul 2026 12:01:41 +0000
Subject: [PATCH] [AMDGPU][CodeGen] Don't always create `S_SET_VGPR_MSB` after
`S_SETREG_B32`
On encountering a `S_SETREG_IMM32_B32(MODE)` with size>12, offset==0,
and unmatching VGPR MSBS, we currently always insert a
`S_NOP`/`S_SET_VGPR_MSB` pair regardless of whether an instruction down
the block requires it. These instructions may therefore be useless.
This defers the decision to insert such instructions to the time it is
really needed, if such a time happens. Furthermore, if the VGPR MSBs
induced by the MODE register mode are appropriate for further
instructions, we simply use them without inserting a new
`S_SET_VGPR_MSB`.
---
.../Target/AMDGPU/AMDGPULowerVGPREncoding.cpp | 54 ++++++++++++-------
.../CodeGen/AMDGPU/vgpr-setreg-mode-swar.mir | 50 +++++++++++++----
2 files changed, 77 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULowerVGPREncoding.cpp b/llvm/lib/Target/AMDGPU/AMDGPULowerVGPREncoding.cpp
index 75c3dd3b1de09..167d3ce50c13d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULowerVGPREncoding.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULowerVGPREncoding.cpp
@@ -96,10 +96,22 @@ class AMDGPULowerVGPREncoding {
// Layout: [src0 msb, src1 msb, src2 msb, dst msb].
unsigned V = 0;
for (const auto &[I, Op] : enumerate(Ops))
- V |= Op.MSBits.value_or(0) << (I * 2);
+ V |= Op.MSBits.value_or(0) << (I * BitsPerField);
return V;
}
+ /// Creates a \ref ModeTy from \p Mode. Inverse of \ref ModeTy::encode, such
+ /// that: Mode == ModeTy::decode(Mode).encode().
+ static ModeTy decode(unsigned Mode) {
+ ModeTy DecodedMode;
+ const unsigned FieldMask = (1 << BitsPerField) - 1;
+ for (OpMode &Op : DecodedMode.Ops) {
+ Op.MSBits = Mode & FieldMask;
+ Mode >>= BitsPerField;
+ }
+ return DecodedMode;
+ }
+
void print(raw_ostream &OS) const {
static const char *FieldNames[] = {"src0", "src1", "src2", "dst"};
OS << '{';
@@ -472,14 +484,23 @@ bool AMDGPULowerVGPREncoding::needNopBeforeSetVGPRMSB(
}
/// Convert mode value from S_SET_VGPR_MSB format to MODE register format.
-/// S_SET_VGPR_MSB uses: (src0[0-1], src1[2-3], src2[4-5], dst[6-7])
-/// MODE register uses: (dst[0-1], src0[2-3], src1[4-5], src2[6-7])
+/// S_SET_VGPR_MSB uses: (src0[0-1], src1[2-3], src2[4-5], dst[6-7] )
+/// MODE register uses: (dst[0-1], src0[2-3], src1[4-5], src2[6-7])
/// This is a left rotation by 2 bits on an 8-bit value.
static int64_t convertModeToSetregFormat(int64_t Mode) {
assert(isUInt<8>(Mode) && "Mode expected to be 8-bit");
return llvm::rotl<uint8_t>(static_cast<uint8_t>(Mode), /*R=*/2);
}
+/// Convert mode value from MODE format to S_SET_VGPR_MSB register format.
+/// MODE register uses: (dst[0-1], src0[2-3], src1[4-5], src2[6-7])
+/// S_SET_VGPR_MSB uses: (src0[0-1], src1[2-3], src2[4-5], dst[6-7] )
+/// This is a right rotation by 2 bits on an 8-bit value.
+static int64_t convertModeToSetVGPRFormat(int64_t Mode) {
+ assert(isUInt<8>(Mode) && "Setreg mode expected to be 8-bit");
+ return llvm::rotr<uint8_t>(static_cast<uint8_t>(Mode), /*R=*/2);
+}
+
bool AMDGPULowerVGPREncoding::updateSetregModeImm(MachineInstr &MI,
int64_t ModeValue) {
assert(MI.getOpcode() == AMDGPU::S_SETREG_IMM32_B32);
@@ -545,27 +566,24 @@ bool AMDGPULowerVGPREncoding::handleSetregMode(MachineInstr &MI) {
MachineOperand *ImmOp = TII->getNamedOperand(MI, AMDGPU::OpName::imm);
assert(ImmOp && "ImmOp must be present");
int64_t ImmBits12To19 = (ImmOp->getImm() & VGPR_MSB_MASK) >> VGPRMSBShift;
- int64_t SetregModeValue = convertModeToSetregFormat(ModeValue);
+ int64_t SetRegMode = convertModeToSetVGPRFormat(ImmBits12To19);
LLVM_DEBUG(dbgs() << " Case 2: Size(" << Size << ") > VGPRMSBShift, "
<< "ImmBits12To19=0x" << Twine::utohexstr(ImmBits12To19)
- << " SetregModeValue=0x"
- << Twine::utohexstr(SetregModeValue) << '\n');
- if (ImmBits12To19 == SetregModeValue) {
+ << " Mode=0x" << Twine::utohexstr(SetRegMode) << '\n');
+ if (ModeValue == SetRegMode) {
LLVM_DEBUG(dbgs() << " -> bits[12:19] already correct\n");
return false;
}
- // imm32[12:19] doesn't match VGPR MSBs - insert s_set_vgpr_msb after
- // the original instruction to restore the correct value. Insert S_NOP
- // to avoid the GFX1250 hazard where S_SET_VGPR_MSB immediately after
- // S_SETREG_IMM32_B32(MODE) is silently dropped.
- MachineBasicBlock::iterator InsertPt = std::next(MI.getIterator());
- BuildMI(*MBB, InsertPt, MI.getDebugLoc(), TII->get(AMDGPU::S_NOP)).addImm(0);
- MostRecentModeSet = BuildMI(*MBB, InsertPt, MI.getDebugLoc(),
- TII->get(AMDGPU::S_SET_VGPR_MSB))
- .addImm(ModeValue | (ModeValue << ModeWidth));
- LLVM_DEBUG(dbgs() << " -> inserted S_SET_VGPR_MSB after setreg: "
- << *MostRecentModeSet);
+ // imm32[12:19] doesn't match VGPR MSBs - set the current mode to the MODE
+ // register mode.
+ CurrentMode = ModeTy::decode(SetRegMode);
+ LLVM_DEBUG({
+ dbgs() << " -> bits[12:19] incorrect, current mode changed to MODE "
+ "register mode: ";
+ CurrentMode.print(dbgs());
+ dbgs() << '\n';
+ });
return true;
}
diff --git a/llvm/test/CodeGen/AMDGPU/vgpr-setreg-mode-swar.mir b/llvm/test/CodeGen/AMDGPU/vgpr-setreg-mode-swar.mir
index b9c3cdb3db45f..62271d7a08b85 100644
--- a/llvm/test/CodeGen/AMDGPU/vgpr-setreg-mode-swar.mir
+++ b/llvm/test/CodeGen/AMDGPU/vgpr-setreg-mode-swar.mir
@@ -163,7 +163,7 @@ body: |
---
# Case 3: Size > 12 (size=16), imm32[12:19] doesn't match VGPR MSBs, offset is non-zero
# vgpr256/257: S_SET_VGPR_MSB mode = 65, MODE register mode = 5
-# imm32 = 0x23ABC = 146108 (bits 12:19 = 0x23 != 5), must insert s_set_vgpr_msb after
+# imm32 = 0x23ABC = 146108 (bits 12:19 = 0x23 != 5)
# ASM-LABEL: {{^}}setreg_size_gt_12_mismatch_offset_1:
# ASM: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 1, 16), 0x23abc ; msbs: dst=3 src0=0 src1=2 src2=0
@@ -178,8 +178,6 @@ body: |
; CHECK: S_SET_VGPR_MSB 65, implicit-def $mode
; CHECK-NEXT: $vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
; CHECK-NEXT: S_SETREG_IMM32_B32 146108, 30785, implicit-def $mode, implicit $mode
- ; CHECK-NEXT: S_NOP 0
- ; CHECK-NEXT: S_SET_VGPR_MSB 16705, implicit-def $mode
; CHECK-NEXT: S_ENDPGM 0
$vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
; size=16, offset=1, hwreg=MODE: simm16 = 0x7841 = 30785
@@ -368,6 +366,46 @@ body: |
S_ENDPGM 0
...
+---
+# Case 10: After s_setreg_imm32_b32 (Size > 12, non-matching)
+# V_FMA_F32_e64 matches MODE register mode, no new S_SET_VGPR_MSB needed.
+# Second V_MOV_B32_e32 does not match MODE register mode, a new S_SET_VGPR_MSB
+# is needed because we cannot piggyback on S_SETREG_IMM32_B32.
+#
+# V_MOV_B32_e32 (vgpr256/257): S_SET_VGPR_MSB mode = 65 = 0b01.01.00.01, MODE register mode = 5
+# Setreg has size=16 with imm32[12:19] = 23 !=5 (does not match MODE register mode).
+# V_FMA_F32_e64 (vgpr768/vgpr0/vgpr512/vgpr1): S_SET_VGPR_MSB mode = 197 = 0b11.00.10.00, MODE register mode = 23
+
+# ASM-LABEL: {{^}}setreg_size_gt_12_match_then_identical_vgpr:
+# ASM: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 1, 16), 0x23abc ; msbs: dst=3 src0=0 src1=2 src2=0
+
+# DIS-LABEL: <setreg_size_gt_12_match_then_identical_vgpr>:
+
+name: setreg_size_gt_12_match_then_identical_vgpr
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+
+ ; CHECK-LABEL: name: setreg_size_gt_12_match_then_identical_vgpr
+ ; CHECK: liveins: $vgpr0, $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: S_SET_VGPR_MSB 65, implicit-def $mode
+ ; CHECK-NEXT: $vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
+ ; CHECK-NEXT: S_SETREG_IMM32_B32 146108, 30785, implicit-def $mode, implicit $mode
+ ; CHECK-NEXT: $vgpr768 = V_FMA_F32_e64 0, $vgpr0, 0, $vgpr512, 0, $vgpr1, 0, 0, implicit $mode, implicit $exec
+ ; CHECK-NEXT: S_SET_VGPR_MSB 51265, implicit-def $mode
+ ; CHECK-NEXT: $vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0
+ $vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
+ ; size=16, offset=1, hwreg=MODE: simm16 = 0x7841 = 30785
+ ; imm32 = 0x23ABC = 146108 (bits 12:19 = 23 != 5, does not match!)
+ S_SETREG_IMM32_B32 146108, 30785, implicit-def $mode, implicit $mode
+ $vgpr768 = V_FMA_F32_e64 0, $vgpr0, 0, $vgpr512, 0, $vgpr1, 0, 0, implicit $mode, implicit $exec
+ $vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
+ S_ENDPGM 0
+...
+
---
# S_SET_VGPR_MSB format: (src0_msb[0-1], src1_msb[2-3], src2_msb[4-5], dst_msb[6-7])
# MODE register format: (dst_msb[0-1], src0_msb[2-3], src1_msb[4-5], src2_msb[6-7])
@@ -473,8 +511,6 @@ body: |
# ASM-NEXT: s_set_vgpr_msb 0x4149 ; msbs: dst=1 src0=1 src1=2 src2=0
# ASM-NEXT: v_add_nc_u32_e32 v0 /*v256*/, v1 /*v257*/, v0 /*v512*/
# ASM-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 1, 16), 0x5abc ; msbs: dst=1 src0=1 src1=0 src2=0
-# ASM-NEXT: s_nop 0
-# ASM-NEXT: s_set_vgpr_msb 0x4949 ; msbs: dst=1 src0=1 src1=2 src2=0
# DIS-LABEL: <setreg_size_gt_12_offset_1_match_then_mismatch>:
# DIS-NEXT: s_set_vgpr_msb 0x41
@@ -486,8 +522,6 @@ body: |
# DIS-NEXT: s_set_vgpr_msb 0x4149
# DIS-NEXT: v_add_nc_u32_e32 v0 /*v256*/, v1 /*v257*/, v0 /*v512*/
# DIS-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 1, 16), 0x5abc
-# DIS-NEXT: s_nop 0
-# DIS-NEXT: s_set_vgpr_msb 0x49
---
name: setreg_size_gt_12_offset_1_match_then_mismatch
@@ -504,8 +538,6 @@ body: |
; CHECK-NEXT: S_SET_VGPR_MSB 16713, implicit-def $mode
; CHECK-NEXT: $vgpr256 = V_ADD_U32_e32 $vgpr257, $vgpr512, implicit $exec
; CHECK-NEXT: S_SETREG_IMM32_B32 23228, 30785, implicit-def $mode, implicit $mode
- ; CHECK-NEXT: S_NOP 0
- ; CHECK-NEXT: S_SET_VGPR_MSB 18761, implicit-def $mode
; CHECK-NEXT: S_ENDPGM 0
$vgpr256 = V_MOV_B32_e32 $vgpr257, implicit $exec
; size=16, offset=1, hwreg=MODE: simm16 = 0x7841 = 30785
More information about the llvm-commits
mailing list