[llvm] [CodeGen] Treat Reg uses which are partailly defined within bundle as internal read (PR #201004)
Vikram Hegde via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 22:05:47 PDT 2026
https://github.com/vikramRH updated https://github.com/llvm/llvm-project/pull/201004
>From 9039771a25e618ff03c447fef37fce6a1c06ff74 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] [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
+...
More information about the llvm-commits
mailing list