This is an archive of the discontinued LLVM Phabricator instance.

[LiveDebugValues] Cleanup Transfers when removing Entry Value Location
ClosedPublic

Authored by ntesic on Jul 27 2021, 2:12 AM.

Details

Summary

If we encounter a new debug value, describing the same parameter, we should stop tracking
the parameter's Entry Value. At that point, in some cases, the Transfer which uses the parameter's
Entry Value, is already emitted. Thanks to the RemoveRedundantDebugValues pass, many problems with
incorrect instruction order and number of DBG_VALUEs are fixed. However, we still cannot rely on the
rule that each new debug value is set by the previous non-debug instruction in Machine Basic Block.

When new parameter debug value triggers removal of Backup Entry Value for the same parameter,
do the cleanup of Transfers emitted from Backup Entry Values.
Get the Transfer Instruction which created the new debug value and search for debug values already
emitted from the to-be-deleted Backup Entry Value and attached to the Transfer Instruction.
If found, delete the Transfer and remove "primary" Entry Value Var Loc from OpenRanges.

This patch fixes PR47628.

Diff Detail

Event Timeline

ntesic created this revision.Jul 27 2021, 2:12 AM
ntesic requested review of this revision.Jul 27 2021, 2:12 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 27 2021, 2:12 AM

As I understand it, this patch is aiming to recognise patterns where an entry value is being copied to a new register location and then being DBG_VALUE'd, which is effectively a no-op as far as tracking entry values is concerned.

I think the EntryValTransfers container is going to suffer from not being aware that it's part of a dataflow algorithm: one transfer gets inserted per emitEntryValues, and we can repeatedly explore the same block in a loop as part of the dataflow algorithm. But cleanupEntryValueTransfers will only delete one entry -- I suspect it should try and delete all matching entries. (The uh, Transfers collection suffers from the same problem, which I had a patch for at D67500, but didn't push it particularly hard).

The RegSetterInstructionMap is purely to find COPYs that might mean the entry value doesn't have to be dropped, yes? This seems OK, so long as it's not relied upon to determine whether a register contains a different value -- values can be defined when blocks merge and the join method runs.

llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
1237–1238

Always returns true -> should instead be void? This disguises the fact that removeEntryValue always intends to return true when it calls this function.

1248–1249

You might be able to use llvm::make_range and turn this into a range-based-loop, which would be a little more readable.

1251–1253

Any reason to not use the VarLoc operator==?

1284–1286

What about loop heads like this:

entry:
  DBG_VALUE $rdi

loop:
  DBG_VALUE $rdi
  $rdi = somedef
  JMP loop

The second DBG_VALUE refers to a different value, due to the def of rdi in the loop. On the first examination of loop, there wouldn't be any reason to remove an entry value; presumably we can rely on the join method to erase the EntryValueBackupKind locations when the loop is visited for a second time?

1315–1322

There are four identical return/calls like this after TransferInst is assigned, and two instances of "return false". Wouldn't it be better to switch the logic to return cleanupEntryValue... by default, and pick out the two instances where false is returned?

1422–1424

Could I recommend assert(EntryValueIDs.size() == 1 && "EntryValue loc should not be variadic");.

(Purely for communicating the assumptions this is based on to the reader)

Hi Jeremy,
Thanks for the comments.

This patch purpose is to fix PR47628 and improve
the solution from D68209 .
Here is the more detailed explanation.

Typical MIR in focus of the patch:

$edi = MOV
DBG_VALUE $edi, ,"param"

Step_1: MI: $edi = MOV ...

  • LDV detects parameter forwarding register is clobbered.
  • As the primary location of parameter is lost, we use its EntryValue Backup location as the new primary location, and emit the Transfer.

Step_2: MI: DBG_VALUE $edi, ,"param"

  • LDV detects parameter value is modified.
  • The EntryValue Backup location of the parameter is not valid anymore.

Problem:
Step_2 means we shouldn't have used EntryValue Backup location in Step_1.

Old solution:

  • removes EntryVarLoc from EntryValue Backup locations
  • not from primary locations (OpenRanges) if inserted
  • doesn't invalidate already emitted Transfer

Solution from this patch - do the cleanup to undo the Step_1:

  • remove emitted EntryValueTransfer
  • remove EntryVarLoc from OpenRanges

Bad MIR example from PR47628:

    renamable $edi = MOV32rm $rip, 1, $noreg, @value, $noreg, debug-location !20
