This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyCFG] Fix a crash when folding PHIs
ClosedPublic

Authored by davide on May 7 2018, 5:36 PM.

Details

Summary

This fixes a crash found by @zhendongsu when running SimplifyCFG.
This is the gist:

We enter MergeBlockIntoPredecessor with a block looking like this:

for.inc.us-lcssa:                                 ; preds = %cond.end
  %k.1.lcssa.ph = phi i32 [ %conv15, %cond.end ]
  %t.3.lcssa.ph = phi i32 [ %k.1.lcssa.ph, %cond.end ]
  br label %for.inc, !dbg !66

[note the first arg of the PHI being a PHI].

FoldSingleEntryPHINodes gets rid of both PHIs (calling, eraseFromParent).
But right before we call the function, we push into IncomingValues the only argument of the PHIs, and shortly after we try to iterate over something which has been invalidated before :(

The way I propose(d) to fix this is that of not pushing into IncomingValues if PN.getIncomingValue(0) isa<PHINode>.
It seems enough to cover all the cases. Eli proposed to move the debug info handling in the function which takes care of folding the phi, although this is a little tricky because we remove the redundant dbg.values post slice (so it's left as a follow up).

An attempt to fix:
http://llvm.org/bugs/show_bug.cgi?id=37300 and rdar://problem/39910460

The thing that worries me the most is the testcase (as it's admittedly, insane). I spent some time trying to reduce it but I was never able to get to something manageable in size (or something which doesn't screw up debug info). bugpoint itself doesn't seem to help much here. Ideas on how to reduce further are appreciated :)

Diff Detail

Repository
rL LLVM

Event Timeline

davide created this revision.May 7 2018, 5:36 PM

That testcase is huge. Do all instructions need !dbg locations?

davide added a comment.May 7 2018, 5:47 PM

That testcase is huge. Do all instructions need !dbg locations?

I can probably limit the number of !dbg location attached to the instructions, and that could shrink the test a bit [but still crashing], if you're fine with it.
I was mainly worried about feeding something which is different from what the frontend/previous passes provide.

davide added a comment.May 7 2018, 6:38 PM

Got it down to 350 lines ~ with your suggestion, but still I'm not happy if I look at the size
https://reviews.llvm.org/P8079

davide added a comment.May 7 2018, 7:06 PM

I think I found a better (but slow :() way to reduce it. I'll send an updated testcase tomorrow.

I've slowly come to always prefer the smallest possible test case, since anything else makes it impossible for future readers to determine what the test is supposed to be testing and it is very easy to end up with cargo-cult testcases that don't test anything interesting after a while.

Thanks, the new test looks much better!

vsk added inline comments.May 8 2018, 11:49 AM
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
155 ↗(On Diff #145602)

Would it be safe/worthwhile to allow incoming values which are phi nodes from a block other than BB? These should not be invalidated by FoldSingleEntryPHINodes(). If the goal is to eliminate duplicate dbg.values for incoming values, then it might make sense.

Apologies if this is off-base, I'm not familiar with this code.

efriedma added inline comments.May 8 2018, 11:51 AM
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
152 ↗(On Diff #145602)

AssertingVH? (This would also make it easier to reduce the testcase, by turning undefined behavior into a simple assertion failure.)

155 ↗(On Diff #145602)

Maybe !isa<PHINode>(PN.getIncomingValue(0)) || cast<PHINode>(PN.getIncomingValue(0))->getParent() != BB, or something like that, so we preserve debug info in more cases?

davide updated this revision to Diff 145781.May 8 2018, 2:11 PM

Addressed comments. Thanks!

vsk added a comment.May 8 2018, 4:02 PM

This seems sensible to me! It'd be great if someone more familiar with simplifyCfg could +1.

efriedma accepted this revision.May 8 2018, 4:04 PM

LGTM

This revision is now accepted and ready to land.May 8 2018, 4:04 PM
This revision was automatically updated to reflect the committed changes.