[llvm] [CodeGen] Treat Reg uses which are partially defined within bundle as internal read (PR #201004)
Vikram Hegde via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 23:05:17 PDT 2026
https://github.com/vikramRH updated https://github.com/llvm/llvm-project/pull/201004
>From 44ab57057f802c28604c41a3d359315b7dbec8b7 Mon Sep 17 00:00:00 2001
From: vikhegde <vikram.hegde at amd.com>
Date: Mon, 1 Jun 2026 14:55:42 +0530
Subject: [PATCH 1/2] [CodeGen] Treat Reg uses which are partailly defined
within bundle as internal read
---
llvm/lib/CodeGen/MachineInstrBundle.cpp | 52 ++++++++++---
llvm/test/CodeGen/AMDGPU/finalizebundle.mir | 76 +++++++++++++++++++
.../CodeGen/AMDGPU/hard-clauses-gfx1250.mir | 42 ++++++++++
3 files changed, 161 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/CodeGen/MachineInstrBundle.cpp b/llvm/lib/CodeGen/MachineInstrBundle.cpp
index 663b755193695..c84c562905ad2 100644
--- a/llvm/lib/CodeGen/MachineInstrBundle.cpp
+++ b/llvm/lib/CodeGen/MachineInstrBundle.cpp
@@ -10,10 +10,12 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/LiveRegUnits.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
@@ -115,16 +117,23 @@ static DebugLoc getDebugLoc(MachineBasicBlock::instr_iterator FirstMI,
}
/// Check if target reg is contained in given lists, which are:
-/// LocalDefsV as given list for virtual regs
-/// LocalDefsP as given list for physical regs, in BitVector[RegUnit] form
+/// LocalDefsV as given list for virtual regs.
+/// LocalDefsP as given list for physical regs, in BitVector[RegUnit] form.
+/// This uses the ExternDefs to see if the reg is "partially defined"
+/// within the bundle. i.e a subreg of Reg is defined within the bundle
+/// while the remianing part is undef.
static bool containsReg(SmallSetVector<Register, 32> LocalDefsV,
- const BitVector &LocalDefsP, Register Reg,
- const TargetRegisterInfo *TRI) {
+ const BitVector &LocalDefsP,
+ const BitVector &ExternDefs,
+ const TargetRegisterInfo *TRI, Register Reg,
+ bool TracksLiveness, bool IsUndefUse) {
if (Reg.isPhysical()) {
- for (MCRegUnit Unit : TRI->regunits(Reg.asMCReg()))
- if (!LocalDefsP[static_cast<unsigned>(Unit)])
- return false;
-
+ for (MCRegUnit Unit : TRI->regunits(Reg.asMCReg())) {
+ unsigned U = static_cast<unsigned>(Unit);
+ if (LocalDefsP[U] || (TracksLiveness && !IsUndefUse && !ExternDefs[U]))
+ continue;
+ return false;
+ }
return true;
}
return LocalDefsV.contains(Reg);
@@ -150,6 +159,30 @@ void llvm::finalizeBundle(MachineBasicBlock &MBB,
BuildMI(MF, getDebugLoc(FirstMI, LastMI), TII->get(TargetOpcode::BUNDLE));
Bundle.prepend(MIB);
+ // Compute the regunits whose definitions reach the bundle from outside,
+ // we use this to mark a partial-def + full-reg-uses as IsInternalRead.
+ bool TracksLiveness = MF.getRegInfo().tracksLiveness();
+ LiveRegUnits ExternDefs(*TRI);
+ if (TracksLiveness) {
+ if (MF.getRegInfo().reservedRegsFrozen()) {
+ const BitVector &Reserved = MF.getRegInfo().getReservedRegs();
+ for (int RegIdx = Reserved.find_first(); RegIdx >= 0;
+ RegIdx = Reserved.find_next(RegIdx))
+ ExternDefs.addReg(MCRegister(RegIdx));
+ }
+ ExternDefs.addLiveIns(MBB);
+ for (auto It = MBB.instr_begin(); It != FirstMI; ++It) {
+ if (It->isDebugInstr())
+ continue;
+ for (const MachineOperand &MO : It->operands()) {
+ if (!MO.isReg() || !MO.isDef() || MO.isDead() ||
+ !MO.getReg().isPhysical())
+ continue;
+ ExternDefs.addReg(MO.getReg().asMCReg());
+ }
+ }
+ }
+
SmallSetVector<Register, 32> LocalDefs;
BitVector LocalDefsP(TRI->getNumRegUnits());
SmallSet<Register, 8> DeadDefSet;
@@ -168,7 +201,8 @@ void llvm::finalizeBundle(MachineBasicBlock &MBB,
if (!Reg)
continue;
- if (containsReg(LocalDefs, LocalDefsP, Reg, TRI)) {
+ if (containsReg(LocalDefs, LocalDefsP, ExternDefs.getBitVector(), TRI,
+ Reg, TracksLiveness, MO.isUndef())) {
MO.setIsInternalRead();
if (MO.isKill()) {
// Internal def is now killed.
diff --git a/llvm/test/CodeGen/AMDGPU/finalizebundle.mir b/llvm/test/CodeGen/AMDGPU/finalizebundle.mir
index 590d69b8eb869..528826da656cb 100644
--- a/llvm/test/CodeGen/AMDGPU/finalizebundle.mir
+++ b/llvm/test/CodeGen/AMDGPU/finalizebundle.mir
@@ -11,6 +11,10 @@
define void @test_mmo_merge1() { unreachable }
define void @test_mmo_merge2() { unreachable }
define void @test_mmo_drop() { unreachable }
+ define void @test_partial_def_1() { unreachable }
+ define void @test_partial_def_2() { unreachable }
+ define void @test_partial_def_3() { unreachable }
+ define void @test_partial_def_4() { unreachable }
...
@@ -99,3 +103,75 @@ body: |
DS_WRITE_B32_gfx9 %0:vgpr_32, %1:vgpr_32, 0, 0, implicit $exec :: (store (s32) into @foo, addrspace 3)
DS_WRITE_B32_gfx9 %0:vgpr_32, %1:vgpr_32, 4, 0, implicit $exec
...
+
+---
+name: test_partial_def_1
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $sgpr0_sgpr1, $vgpr1
+ ; CHECK-LABEL: name: test_partial_def_1
+ ; CHECK: liveins: $sgpr0_sgpr1, $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: BUNDLE implicit-def $vgpr0_lo16, implicit-def dead $vgpr0, implicit $sgpr0_sgpr1, implicit $vgpr1, implicit $exec {
+ ; CHECK-NEXT: $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ ; CHECK-NEXT: $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, internal killed $vgpr0, implicit $exec
+ ; CHECK-NEXT: }
+ $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, killed $vgpr0, implicit $exec
+...
+
+---
+name: test_partial_def_2
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+ ; CHECK-LABEL: name: test_partial_def_2
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: BUNDLE implicit-def $vgpr2_vgpr3, implicit-def $vgpr5_vgpr6, implicit $vgpr0_vgpr1 {
+ ; CHECK-NEXT: $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ ; CHECK-NEXT: $vgpr5_vgpr6 = COPY internal $vgpr3_vgpr4
+ ; CHECK-NEXT: }
+ $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ $vgpr5_vgpr6 = COPY $vgpr3_vgpr4
+...
+
+---
+name: test_partial_def_3
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0_vgpr1
+ ; CHECK-LABEL: name: test_partial_def_3
+ ; CHECK: liveins: $vgpr0_vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: BUNDLE implicit-def $vgpr2_vgpr3, implicit-def $vgpr3_vgpr4, implicit-def $vgpr5_vgpr6_vgpr7, implicit-def $vgpr8_vgpr9, implicit $vgpr0_vgpr1 {
+ ; CHECK-NEXT: $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ ; CHECK-NEXT: $vgpr3_vgpr4 = COPY $vgpr0_vgpr1
+ ; CHECK-NEXT: $vgpr5_vgpr6_vgpr7 = COPY internal $vgpr3_vgpr4_vgpr5
+ ; CHECK-NEXT: $vgpr8_vgpr9 = COPY internal $vgpr3_vgpr4
+ ; CHECK-NEXT: }
+ $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ $vgpr3_vgpr4 = COPY $vgpr0_vgpr1
+ $vgpr5_vgpr6_vgpr7 = COPY $vgpr3_vgpr4_vgpr5
+ $vgpr8_vgpr9 = COPY $vgpr3_vgpr4
+...
+
+---
+name: test_partial_def_4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+ ; CHECK-LABEL: name: test_partial_def_4
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: BUNDLE implicit-def $vgpr2_vgpr3, implicit-def $vgpr5_vgpr6, implicit $vgpr0_vgpr1, implicit undef $vgpr3_vgpr4 {
+ ; CHECK-NEXT: $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ ; CHECK-NEXT: $vgpr5_vgpr6 = COPY undef $vgpr3_vgpr4
+ ; CHECK-NEXT: }
+ $vgpr2_vgpr3 = COPY $vgpr0_vgpr1
+ $vgpr5_vgpr6 = COPY undef $vgpr3_vgpr4
+...
diff --git a/llvm/test/CodeGen/AMDGPU/hard-clauses-gfx1250.mir b/llvm/test/CodeGen/AMDGPU/hard-clauses-gfx1250.mir
index 79480bc8017f7..f186e98946c25 100644
--- a/llvm/test/CodeGen/AMDGPU/hard-clauses-gfx1250.mir
+++ b/llvm/test/CodeGen/AMDGPU/hard-clauses-gfx1250.mir
@@ -635,3 +635,45 @@ body: |
$vgpr2 = GLOBAL_LOAD_DWORD $vgpr0_vgpr1, 0, 0, implicit $exec, implicit $flat_scr
$vgpr3 = GLOBAL_LOAD_DWORD $vgpr0_vgpr1, 4, 24, implicit $exec, implicit $flat_scr
...
+
+---
+name: global_load_dword_short_partial_def_1
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $sgpr0_sgpr1, $vgpr3
+ ; GFX12-LABEL: name: global_load_dword_short_partial_def_1
+ ; GFX12: liveins: $sgpr0_sgpr1, $vgpr3
+ ; GFX12-NEXT: {{ $}}
+ ; GFX12-NEXT: $vgpr1 = COPY $vgpr3
+ ; GFX12-NEXT: BUNDLE implicit-def $vgpr0_lo16, implicit-def dead $vgpr0, implicit $sgpr0_sgpr1, implicit $vgpr1, implicit $exec {
+ ; GFX12-NEXT: S_CLAUSE 1
+ ; GFX12-NEXT: $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ ; GFX12-NEXT: $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, internal killed $vgpr0, implicit $exec
+ ; GFX12-NEXT: }
+ $vgpr1 = COPY $vgpr3
+ $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, killed $vgpr0, implicit $exec
+...
+
+---
+name: global_load_dword_short_partial_def_2
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $sgpr0_sgpr1, $vgpr3
+ ; GFX12-LABEL: name: global_load_dword_short_partial_def_2
+ ; GFX12: liveins: $sgpr0_sgpr1, $vgpr3
+ ; GFX12-NEXT: {{ $}}
+ ; GFX12-NEXT: $vgpr1 = COPY $vgpr3
+ ; GFX12-NEXT: $vgpr0_hi16 = COPY $vgpr1_hi16
+ ; GFX12-NEXT: BUNDLE implicit-def $vgpr0_lo16, implicit-def $vgpr0, implicit $sgpr0_sgpr1, implicit $vgpr1, implicit $exec, implicit killed $vgpr0 {
+ ; GFX12-NEXT: S_CLAUSE 1
+ ; GFX12-NEXT: $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ ; GFX12-NEXT: $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, killed $vgpr0, implicit $exec
+ ; GFX12-NEXT: }
+ $vgpr1 = COPY $vgpr3
+ $vgpr0_hi16 = COPY $vgpr1_hi16
+ $vgpr0_lo16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 $sgpr0_sgpr1, $vgpr1, 0, 0, implicit $exec
+ $vgpr0 = GLOBAL_LOAD_SHORT_D16_HI_SADDR $sgpr0_sgpr1, $vgpr1, 512, 0, killed $vgpr0, implicit $exec
+...
>From 636740f73ade33cc8b1d6569f40a9a77bd29cb79 Mon Sep 17 00:00:00 2001
From: vikhegde <vikram.hegde at amd.com>
Date: Tue, 9 Jun 2026 17:15:35 +0530
Subject: [PATCH 2/2] add test
---
.../si-insert-hard-clause-bundle-fail.ll | 59 +++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/si-insert-hard-clause-bundle-fail.ll
diff --git a/llvm/test/CodeGen/AMDGPU/si-insert-hard-clause-bundle-fail.ll b/llvm/test/CodeGen/AMDGPU/si-insert-hard-clause-bundle-fail.ll
new file mode 100644
index 0000000000000..d45a527f91123
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-insert-hard-clause-bundle-fail.ll
@@ -0,0 +1,59 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; test that the test does not fail machine verification due to instruction bundling.
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1150 -verify-machineinstrs -o - < %s | FileCheck %s
+
+define <8 x i16> @test(i32 %block_offset.023.i.i.i.i.i, ptr addrspace(1) %invariant.gep.i.i.i.i.i) {
+; CHECK-LABEL: test:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: v_dual_mov_b32 v3, v0 :: v_dual_mov_b32 v4, 0
+; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; CHECK-NEXT: v_lshlrev_b64 v[3:4], 1, v[3:4]
+; CHECK-NEXT: v_add_co_u32 v6, vcc_lo, v1, v3
+; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; CHECK-NEXT: v_add_co_ci_u32_e64 v7, null, v2, v4, vcc_lo
+; CHECK-NEXT: s_clause 0x6
+; CHECK-NEXT: global_load_d16_b16 v0, v[6:7], off
+; CHECK-NEXT: global_load_d16_b16 v5, v[6:7], off offset:1024
+; CHECK-NEXT: global_load_d16_b16 v4, v[6:7], off offset:2048
+; CHECK-NEXT: global_load_d16_b16 v3, v[6:7], off offset:3072
+; CHECK-NEXT: global_load_d16_hi_b16 v0, v[1:2], off offset:20
+; CHECK-NEXT: global_load_d16_hi_b16 v5, v[6:7], off offset:1536
+; CHECK-NEXT: global_load_d16_hi_b16 v4, v[6:7], off offset:2560
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: v_dual_mov_b32 v1, v5 :: v_dual_mov_b32 v2, v4
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %idx.ext.i.i.i.i.i = zext i32 %block_offset.023.i.i.i.i.i to i64
+ %gep.i.i.i.i.i = getelementptr inbounds nuw [2 x i8], ptr addrspace(1) %invariant.gep.i.i.i.i.i, i64 %idx.ext.i.i.i.i.i
+ %48 = load i16, ptr addrspace(1) %gep.i.i.i.i.i, align 2, !tbaa !23
+ %49 = insertelement <8 x i16> poison, i16 %48, i64 0
+ %arrayidx.1.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 512
+ %50 = load i16, ptr addrspace(1) %arrayidx.1.i.i.i.i.i.i, align 2, !tbaa !23
+ %51 = insertelement <8 x i16> %49, i16 %50, i64 1
+ %arrayidx.2.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 1024
+ %52 = load i16, ptr addrspace(1) %arrayidx.2.i.i.i.i.i.i, align 2, !tbaa !23
+ %53 = insertelement <8 x i16> %51, i16 %52, i64 2
+ %arrayidx.3.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 1536
+ %54 = load i16, ptr addrspace(1) %arrayidx.3.i.i.i.i.i.i, align 2, !tbaa !23
+ %55 = insertelement <8 x i16> %53, i16 %54, i64 3
+ %arrayidx.4.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 2048
+ %56 = load i16, ptr addrspace(1) %arrayidx.4.i.i.i.i.i.i, align 2, !tbaa !23
+ %57 = insertelement <8 x i16> %55, i16 %56, i64 4
+ %arrayidx.5.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 2560
+ %58 = load i16, ptr addrspace(1) %arrayidx.5.i.i.i.i.i.i, align 2, !tbaa !23
+ %59 = insertelement <8 x i16> %57, i16 %58, i64 5
+ %arrayidx.6.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 3072
+ %60 = load i16, ptr addrspace(1) %arrayidx.6.i.i.i.i.i.i, align 2, !tbaa !23
+ %61 = insertelement <8 x i16> %59, i16 %60, i64 6
+ %arrayidx.7.i.i.i.i.i.i = getelementptr inbounds nuw i8, ptr addrspace(1) %gep.i.i.i.i.i, i64 3584
+ %62 = load i16, ptr addrspace(1) %arrayidx.7.i.i.i.i.i.i, align 2, !tbaa !23
+ %63 = insertelement <8 x i16> %61, i16 %62, i64 7
+ %tmp3 = getelementptr inbounds nuw [2 x i8], ptr addrspace(1) %invariant.gep.i.i.i.i.i, i64 10
+ %tmp4 = load i16, ptr addrspace(1) %tmp3, align 2, !tbaa !23
+ %tmp5 = insertelement <8 x i16> %61, i16 %tmp4, i64 1
+ ret <8 x i16> %tmp5
+}
+
+!7 = !{!"omnipotent char", !8, i64 0}
+!8 = !{!"Simple C++ TBAA"}
+!23 = !{!7, !7, i64 0}
More information about the llvm-commits
mailing list