Data flow/liveness in register pairs

Hello,

Consider this code (this is all after register allocation):

   R0<def> = ... R0 // Set lower half (based on the previous value)
   R1<def> = ... // Set upper half
   ... = R0_R1 // Use the pair

It is my understanding that the use of the whole pair will need to have some sort of a reaching def, i.e. the code will need at least those flags:

   R0<def> = ... R0 // Set lower half (based on the previous value)
   R1<def> = ... R0_R1<imp-def> // Set upper half (and the whole pair)
   ... = R0_R1 // Use the pair

The problem is that this will introduce data-flow dependency between the first and the second instruction, since the first one uses a half of what the second one implicitly defines. What I want is to separate the information about a super-register being defined from the instructions that define parts of it.

I was contemplating something like this:
   R0<def> = ... R0 // Set lower half (based on the previous value)
   R1<def> = ... // Set upper half
   R0_R1<def> = pseudo-consider-register-defined-here
   ... = R0_R1 // Use the pair
specifically with IMPLICIT_DEF, but that does not do what I thought it would.

I have also thought of doing this before register allocation, using something like this:
   vreg100:lower_half<def,read-undef> = ...
   vreg100:upper_half<def,read-undef> = ...
but the after the second instruction, the "lower_half" will revert to "undef" (at least according to my understanding).

Having simply
   vreg100:lower_half<def,read-undef> = ...
   vreg100:upper_half<def> = ...
will treat the second instruction as an implicit use of both halves of vreg100 (and introduce the dreaded dependency).

Any suggestions as to how to deal with this?

-Krzysztof

Hello,

Consider this code (this is all after register allocation):

R0<def> = ... R0 // Set lower half (based on the previous value)
R1<def> = ... // Set upper half
... = R0_R1 // Use the pair

It is my understanding that the use of the whole pair will need to have some sort of a reaching def, i.e. the code will need at least those flags:

R0<def> = ... R0 // Set lower half (based on the previous value)
R1<def> = ... R0_R1<imp-def> // Set upper half (and the whole pair)

You also need R0<imp-use> for correctness.

... = R0_R1 // Use the pair

The problem is that this will introduce data-flow dependency between the first and the second instruction, since the first one uses a half of what the second one implicitly defines. What I want is to separate the information about a super-register being defined from the instructions that define parts of it.

I was contemplating something like this:
R0<def> = ... R0 // Set lower half (based on the previous value)
R1<def> = ... // Set upper half
R0_R1<def> = pseudo-consider-register-defined-here
... = R0_R1 // Use the pair
specifically with IMPLICIT_DEF, but that does not do what I thought it would.

The current rules require reaching defs to be expressed for physical registers. That's why you also need an imp-use here. That said, I don't think the current rules are realistic. If you ignore the rules and strip all implicit def/use operands the consequences are:

- MachineVerifier complains. You can communicate that you've broken physreg liveness by calling MRI->invalidateLiveness. Once you've done this, you can't benefit from code that needs physreg liveness. See MRI->tracksLiveness

- CriticalAntiDepBreaker breaks. This is a feature of postRA scheduling that scavenges registers. It is enabled or disabled for each subtarget. You should verify and assert that it is disabled. The PostRA scheduler's DAG builder should still work fine though. It will track dependencies on physreg aliases correctly.

- PEI wil probably break for the same reason as CriticalAntiDepBreaker. It runs right after register rewriting. So if you expand this code or just strip the imp-def/uses after PEI then it's not a problem.

I have also thought of doing this before register allocation, using something like this:
vreg100:lower_half<def,read-undef> = ...
vreg100:upper_half<def,read-undef> = ...
but the after the second instruction, the "lower_half" will revert to "undef" (at least according to my understanding).

Having simply
vreg100:lower_half<def,read-undef> = ...
vreg100:upper_half<def> = ...
will treat the second instruction as an implicit use of both halves of vreg100 (and introduce the dreaded dependency).

Any suggestions as to how to deal with this?

As with physregs, you need an imp-use operand on the second definitions for correct dependencies.

The current DAG builder for scheduling does not model subregisters, so you will get the false dependence. You could fake it by modifying the DAG builder or postprocessing the DAG and checking for subreg aliasing using this interface:

  unsigned getSubRegIndexLaneMask(unsigned SubIdx)

However, live interval update will break when the subreg defs are reordered. This will take a little more work to fix. I have been wanting to develop a more general API for liveness update, so that's not a bad direction to take. But it won't be fixed overnight.

Ideally, liveintervals itself would work at the level of virtual sub registers, but that's a big design problem without much payoff. (We haven't seen a significant need to reorder subregister defs). So I suggest for now you focus on one of the workarounds I mentioned above.

-Andy