-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[LiveVariables] Mark use as implicit-def if defined at instr #119446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-backend-amdgpu Author: None (jofrn) ChangesLiveVariables will mark instructions with their implicit subregister uses. However, it will miss marking the subregister as an implicit-def if its own definition is a subregister of it, i.e. This change ensures such uses are marked as implicit-def, i.e. Full diff: https://github.com/llvm/llvm-project/pull/119446.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/LiveVariables.cpp b/llvm/lib/CodeGen/LiveVariables.cpp
index f17d60dc22dda9..e6753563a24c28 100644
--- a/llvm/lib/CodeGen/LiveVariables.cpp
+++ b/llvm/lib/CodeGen/LiveVariables.cpp
@@ -277,10 +277,21 @@ void LiveVariables::HandlePhysRegUse(Register Reg, MachineInstr &MI) {
continue;
if (PartDefRegs.count(SubReg))
continue;
+
+ // Check if SubReg is defined at LastPartialDef.
+ bool IsDefinedHere = false;
+ for (int i = 0; i < LastPartialDef->getNumOperands(); ++i) {
+ auto MO = LastPartialDef->getOperand(i);
+ if (!MO.isDef()) continue;
+ if (TRI->isSubRegister(SubReg, MO.getReg())) {
+ IsDefinedHere = true;
+ break;
+ }
+ }
// This part of Reg was defined before the last partial def. It's killed
// here.
LastPartialDef->addOperand(MachineOperand::CreateReg(SubReg,
- false/*IsDef*/,
+ IsDefinedHere/*IsDef*/,
true/*IsImp*/));
PhysRegDef[SubReg] = LastPartialDef;
for (MCPhysReg SS : TRI->subregs(SubReg))
diff --git a/llvm/test/CodeGen/AMDGPU/implicitdef-subreg.mir b/llvm/test/CodeGen/AMDGPU/implicitdef-subreg.mir
new file mode 100644
index 00000000000000..9b11bb482a028e
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/implicitdef-subreg.mir
@@ -0,0 +1,44 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -O1 %s --run-pass=livevars -implicitdef -o - | FileCheck %s
+---
+name: sgpr_copy
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: sgpr_copy
+ ; CHECK: %sval:sreg_32 = S_MOV_B32 0
+ ; CHECK-NEXT: $sgpr0 = COPY %sval
+ ; CHECK-NEXT: $sgpr1 = COPY %sval
+ ; CHECK-NEXT: $sgpr2 = COPY %sval
+ ; CHECK-NEXT: $sgpr3 = COPY killed %sval, implicit-def $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr0, implicit $sgpr1, implicit $sgpr2, implicit $sgpr0_sgpr1, implicit $sgpr0_sgpr1_sgpr2, implicit-def $sgpr2_sgpr3
+ ; CHECK-NEXT: dead $sgpr30_sgpr31 = COPY killed $sgpr0_sgpr1_sgpr2_sgpr3
+ %sval:sreg_32 = S_MOV_B32 0
+
+ $sgpr0 = COPY %sval
+ $sgpr1 = COPY %sval
+ $sgpr2 = COPY %sval
+ $sgpr3 = COPY %sval
+ $sgpr30_sgpr31 = COPY $sgpr0_sgpr1_sgpr2_sgpr3
+
+...
+---
+name: vgpr_copy
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: vgpr_copy
+ ; CHECK: %sval:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; CHECK-NEXT: $vgpr0 = COPY %sval
+ ; CHECK-NEXT: $vgpr1 = COPY %sval
+ ; CHECK-NEXT: $vgpr2 = COPY %sval
+ ; CHECK-NEXT: $vgpr3 = COPY killed %sval, implicit-def $vgpr0_vgpr1_vgpr2_vgpr3, implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit $vgpr0_vgpr1, implicit $vgpr0_vgpr1_vgpr2, implicit-def $vgpr1_vgpr2_vgpr3
+ ; CHECK-NEXT: dead [[COPY:%[0-9]+]]:vgpr_32 = COPY killed $vgpr0_vgpr1_vgpr2_vgpr3
+ %sval:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+
+ $vgpr0 = COPY %sval
+ $vgpr1 = COPY %sval
+ $vgpr2 = COPY %sval
+ $vgpr3 = COPY %sval
+ %0:vgpr_32 = COPY $vgpr0_vgpr1_vgpr2_vgpr3
+
+...
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
bb287c4
to
d450a15
Compare
LiveVariables will mark instructions with their implicit subregister uses. However, it will miss marking the subregister as an implicit-def if its own definition is a subregister of it, i.e. `$r3 = OP val, implicit-def $r0_r1_r2_r3, ..., implicit $r2_r3`, which defines $sr3 on the same line it is used. This change ensures such uses are marked as implicit-def, i.e. `$r3 = OP val, implicit-def $r0_r1_r2_r3, ..., implicit-def $r2_r3`.
d450a15
to
6b852f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you need this for? We should be trying to get rid of the LiveVariables pass. All of the code here for handling sub registers is very out of date
llvm/lib/CodeGen/LiveVariables.cpp
Outdated
|
||
// Check if SubReg is defined at LastPartialDef. | ||
bool IsDefinedHere = false; | ||
for (int I = 0; I < LastPartialDef->getNumOperands(); ++I) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole function looks like it could use a rewrite. Is this a re-invention of MachineInstr::modifiesRegister?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parent function, LiveVariables::HandlePhysRegUse
, will additionally collect definitions of Reg
(e.g. four COPY
instructions for a use of $sgpr0_$sgpr1_$sgpr2_sgpr3
in a subsequent instruction), and mark the last definition with its implicit uses and defs.
modifiesRegister
can be used here in place of this loop. It will also mark superregisters though, so will try the tests again...
If we do not have this, then
|
Do you have an IR sample that hits this? Should add as a test if so |
This also causes superregisters to be marked as implicit-def.
9c0aa9b
to
0208eb9
Compare
Yes, added it in. |
llvm/lib/CodeGen/LiveVariables.cpp
Outdated
false/*IsDef*/, | ||
true/*IsImp*/)); | ||
LastPartialDef->addOperand( | ||
MachineOperand::CreateReg(SubReg, IsDefinedHere, true /*IsImp*/)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swapping what used to be a use with a def sounds wrong. Do we need multiple implicit operands to model this liveness?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will only be switched if the use is defined at this line. By the way, if the use is omitted or marked as implicit-def
, the test will also pass, so we do not need implicit-def
; we just need to remove the implicit
use.
Multiple implicit operands will be added if they are subregs of Reg
within LiveVariables::HandlePhysRegUse
, so I believe it is already being modeled.
Alternatively, there can potentially be handling of this issue at the point of the error (during LiveIntervalCalc
). The implicit use causes a "use not jointly dominated by def" error here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we just need to remove the implicit use.
So can you just skip the add operand altogether? I'm still confused about why this pass is doing anything. This is very old code that predates subregister tracking. I bet we can delete all of this code as a step towards deleting the entire pass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it can be skipped. However, llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir
would need to be updated to not mark implicit-def $w2_hi
, which may be incorrect, so I believe it is better to leave the implicit-def
in.
I'd argue that we are not really replacing what used to be a use with a def. They should have been defs all along because the sub or super register has a definition at this line.
If we do not fix it here, the logic to fix it in LiveRangeCalc.cpp needs to update LiveRangeCalc::findReachingDefs
to take into consideration definitions that are found at the current instruction. And it propagates a change to be made in RegisterPressure.cpp, so I think it is cleaner to have it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveRangeCalc requiring this pass run before is spaghetti. We shouldn't need this pass to fix the liveness representation. The liveness of physical registers should be fully expressed at all points in the compilation. This pass has been papering over issues in LiveRangeCalc
The implicit-def of w2_hi is redundant with the x2 implicit-def. The use was marking a kill (except it didn't add a kill flag?). So there's no reason to have the new implicit-def, and losing the implicit use loses the use kill point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed a chunk of the code, which also got rid of w2_hi
, so now it doesn't have a kill point... Need to take a closer look at it to see if we can keep w2_hi
here. Perhaps it doesn't have a kill flag for the reason of it being erroneously added in this function.
@@ -756,7 +756,7 @@ body: | | |||
; CHECK: liveins: $x0, $x1, $x2 | |||
; CHECK-NEXT: {{ $}} | |||
; CHECK-NEXT: early-clobber renamable $x1, renamable $x0 = LDRSWpre renamable $x1, 40, implicit $w1, implicit $w1_hi :: (load (s32)) | |||
; CHECK-NEXT: renamable $w2 = LDRWui renamable $x1, 1, implicit-def $x2, implicit $w2_hi :: (load (s32)) | |||
; CHECK-NEXT: renamable $w2 = LDRWui renamable $x1, 1, implicit-def $x2, implicit-def $w2_hi :: (load (s32)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x2 is composed of [w2, and w2_hi], the implicit-def of w2_hi is redundant with the implicit-def of $x2.
llvm/lib/CodeGen/LiveVariables.cpp
Outdated
false/*IsDef*/, | ||
true/*IsImp*/)); | ||
LastPartialDef->addOperand( | ||
MachineOperand::CreateReg(SubReg, IsDefinedHere, true /*IsImp*/)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveRangeCalc requiring this pass run before is spaghetti. We shouldn't need this pass to fix the liveness representation. The liveness of physical registers should be fully expressed at all points in the compilation. This pass has been papering over issues in LiveRangeCalc
The implicit-def of w2_hi is redundant with the x2 implicit-def. The use was marking a kill (except it didn't add a kill flag?). So there's no reason to have the new implicit-def, and losing the implicit use loses the use kill point
86d785f
to
b65b610
Compare
b65b610
to
ebc5d0c
Compare
Any thing else that needs to be addressed other than the lit test ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can push forward with this, but we should still work to delete this pass. This is really out of date subregister management, and LiveRangeCalc should not require preprocessing
@@ -0,0 +1,46 @@ | |||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 | |||
# RUN: llc -mtriple=amdgcn --run-pass=livevars -o - %s | FileCheck %s | |||
--- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment the purpose of the test
$vgpr2 = COPY %vval | ||
$vgpr3 = COPY %vval | ||
%0:vgpr_32 = COPY $vgpr0_vgpr1_vgpr2_vgpr3 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add some more complex cases, like a def of a different tuple in the middle (e.g. v0, v[1:2], v3). And cases where the result has undefined holes (e.g. def v0, v2, v3 leaving v1 undef)
LiveVariables will mark instructions with their implicit subregister uses. However, it will miss marking the subregister as an implicit-def if its own definition is a subregister of it, i.e.
$r3 = OP val, implicit-def $r0_r1_r2_r3, ..., implicit $r2_r3
, which defines $r3 on the same line it is used.This change ensures such uses are marked as implicit-def, i.e.
$r3 = OP val, implicit-def $r0_r1_r2_r3, ..., implicit-def $r2_r3
.