TracksLiveness property and isKill flag

Hi all,

The property TracksLiveness has comment

// TracksLiveness: True when tracking register liveness accurately.
// While this property is set, register liveness information in basic block
// live-in lists and machine instruction operands (e.g. kill flags, implicit
// defs) is accurate. This means it can be used to change the code in ways
// that affect the values in registers, for example by the register
// scavenger.
// When this property is clear, liveness is no longer reliable.

Can I assume that when a MachineFunction has the TracksLiveness
property I can use the isKill flag of a register operand?

But when I try the following test

*** IR Dump After Module Verifier (verify) ***
define i32 @test2(i32* %p, i32 %a, i32 %b, i32 %c) {
entry:
  %0 = add i32 %a, %b
  %1 = add i32 %0, %c
  store i32 %1, i32* %p, align 4
  %sub1 = sub nsw i32 %a, %b
  ret i32 %sub1
}
# *** IR Dump After X86 DAG->DAG Instruction Selection (amdgpu-isel) ***:
# Machine code for function test2: IsSSA, TracksLiveness
Function Live Ins: $rdi in %0, $esi in %1, $edx in %2, $ecx in %3

bb.0.entry:
  liveins: $rdi, $esi, $edx, $ecx
  %3:gr32 = COPY $ecx
  %2:gr32 = COPY $edx
  %1:gr32 = COPY $esi
  %0:gr64 = COPY $rdi
  %4:gr32 = ADD32rr %1:gr32(tied-def 0), %2:gr32, implicit-def dead $eflags
  %5:gr32 = ADD32rr %4:gr32(tied-def 0), %3:gr32, implicit-def dead $eflags
  MOV32mr %0:gr64, 1, $noreg, 0, $noreg, killed %5:gr32 :: (store 4 into %ir.p)
  %6:gr32 = nsw SUB32rr %1:gr32(tied-def 0), %2:gr32, implicit-def dead $eflags
  $eax = COPY %6:gr32
  RET 0, $eax

# End machine code for function test2.

The generated MachineFunction has TracksLiveness property, but for all
virtual registers, only %5 has the correct isKill flag, others don't
have this flag.

Could anyone help to clarify the usage of TracksLiveness and isKill?

thanks a lot!
Guozhi Wei

Hi Carrot,

Kill flags are an optional information and it is not linked to the track liveness property per se.

Essentially, when looking at individual operands, if a kill flag is present it must be correct. If there is no kill flag, the operand can be a last use or not. Also, if you see at least one kill flag within the function, that doesn’t mean all the kill flags are set.
Bottom line the kill flags are optional, conservatively correct flags.

If you want reliable last use information, I encourage you to use the LiveIntervals analysis or after regalloc, you can use llvm::recomputeLivenessFlags.

Regarding TracksLiveness, when this property is true, that means what the comment says in what you shared :).
More explicitly that means that the MachineFunction properly reflects the liveness information of all the values in that function:

  • live-in sets are correct
  • the live intervals analysis if available is correct
  • the live variables analysis if available is correct
  • definitions are before uses

Cheers,
-Quentin

Hi Quentin

Thanks for the clarification!
A little more questions inlined.

Hi Carrot,

Kill flags are an optional information and it is not linked to the track liveness property per se.

The following explanation is quite clear to me, but in the
TracksLiveness comment it says kill flag is accurate, it is still very
confusing depends on the meaning of accurate. I'm not a native English
speaker and don't have confidence to make it better, so could you help
to make the comment more clearer? Or you can just paste the new
comment here, I'm happy to make a patch for it.

Essentially, when looking at individual operands, if a kill flag is present it must be correct. If there is no kill flag, the operand can be a last use or not. Also, if you see at least one kill flag within the function, that doesn’t mean all the kill flags are set.
Bottom line the kill flags are optional, conservatively correct flags.

If you want reliable last use information, I encourage you to use the LiveIntervals analysis or after regalloc, you can use llvm::recomputeLivenessFlags.

Can LiveVariables provide precise kill flags?

Regarding TracksLiveness, when this property is true, that means what the comment says in what you shared :).
More explicitly that means that the MachineFunction properly reflects the liveness information of all the values in that function:
- live-in sets are correct
- the live intervals analysis if available is correct
- the live variables analysis if available is correct
- definitions are before uses
- …

So the property TracksLiveness is set in most of time, and it is
cleared at the very end time, am I correct?

Hi Quentin

Thanks for the clarification!
A little more questions inlined.

Hi Carrot,

Kill flags are an optional information and it is not linked to the track liveness property per se.

The following explanation is quite clear to me, but in the
TracksLiveness comment it says kill flag is accurate, it is still very
confusing depends on the meaning of accurate.

Maybe we could patch up the comment, indeed. The reality of this is that the kill flags are accurate but only on the operands where they are set.
The rationale here is keeping them up to date can be challenging so most optimizations just clear them when they are unsure. So the only guarantee we make is that they are conservatively correct.

I'm not a native English
speaker and don't have confidence to make it better, so could you help
to make the comment more clearer? Or you can just paste the new
comment here, I'm happy to make a patch for it.

Essentially, when looking at individual operands, if a kill flag is present it must be correct. If there is no kill flag, the operand can be a last use or not. Also, if you see at least one kill flag within the function, that doesn’t mean all the kill flags are set.
Bottom line the kill flags are optional, conservatively correct flags.

If you want reliable last use information, I encourage you to use the LiveIntervals analysis or after regalloc, you can use llvm::recomputeLivenessFlags.

Can LiveVariables provide precise kill flags?

Well, yes, but I wouldn’t recommend to rely on it.

LiveVariables only works on pure SSA form, i.e., before we run the PHI elimination and the two address passes. So if you want precise kill flags after any of these passes, you cannot re-run it.
Also keep in mind, that kill flags can be dropped by any optimization passes between LiveVariables and where you may want to use it.
Finally, we stopped half way through, but eventually we want to remove that pass. (See the comments in TargetPassConfig.cpp around LiveVariables.)

Putting all together, it is better if your pass doesn’t depend on kill flags to do the right thing. Instead use LiveIntervals.

Regarding TracksLiveness, when this property is true, that means what the comment says in what you shared :).
More explicitly that means that the MachineFunction properly reflects the liveness information of all the values in that function:
- live-in sets are correct
- the live intervals analysis if available is correct
- the live variables analysis if available is correct
- definitions are before uses
- …

So the property TracksLiveness is set in most of time, and it is
cleared at the very end time, am I correct?

Correct, yes.

Hi Quentin

Can I change to comment to

  // TracksLiveness: True when tracking register liveness accurately.
  // While this property is set, register liveness information in basic block
  // live-in lists and machine instruction operands (e.g. implicit
  // defs) is accurate, kill flags are conservatively accurate (kill flag
  // correctly indicates the last use of a register, an operand without kill
  // flag may or may not be the last use of a register). This means it can
  // be used to change the code in ways that affect the values in
  // registers, for example by the register scavenger.
  // When this property is cleared at a very late time, liveness is no longer
  // reliable.

Hi Quentin

Can I change to comment to

// TracksLiveness: True when tracking register liveness accurately.
// While this property is set, register liveness information in basic block
// live-in lists and machine instruction operands (e.g. implicit
// defs) is accurate, kill flags are conservatively accurate (kill flag
// correctly indicates the last use of a register, an operand without kill
// flag may or may not be the last use of a register). This means it can
// be used to change the code in ways that affect the values in
// registers, for example by the register scavenger.
// When this property is cleared at a very late time, liveness is no longer
// reliable.

Looks good to me.