This is an archive of the discontinued LLVM Phabricator instance.

IfConversion: Add implicit uses for redefined regs with live subregisters
ClosedPublic

Authored by kparzysz on Aug 4 2016, 12:21 PM.

Details

Summary

Normally, if conversion would add implicit uses for redefined registers, e.g. R0<def> = add_if ..., R0<imp-use>. However, if only subregisters of R0 are known to be live but not R0 itself, such implicit uses will not be added, causing prior definitions of such subregisters and R0 itself to become dead.

Diff Detail

Repository
rL LLVM

Event Timeline

kparzysz updated this revision to Diff 66837.Aug 4 2016, 12:21 PM
kparzysz updated this revision to Diff 66838.
kparzysz retitled this revision from to Treat aliased registers as live in if-conversion.
kparzysz updated this object.
kparzysz added reviewers: qcolombet, jonpa.
kparzysz set the repository for this revision to rL LLVM.
kparzysz added a subscriber: llvm-commits.

Removed debug statement.

jonpa edited edge metadata.Aug 5 2016, 2:30 AM

It seems LivePhysRegs::addReg() adds the register and its sub regs, so I am thinking it should be enough here to iterate over super regs (including self) instead of all aliases?

kparzysz updated this revision to Diff 66933.Aug 5 2016, 5:44 AM
kparzysz edited edge metadata.

Replaced the reg-alias iterator with super-reg iterator.

From what I can understand, the MachineFunction has first the %R16 and %R17 defined in BB#0, to be later used in BB#2. This is why these registers are the ones present in
the live-in lists to begin with, and not %D8. Then, the Hexagon Copy-To-Combine pass rewrites BB#0, to copy %D8 with one instruction. The live-in lists remain the same, and the use operands also:

(abbreviated)

BB#0: derived from LLVM BB %entry
    Live Ins: %R0 %R1 %D8 %D8
	%R16<def> = A2_tfr %R1<kill>
	%R17<def> = A2_tfr %R0<kill>
    Successors according to CFG: BB#3(0x30000000 / 0x80000000 = 37.50%) BB#1(0x50000000 / 0x80000000 = 62.50%)

BB#1: derived from LLVM BB %for.body.preheader
    Live Ins: %R16 %R17
    Predecessors according to CFG: BB#0
    Successors according to CFG: BB#2(?%)

BB#2: derived from LLVM BB %for.body
    Live Ins: %D2 %R16 %R17 %R29 %R30 %R31
    Predecessors according to CFG: BB#1 BB#2
	%R17<def> = A2_addi %R17<kill>, -1
	%R16<def> = A2_addi %R16<kill>, 8

-> # After Hexagon Copy-To-Combine Pass:

BB#0: derived from LLVM BB %entry
    Live Ins: %R0 %R1 %D8 %D8
	%D8<def> = A2_combinew %R0<kill>, %R1<kill>

BB#1: derived from LLVM BB %for.body.preheader
    Live Ins: %R16 %R17
    Predecessors according to CFG: BB#0
    Successors according to CFG: BB#2(?%)

BB#2: derived from LLVM BB %for.body
    Live Ins: %D2 %R16 %R17 %R29 %R30 %R31
	%R17<def> = A2_addi %R17<kill>, -1
	%R16<def> = A2_addi %R16<kill>, 8

The first question for me is if this transformation is entirely correct. Should also implicit-defs of %R16 or %R17 be added to the new instruction? Or should it add %D8 to live-in lists and as implicit-use operands? (The latter alternative seems discouraging due to its complexity).

This patch seems conservatively right though in this context to assume that %D8 is live when any one of its subregs is live (it will make LivePhysRegs in later passes think that all of the subregs are live.)

Quentin, what do you think?

qcolombet edited edge metadata.Sep 8 2016, 4:49 PM

Hi Krzysztof,

Thanks for your patience, I missed the patch earlier.

I don't like the idea of the if-converter growing the live-in set for no apparent reason. In my opinion, we end up in this situation because other passes did something wrong, like in that case the Copy-To-Combine pass if I understand correctly.

To give a bit more concret on why I don't like it, Matthias recently removed a similar fix in BranchFolding IIRC, that in the end was kidding bugs somewhere else.

Cheers,
-Quentin

kparzysz updated this revision to Diff 70850.Sep 9 2016, 9:22 AM
kparzysz retitled this revision from Treat aliased registers as live in if-conversion to IfConversion: Add implicit uses for live subregisters.
kparzysz updated this object.
kparzysz edited edge metadata.

Changed the approach from making super-register live, to adding implicit uses of sub-registers.

Ping. This is a different solution---it does not change the live-in set.

Hi Krzysztof,

We were discussing similar liveness issues in https://reviews.llvm.org/D17257 with Jonas and I believe the right way to fix that would be to switch the live-in sets to RegUnit. The implicit operand would work but they look like a workaround to the actual problem to me.
Adding the RegUnit instead of the PhysReg is easy and could be hidden in the addLiveIn method, removing them is a different story.

