This is an archive of the discontinued LLVM Phabricator instance.

hasPath
Needs ReviewPublic

Authored by nlewycky on Jun 17 2013, 4:27 PM.

Details

Reviewers
chandlerc
Summary

Reimplement hasPath and put it in new CFG.h with the non-transforming parts of BasicBlockUtils.h

Diff Detail

Event Timeline

nlewycky updated this revision to Unknown Object (????).Jun 25 2013, 10:25 PM
chandlerc accepted this revision.Jul 24 2013, 5:55 PM

Reviewed it pretty thoroughly now from the API side and the core analysis logic side. Sorry for the nit picks, just commented as stuff caught my eye. The substantive comments are there as well. Anyways, detailed comments inline.

One set of test cases I'd like to see are cases where the tricks to avoid successor walks allow us to scale up better. IE, lots of tiny blocks that we skip w/ loop info (or maybe domtree).

The comments are a mixture of "please fix this" and questions or ideas for future stuff that I think would be good to do. Once the first group are addressed, I'm happy for you to commit whenever and we can continue the discussion here or in whatever forum works best. I'm not worried about seeing the fixes for the things that are obvious, and the things that aren't obvious seem likely to end up in their own separate patch anyways. So, with changes requested, LGTM.

include/llvm/Analysis/CFG.h
36

Want to reformat the code you're moving in this patch? Your call, I know this is a move.

52

I think it would be useful to give some guidance about the performance (big-O complexity based) that users should expect to help guide callers.

I would also add a brief one-line comment.

53

Would it be useful to include a convenience overload that works in terms of BBs?

Also, why not references to instructions? Can these usefully be null?

lib/Analysis/CFG.cpp
117–126

Not for this change, but I would like to see this added to LoopInfo's interface so others can find it rather than re-inventing it.

128–134

This also seems useful in LoopInfo. I would also potentially phrase it there in a more general form as 'loopContains(...)' which accepts 1, 2, or maybe more basic block (or instruction) arguments... But maybe this is the only case that comes up.

136–138

Don't duplicate the doxygen comment...

145–148

I would hoist this into a static helper function which can then carry this comment.

151–159

I think I would rewrite this whole thing as this to make it a bit more clear what's going on... Not sure how you feel about it though.

// We can't handle loops. As a consequence, we can only reason about the entry block
// without loop info.
if ((LI && LI->getLoopFor(BB) != 0) ||
    (!LI && BB != &BB->getParent()->getEntryBlock())
  return true;
161–163

mem2reg keeps a cache of instruction indices within a block to make repeated queries for the same basic block fast -- do you envision this being useful for callers of this API?

172

Comment why the limit is 32?

Make this a constant?

Make this a command line flag for debugging?

173–174

I much prefer 'Visited' to 'EverQueued'.

I also find it more conventional and easier to read 'Worklist' as a single word.

179–182

Do this before setting up the worklist. It makes more sense with the other special cases. Also, s/NULL/0/

193

Comment clearly that this is the conservative exit from the loop in the case where we don't know anything.

Also, I would put the return on its own line for consistency.

200

Does this have append semantics? If not, give it append semantics?

Then you can append onto your worklist and do the equivalent of std::remove to skip the visited blocks.

If not, at least hoist this vector out of the loop and use clear to reset it. I suspect it can also benefit from a smaller base size than '32'.

205–211

Could we do a similar trick with the domtree as the loopinfo?

Specifically, could we immediately sink to the leaves of the blocks domtree? That would allow us to skip over arbitrarily long chains of basic blocks rather than walking each one.

Clearly, adding this could go in a follow-up patch.

213

Comment that the reason we say 'false' here is that we have exhausted the possible paths, and thus know that it is in fact unreachable.

Thanks for the review! I'm going to submit this shortly, but I'll be happy to make further changes in followup patches.

include/llvm/Analysis/CFG.h
36

Done, clang-format'd.

52

Great idea, I've written a chunk about the cost. I'd rather have something more like the complexity guarantees on something like the C++ standard, but ended up with a description of the algorithm. It'll do.

I tried and failed to write a \brief within 80-columns.

53

It's uncommon to use references to IR in llvm. You're right that they can't be null, but I have an irrational dislike of this change. Sorry.

lib/Analysis/CFG.cpp
117–126

Agreed.

128–134

This code is unusual in that we always want to look at the outermost loop, while most users of Loop do not. We might want to move this to LoopInfo, but I would need to think hard about that.

136–138

Done.

151–159

Hm, your comment made me realize that this code is suboptimal in the case where LI is NULL.

It's not exactly right that we can't handle loops. Rather, if we're inside a loop then it's possible to reach any instruction in the block from any other instruction in the block just by going around the backedge. Thus the answer for loops is a truthful and correct true, not merely a conservative "true". I've updated the comments.

However, in the case where LI is null, we shouldn't bail out and return true here. Instead we should go into the per-block scanning. It may be that this block has no successors for instance, and we can prove that we don't reach BB. I'll save that for a future patch, the fix is not as simple as my first attempt.

161–163

I don't, I expect that at least one side (From or To) will be varying in parent BB with each call. I do expect to reuse the same To many times, for instance.

172

Comment why the limit is 32?

Done.

Make this a constant?

CFG.cpp:205:12: error: decrement of read-only variable ‘Limit’

Make this a command line flag for debugging?

Or make it an argument to the caller? I'll leave it for now as it's easy to change if we want to do either of these things.

173–174

I much prefer 'Visited' to 'EverQueued'.

Okay, I've switched the style to use a Visited+continue at the top.

I also find it more conventional and easier to read 'Worklist' as a single word.

Yep. Done.

179–182

Done.

193

Done.

200

It does have append semantics. Since switching to 'visited' form, I can remove Exits and the need for filtering the Worklist entirely (we just filter at the top of the loop).

205–211

I don't think so. Given a partial domtree with nodes J K and L and edges J->K K->L, we can't sink straight from J to L. There's no guarantee that K doesn't have a successor we can ignore (it could have an edge to A which in turn dominates J).

That doesn't mean we couldn't make some use of domtree, but what you're asking for is a dominance frontier, and we would end up implementing the iterated dominance frontier algorithm in here, at which point it's more sensible to tell callers that they should pass in a loopinfo. This is exactly what loopinfo gives us.

213

Done!

just FYI follow-up...

include/llvm/Analysis/CFG.h
52

You don't have to fit brief comments in 80-columns.

53

You replied to the second of my comments but not the first. ;] The first was the more important. Also, if your dislike is irrational, that says to me you should perhaps make the change.

lib/Analysis/CFG.cpp
145–148

?

Looks like patch was not committed.

This revision now requires review to proceed.Oct 5 2016, 1:25 PM