This is an archive of the discontinued LLVM Phabricator instance.

[SCCP] Calculate Null Pointer Comparisons
Needs ReviewPublic

Authored by njw45 on May 9 2015, 6:26 AM.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary

Loading from a null pointer is undefined; the SimplifyCfg pass correctly decides that any conditional branches that lead to a null pointer derefence can't be taken, and so replaces them with an unconditional branch. We can go further though; if the branch in question post-dominates the Value used to decide which branch to take, then we know exactly what constant that is everywhere in the function. If the Value is a cmp instruction, then we don't need to evaluate it any more - this patch replaces all uses of the comparison with the known constant and removes the unneeded instruction.

Diff Detail

Event Timeline

njw45 updated this revision to Diff 25403.May 9 2015, 6:26 AM
njw45 retitled this revision from to [SCCP] Calculate Null Pointer Comparisons.
njw45 updated this object.
njw45 edited the test plan for this revision. (Show Details)
njw45 added a subscriber: Unknown Object (MLST).May 9 2015, 6:27 AM

This looks generally good.

Do you have any numbers on how often it triggers/helps?
Same with compilation time cost.

It would be nice to know both. The first should be easy, just adding another Statistic to the top and looking at it.

sanjoy added a subscriber: sanjoy.May 11 2015, 10:41 AM

I'm not sure that this is doing the right thing -- I don't think simply producing undef implies undefined behavior.

For instance, in

declare void @g()

define i1 @test_postdominate(i8* %mem) {
  %test = icmp eq i8* %mem, null
  br i1 %test, label %a, label %b
a:
  call void @g()
  br label %c
b:
  br label %c
c:
  %join = phi i8* [ %mem, %a ], [ null, %b ]
  %gep = getelementptr inbounds i8, i8* %join, i64 4
  ret i1 %test
}

if %mem is null, then we have to execute the call to @g, but this pass make the branch into a dead (so @f never calls @g). The fact that %gep is undef (or poison) does not make this program undefined. In fact, if inbounds GEP instructions could invoke UB, then we would not be able to hoist such instructions out of loops.

njw45 updated this revision to Diff 25734.May 13 2015, 2:31 PM

Change to SimplifyCFG, not SCCP

njw45 added a comment.May 13 2015, 2:34 PM

Does it make sense to make simplifycfg smarter instead of sccp?

Yes - that makes the code change much smaller (no need for a custom
visitor)! I've pushed a (completely) new version of the patch to
http://reviews.llvm.org/D9634 . Thanks -

Nick

reames requested changes to this revision.May 13 2015, 3:28 PM
reames added a reviewer: reames.
reames added a subscriber: reames.

Please provide a real description of the change. You'll need a submission comment eventually, please write that and add it to the review. Also, please update the title. This is not specific to null checks.

lib/Transforms/Utils/SimplifyCFG.cpp
4626 ↗(On Diff #25734)

This is wrong since the condition may not be in the same basic block as the branch we're reasoning about. You can replace dominated uses, but not all uses.

You might find these changes interesting:
http://reviews.llvm.org/D9312 - this ones directly analogous in JumpThreading.
http://reviews.llvm.org/D9763 - this prunes a lot of easy cases earlier in the pipeline, possibly removing a bunch of pass ordering problems

This revision now requires changes to proceed.May 13 2015, 3:28 PM
njw45 updated this object.May 15 2015, 9:59 AM
njw45 edited the test plan for this revision. (Show Details)
njw45 edited edge metadata.
njw45 updated this revision to Diff 25871.May 15 2015, 10:02 AM
njw45 edited edge metadata.

Ensure we only replace the conditional if we postdominate it (+test)

Please provide a real description of the change.

I've updated the review description - hope it's OK now!

You can replace dominated uses

Ah yes, I've carried that functionality forward from the SCCP version
of the patch. Unfortunately the SimplifyCFG pass has been updated to
use the new pass manager, but the post-dominator tree analysis hasn't,
so this patch now converts it to too (so it's now +250 -157). I've
also added another unit test to prove that it doesn't do the
optimisation when the branch doesn't post-dominate the test.

Thanks -

Nick

njw45 updated this revision to Diff 25873.May 15 2015, 10:11 AM
njw45 edited edge metadata.

remove trailing whitespace from test

To my knowledge, post-dominance information is not currently used within LLVM's existing passes. As a result, you'd need to justify the cost of the post-dom-tree computation.

I strongly request that you implement the trivial post dominance case (i.e. in same basic block as per the linked patch) to start with. If you then want to propose using post-dominance information more widely, I'm open to that discussion. I just don't want to couple of the optimization at hand with a broader (and harder to justify) discussion.

Once the optimizations in, we could either enhance it by pursuing the post-dominance information or by using the replaceDominatesUses mechanism from GVN and (soon) EarlyCSE.

p.s. You haven't updated any of the existing transforms to keep the post dominance info up to date. As a result, the code as currently structured is really, really wrong.

p.p.s. Your description mentions icmps. I don't get why you're making the restriction. Regardless of the source, you know the value of the Value. Your actual code doesn't seem to have this restriction.

lib/Transforms/Scalar/SampleProfile.cpp
100 ↗(On Diff #25873)

I think you've mixed patches here?

reames resigned from this revision.Jun 15 2015, 4:34 PM
reames removed a reviewer: reames.

Removing myself as review from an aparently abandoned review. Feel free to readd me as a reviewer for new updates. I'm only removing so that I don't see this in my list of pending reviews.