Cheers,
-Quentin

The implicit operand would work but they look like a workaround to the actual problem to me.

If I understand correctly---the reg unit approach will still add the implicit operands, it will just use reg units to track liveness?

If I understand correctly---the reg unit approach will still add the implicit operands, it will just use reg units to track liveness?

You shouldn't need the implicit operands anymore, because the double register would make the two reg unit of the simple register live and the uses would be from those reg unit.
In other words,
live in: D0 (sets reg unit A and B)
use S0 (uses reg unit A)
use S1 (uses reg unit B)
Would be valid without anything else. (Modulo updating the MachineVerifier to check at the RegUnit level).
But again, the problem with the RegUnit approach is that updating the live-ins may be expensive.

I admit I did not spend a lot of time thinking about it.

Cheers,
Q.

kparzysz added a comment.EditedSep 22 2016, 12:53 PM

You shouldn't need the implicit operands anymore, because the double register would make the two reg unit of the simple register live and the uses would be from those reg unit.

Then I don't understand.

I have an instruction:
d8 = L2_loadrd_io <base-reg>, <offset> # load register double

It then is predicated (assume that no implicit operands are added):
d8 = L2_ploadrdf_io <pred-reg>, <base-reg>, <offset> # load register double if-false

If if-conversion puts that block together with a prior definition of r17 (a subreg of d8), e.g
r17 = <something>
d8 = L2_ploadrdf_io <pred-reg>, <base-reg>, <offset> # load register double if-false
how will the compiler know that the first one is not dead?

MatzeB edited edge metadata.Sep 22 2016, 1:15 PM

If I understand correctly---the reg unit approach will still add the implicit operands, it will just use reg units to track liveness?

You shouldn't need the implicit operands anymore, because the double register would make the two reg unit of the simple register live and the uses would be from those reg unit.
In other words,
live in: D0 (sets reg unit A and B)
use S0 (uses reg unit A)
use S1 (uses reg unit B)
Would be valid without anything else. (Modulo updating the MachineVerifier to check at the RegUnit level).
But again, the problem with the RegUnit approach is that updating the live-ins may be expensive.

I don't see how we could get away without the implicit operands in the if-conversion (without teaching many other parts of the compiler what predicated code is). I wrote a longer explanation in another review where I had to remind myself: https://reviews.llvm.org/D20907#476017

Looks fine to me in principle, however I think we can get away with 1 implicit use per clobber at most:

lib/CodeGen/IfConversion.cpp
1456–1460

Would it be more reasonable to check if any subreg is alive and then only add a single implicit use for Reg. Otherwise I'd be concerned that we end up with a large number of implicit-use operands for deep register hierarchies.

MatzeB added inline comments.Sep 22 2016, 1:31 PM
test/CodeGen/Hexagon/ifcvt-live-subreg.mir
3

Always good to see a small and to the point test.

  • I'd add a sentence about what is tested.
  • It's good style to have at least one CHECK-LABEL: name: foo in case someone adds more functions later (also sometimes protects you from accidentally matching random output before the function starts).
  • I'd also go and CHECK for all if-converted instructions to make it a bit more obvious what is happening here.
kparzysz added inline comments.Sep 28 2016, 10:26 AM
lib/CodeGen/IfConversion.cpp
1456–1460

I've been thinking about it. What about this case?

Live-in: %H
if (...) {
  // Define/use super-reg.
  %H:L = ...
  ... = %H:L
}
// %H is still live here
... = %H

After if-conversion we would end up with something like

%H:L = predicated ..., %H:L<imp-use>
... = predicated %H:L

Wouldn't the implicit use be invalid (since %L is not defined)?

kparzysz added inline comments.Sep 28 2016, 10:30 AM
lib/CodeGen/IfConversion.cpp
1456–1460

The %H:L above is meant to represent a super-register consisting of two halves: %H and %L respectively.

MatzeB added inline comments.Sep 28 2016, 11:12 AM
lib/CodeGen/IfConversion.cpp
1456–1460

Using partially defined registers is fine. (It would only be invalid if it would be completely undefined).

kparzysz marked 2 inline comments as done.Sep 28 2016, 12:30 PM
kparzysz updated this revision to Diff 72879.Sep 28 2016, 12:31 PM
kparzysz retitled this revision from IfConversion: Add implicit uses for live subregisters to IfConversion: Add implicit uses for redefined regs with live subregisters.
kparzysz updated this object.
kparzysz edited edge metadata.

Applied suggested changes.

MatzeB accepted this revision.Sep 28 2016, 12:59 PM
MatzeB edited edge metadata.

LGTM

This revision is now accepted and ready to land.Sep 28 2016, 12:59 PM
kparzysz closed this revision.Sep 28 2016, 1:20 PM

Committed in r282626. Forgot to add link in the commit message, so closing manually.