This is an archive of the discontinued LLVM Phabricator instance.

[DebugInfo] Handle undefined values for DBG_PHIs in InstrRef-LiveDebugValues
ClosedPublic

Authored by StephenTozer on May 16 2023, 12:29 PM.

Details

Summary

Fixes https://github.com/llvm/llvm-project/issues/62725

When running llc on the IR file in the above issue, after ISel there is a DBG_INSTR_REF and a single DBG_PHI that it references; at some point in the MIR pipeline, the block containing the DBG_PHI becomes unreachable. When we reach LiveDebugValues, this results in a crash due to unreachable blocks not being considered: In the initial tracking of DBG_PHIs, we will set the value of the lone DBG_PHI as the live-in value at the phi location, i.e. {4,0,4}. In ExtendRanges we perform a machine value dataflow analysis and apply the result to the collected DBG_PHIs. *Generally* this means each DBG_PHI will be updated to use the resolved value if one is found, and otherwise is unchanged. When the DBG_PHI is in an unreachable block however it will be updated to use the empty value instead, which is inconsistent with other phi values (which use an empty optional instead), resulting in us attempting to use the empty value as an actual value and triggering an assertion.

This patch fixes this error by checking for empty live-in values after the data flow analysis, and continuing to use the existing phi value if no value was found for that phi in the analysis. This prevents crashes from mishandling the empty value internally, and results in the correct value being found for any users of the DBG_PHI.

Diff Detail

Event Timeline

StephenTozer created this revision.May 16 2023, 12:29 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 16 2023, 12:29 PM
Herald added a subscriber: hiraditya. · View Herald Transcript
StephenTozer requested review of this revision.May 16 2023, 12:29 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 16 2023, 12:29 PM

This works around the reported crash, which is great. However, there are going to be ValueIDNums with slightly different interpretations as a result of the DebugPHIRecord not being updated. I don't *think* (90% sure) that's going to lead to incorrect variable locations, as the machine-location problem being solved just removes un-necessary PHIs. Thus, not updating the ValueIDNum which will have previously referred to a live-in value (aka a PHI):

  • If the PHI is eliminated, the ValueIDNum will refer to a value that's never defined, therefore any variables using this value will be optimized out (which is fine for now),
  • If the PHI is retained, then ValueIDNum will refer to it , and it will be correct (I think?).

Would you agree?

Could you stick a FIXME in the code-comment you've added indicating that we should find a better overall solution than just not updating the live-in ValueIDNum.

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
3720

NB, PHI not Phi

llvm/test/DebugInfo/X86/instr-ref-unreachable.mir
2–9

File-comment indicating what's the intention behind the test is please

Would you agree?

I think that this change might just be the right thing to do: If the DBG_PHI does not refer to an invalid location, such as a dead stack slot, then the PHI-elimination step should always identify a non-empty value for that location: either the PHI for that location, or some non-empty value if we eliminated that PHI. The only exception to this as far as I can tell is if the block containing the DBG_PHI is unreachable, in which case all incoming values will be the empty value. Hence this code assumes that if we observe an empty value for a DBG_PHI with a valid location, it must be because this block is unreachable.

In that case, leaving the DBG_PHI value unchanged should mean it continues to refer to the live-in value for that location, which I think is correct - we have no way of knowing what the live-in value will be if the block is reached by an indirect jump, so leaving the DBG_PHI referring to the live-in value seems like the sensible approach to me; WDYT?

That sounds alright; some of the trouble is that I don't like the terminology of "leaving" it as a live-in -- through this step we effectively transform live-in ValueIDNums into PHI ValueIDNums and intend for them to be correct.

With that in mind, could you revise the comment into something like... " If there is no resolved value for this live-in then it is not directly reachable from the entry block -- model it as a PHI on entry to this block, which means we leave the ValueIDNum unchanged" if that sounds alright to you?

SGTM; added and updated comments as suggested.

jmorse accepted this revision.May 18 2023, 4:14 AM

LGTM. Interesting that we get a DBG_PHI dominated by another same-numbered DBG_PHI here, I don't think that's a problem for any code we have but a curiosity to be aware of.

This revision is now accepted and ready to land.May 18 2023, 4:14 AM

LGTM. Interesting that we get a DBG_PHI dominated by another same-numbered DBG_PHI here, I don't think that's a problem for any code we have but a curiosity to be aware of.

That example is entirely artificial, it just exists in the test to provide an example where one DBG_PHI being unreachable doesn't automatically undef the user. I would have thought it possible that some combination of legal CFG transformations could cause one DBG_PHI to become dominated by another, but if you think it's infeasible and undesirable to include then I can remove that part from the test.

That example is entirely artificial, it just exists in the test to provide an example where one DBG_PHI being unreachable doesn't automatically undef the user. I would have thought it possible that some combination of legal CFG transformations could cause one DBG_PHI to become dominated by another, but if you think it's infeasible and undesirable to include then I can remove that part from the test.

Best to remove it then IMO, and just exercise the one with instr-ref number 1 one, to ensure that the crash is avoided. Alternately, put something in bb.4 checking that the location can be resolved inside a block where the live-in value is available?

It looks as though when the DBG_INSTR_REF is in the non-directly-reachable block, even when it is in the same block as the DBG_PHI, we give it a $noreg value after LDV. I've left this in the test with a FIXME comment describing the situation; although it's a niche case, I think it's worth keeping it in the test as a potential future fixup, WDYT?

Seems fine as a FIXME as we're aiming to avoid the crash for now