[1] DBG_VALUE $edi, $noreg, !13, !DIExpression(DW_OP_LLVM_entry_value, 1), [...]
    DBG_VALUE $edi, $noreg, !13, !DIExpression(), debug-location !14
    ...
    CALL64pcrel32 @bar, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, debug-location !20
[2] DBG_VALUE $edi, $noreg, !13, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !13

Consequences of the main problem:
[1] Not-deleted Transfer that uses parameter Entry Value will result in bad DBG_VALUE in MIR.
[2] Not-deleted Entry Value Location from Open Ranges will result in usage of incorrect VarLoc later in code.

As I understand it, this patch is aiming to recognise patterns where an entry value is being copied to a new register location and then being DBG_VALUE'd, which is effectively a no-op as far as tracking entry values is concerned.

This patch is not focused on copyies of entry values. As I understand, that is already included in D68209 .

I think the EntryValTransfers container is going to suffer from not being aware that it's part of a dataflow algorithm: one transfer gets inserted per emitEntryValues, and we can repeatedly explore the same block in a loop as part of the dataflow algorithm. But cleanupEntryValueTransfers will only delete one entry -- I suspect it should try and delete all matching entries. (The uh, Transfers collection suffers from the same problem, which I had a patch for at D67500, but didn't push it particularly hard).

The EntryValTransfers container is managed in the similar way as the Transfers.
But, as it is used to do cleanup only for the previous register defining instruction, I don't see that as the problem further in dataflow algorithm.
(In short terms, if we find DBG_VALUE of changed parameter, do the cleanup only for the instruction that created that DBG_VALUE.)

The RegSetterInstructionMap is purely to find COPYs that might mean the entry value doesn't have to be dropped, yes? This seems OK, so long as it's not relied upon to determine whether a register contains a different value -- values can be defined when blocks merge and the join method runs.

When we find new DBG_VALUE of a parameter, if its debug operand is a Register, find which instruction clobbered the Register using RegSetterInstructionMap.
Then we can map that instruction to an emitted Entry Value Transfer.
The insertion into RegSetterInstructionMap is tied to definitions of a registers found by the transferRegisterDef function, so we don't pay attention to the value loaded into the Register.

ntesic added inline comments.Jul 28 2021, 5:33 AM
llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
1251–1253

Well, the EntryVL is of a "backup" kind, and EmittedEV isn't. So, the == operator doesn't see them as equal.

1422–1424

Sure, I agree with that proposal.

ntesic added inline comments.Jul 28 2021, 5:37 AM
llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
1237–1238

I agree. I should definitely find more elegant way to call the cleanupEntryValueTransfers .

ntesic updated this revision to Diff 365942.Aug 12 2021, 2:29 AM
  • Address comments
  • Refactor removeEntryValue
  • Add a test for the loop case emphasized by @jmorse
ntesic marked 5 inline comments as done.Aug 12 2021, 2:30 AM
ntesic marked an inline comment as done.Aug 12 2021, 2:44 AM
ntesic added inline comments.
llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
1284–1286

Thanks for pointing this out!
I think we should stop tracking Entry Value if we find DBG_VALUE describing new definition, without taking into consideration why is the DBG_VALUE there. From this point, I don't see a way to use Entry Value location only for the first examination of loop and not for others, since it is the code at the same PC offset.

My proposal is to preserve Entry Value only for the parameter DBG_VALUEs at the start of entry BB. At this point those, parameter DBG_VALUEs, are not propagated into other BBs, so we don't need to worry about other BBs.

djtodoro added inline comments.Aug 12 2021, 4:21 AM
llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
795

Please add comments describing these types (+ any better name for this type?)

796

RegDefToInstMap

1251–1253

can we use the std::tie() here?

ntesic updated this revision to Diff 366231.Aug 13 2021, 3:50 AM
ntesic marked 3 inline comments as done.Aug 13 2021, 3:52 AM

@djtodoro Thanks for the comments, I agree with all of them.

ntesic updated this revision to Diff 366583.Aug 16 2021, 3:58 AM

Reformat the code.
@jmorse, @djtodoro Any additional comments? Thanks.

djtodoro accepted this revision.Aug 25 2021, 4:21 AM

Thanks.

This revision is now accepted and ready to land.Aug 25 2021, 4:21 AM
This revision was landed with ongoing or failed builds.Aug 30 2021, 5:17 AM
This revision was automatically updated to reflect the committed changes.