-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[RegisterPressure] NFC: Clean up RP handling for instructions with overlapping Def/Use #109875
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
Conversation
…erlapping Def/Use Change-Id: I4edebef95688a9814c46b73166e9ca88a97e5304
@llvm/pr-subscribers-llvm-regalloc Author: Jeffrey Byrnes (jrbyrnes) ChangesThe current RP handling for uses of an MI that overlap with defs is confusing and unnecessary. Moreover, it is incorrect if the RP tracked register by subreg / lane. This cleans it up a bit by snking the use handling into the subsequent use loop (which has more accurate handling if we were to track RP by subreg). The effect of this PR is to replace A. with B. Note that A and B have different definitions of LiveBefore A. and B. Also note, A. NewMask = ~LiveAfter & ((LiveAfter & ~DefLanes) | UseLanes) => (1 & UseLanes) => UseLanes = (0 | UseLanes) => (LiveAfter | UseLanes) = NewMask B. Full diff: https://github.com/llvm/llvm-project/pull/109875.diff 1 Files Affected:
diff --git a/llvm/lib/CodeGen/RegisterPressure.cpp b/llvm/lib/CodeGen/RegisterPressure.cpp
index 59a1911555e9cd..a517cb9631556e 100644
--- a/llvm/lib/CodeGen/RegisterPressure.cpp
+++ b/llvm/lib/CodeGen/RegisterPressure.cpp
@@ -1060,18 +1060,12 @@ void RegPressureTracker::bumpUpwardPressure(const MachineInstr *MI) {
LaneBitmask LiveBefore = (LiveAfter & ~DefLanes) | UseLanes;
// There may be parts of the register that were dead before the
- // instruction, but became live afterwards. Similarly, some parts
- // may have been killed in this instruction.
+ // instruction, but became live afterwards.
decreaseRegPressure(Reg, LiveAfter, LiveAfter & LiveBefore);
- increaseRegPressure(Reg, LiveAfter, ~LiveAfter & LiveBefore);
}
- // Generate liveness for uses.
+ // Generate liveness for uses. Also handle any uses which overlap with defs.
for (const RegisterMaskPair &P : RegOpers.Uses) {
Register Reg = P.RegUnit;
- // If this register was also in a def operand, we've handled it
- // with defs.
- if (getRegLanes(RegOpers.Defs, Reg).any())
- continue;
LaneBitmask LiveAfter = LiveRegs.contains(Reg);
LaneBitmask LiveBefore = LiveAfter | P.LaneMask;
increaseRegPressure(Reg, LiveAfter, LiveBefore);
|
This suggests that it is not NFC? Is there any way of testing this? |
I think you're right that the wording suggests that, but the "proof" that @jrbyrnes wrote in the commit message shows that this is NFC. |
I confirm that this is true. If we already counted the regunit there's no point in adding it again, hence the behavior that @jrbyrnes described. |
Well, yes and no. With the way things currently are, this change has no impact as the versions of the code are logically equivalent. This is because the generic trackers do not track by subreg. Since the RP tracker tracks by whole reg, if (when increasing RP) any lane in the register was previously live, then we do not modify RP (even if Width - 1 Lanes just become live). Thus, if the PreviousMask had any live lanes, we exit from increaseRegPressure since the whole reg is already live. Due to this exit, the code versions are logically equivalent (as @qcolombet confirmed)
However, if we were to track RP by subreg (instead of whole reg), we would be interested in looking at the delta between the previous mask and the new mask in terms of individual lanes. This implies that PrevMask would model the state of live lanes before the instruction, and NewMask would model the state of live lanes after the instruction. The current call to Thus, when tracking by subreg, there are functional changes. (e.g. we need to account for this in #93090 or else RP tracking is broken).
Yeah, I think it may be helpful since there are a lot of details to consider when analyzing this code. The best I can think of is a unittest which checks the masks -- I'll look into this |
…erlapping Def/Use (llvm#109875) The current RP handling for uses of an MI that overlap with defs is confusing and unnecessary. Moreover, the lane masks do not accurately model the liveness behavior of the subregs. This cleans things up a bit and more accurately models subreg lane liveness by sinking the use handling into subsent Uses loop. The effect of this PR is to replace A. `increaseRegPressure(Reg, LiveAfter, ~LiveAfter & LiveBefore)` with B. `increaseRegPressure(Reg, LiveAfter, LiveBefore)` Note that A (Defs loop) and B (Uses loop) have different definitions of LiveBefore A. `LiveBefore = (LiveAfter & ~DefLanes) | UseLanes` and B. `LiveBefore = LiveAfter | UseLanes` Also note, `increaseRegPressure` will exit if `PrevMask` (`LiveAfter` for both A/B) has any active lanes, thus these calls will only have an effect if `LiveAfter` is 0. A. NewMask = ~LiveAfter & ((LiveAfter & ~DefLanes) | UseLanes) => (1 & UseLanes) => UseLanes = (0 | UseLanes) => (LiveAfter | UseLanes) = NewMask B.
…erlapping Def/Use (llvm#109875) The current RP handling for uses of an MI that overlap with defs is confusing and unnecessary. Moreover, the lane masks do not accurately model the liveness behavior of the subregs. This cleans things up a bit and more accurately models subreg lane liveness by sinking the use handling into subsent Uses loop. The effect of this PR is to replace A. `increaseRegPressure(Reg, LiveAfter, ~LiveAfter & LiveBefore)` with B. `increaseRegPressure(Reg, LiveAfter, LiveBefore)` Note that A (Defs loop) and B (Uses loop) have different definitions of LiveBefore A. `LiveBefore = (LiveAfter & ~DefLanes) | UseLanes` and B. `LiveBefore = LiveAfter | UseLanes` Also note, `increaseRegPressure` will exit if `PrevMask` (`LiveAfter` for both A/B) has any active lanes, thus these calls will only have an effect if `LiveAfter` is 0. A. NewMask = ~LiveAfter & ((LiveAfter & ~DefLanes) | UseLanes) => (1 & UseLanes) => UseLanes = (0 | UseLanes) => (LiveAfter | UseLanes) = NewMask B. (cherry picked from commit cd40070) Change-Id: I8e733510825098b0a8359c4997436841ecb50dd3
The current RP handling for uses of an MI that overlap with defs is confusing and unnecessary. Moreover, the lane masks do not accurately model the liveness behavior of the subregs. This cleans things up a bit and more accurately models subreg lane liveness by sinking the use handling into subsent Uses loop.
The effect of this PR is to replace
A.
increaseRegPressure(Reg, LiveAfter, ~LiveAfter & LiveBefore)
with
B.
increaseRegPressure(Reg, LiveAfter, LiveBefore)
Note that A (Defs loop) and B (Uses loop) have different definitions of LiveBefore
A.
LiveBefore = (LiveAfter & ~DefLanes) | UseLanes
and
B.
LiveBefore = LiveAfter | UseLanes
Also note,
increaseRegPressure
will exit ifPrevMask
(LiveAfter
for both A/B) has any active lanes, thus these calls will only have an effect ifLiveAfter
is 0.A. NewMask = ~LiveAfter & ((LiveAfter & ~DefLanes) | UseLanes) => (1 & UseLanes) => UseLanes = (0 | UseLanes) => (LiveAfter | UseLanes) = NewMask B.