This is an archive of the discontinued LLVM Phabricator instance.

Update call graph after devirtualizing returned value
AbandonedPublic

Authored by pete on Jun 3 2014, 5:17 PM.

Details

Reviewers
None
Summary

This patch is part of a series which ultimately allows us to splice the last use of a callee instead of clone it. The other patches are ready but i'd like to get this done first.

This patch updates the call graph whenever the inliner devirtualizes a call based on a returned value.

That is, if we have the following, then after @f1 is inlined, the call to % funcall1_ actually points to @f2. The inliner will currently proceed with inlining @f2 but with out of date call graph information.

define i32 @test1() {

%funcall1_ = call fastcc i32 ()* ()* @f1()
%executecommandptr1_ = call i32 %funcall1_()
ret i32 %executecommandptr1_

}

define internal fastcc i32 ()* @f1() nounwind readnone {

ret i32 ()* @f2

}

define internal i32 @f2() nounwind readnone {

ret i32 1

}

Diff Detail

Event Timeline

pete updated this revision to Diff 10071.Jun 3 2014, 5:17 PM
pete retitled this revision from to Update call graph after devirtualizing returned value.
pete updated this object.
pete edited the test plan for this revision. (Show Details)
pete added a reviewer: chandlerc.
pete added a subscriber: Unknown Object (MLST).
chandlerc added inline comments.Jun 3 2014, 5:47 PM
lib/Transforms/Utils/InlineFunction.cpp
521–522

You can just write:

for (Use *U : TheCall->uses()) {
524

I don't understand why you're doing it this way.

I would just do the RAUW in the caller of this like normal, and then walk the uses after replacing them.

526–527

So, this misses cases where the function pointer is washed through a bitcast to i8* and back to a function pointer.

If you do the RAUW first, I think you can use instsimplify and look through casts to handle all of these cases more generally. You probably will also need to walk the uses recursively to find all the transitive users through bitcasts.

529–531

Why not just pass this in?

533–534

This is a linear operation on the caller, which makes this whole thing go quadratic. Have you seen any compile time performance hits?

The entire design of the call graph makes doing this really annoying. I can't wait until we can switch to LCG....

pete added inline comments.Jun 3 2014, 7:04 PM
lib/Transforms/Utils/InlineFunction.cpp
521–522

Will do. At first I thought I was invalidating the iterator but actually I'm not in this case.

524

If we end up returning a Function* say, then that means walking all the users of a Function* then identifying those which are instructions in the caller. I thought that would be too slow. My current implementation is O(num return value uses).

526–527

You're right. Based on how the inliner would process a call with a bit cast, I think my current code will work, but it'll be much more efficient to do what you're suggesting here.

529–531

Will do. This saved us nothing by avoiding passing it in.

533–534

This is stolen from the SCC pass updater which runs after inlining to recalculate the call graph. Doing it here should be performance neutral as we save the updater doing it instead.

Honestly I haven't measured the compile time impact yet. I'll get to that once we converge on a good patch.

pete updated this revision to Diff 10111.Jun 4 2014, 3:41 PM

Attached updated patch which addresses many of the points raised.

The main changes are to devirtualizedCallUsers which now walks uses looking for calls to devirtualize and through bit casts. It simplifies bitcasts and updates the call graph for any calls which ultimately (even through bit casts) end up calling a Function* directly. It now calls RAUW directly after it has noted down the interesting bit casts and calls.

I tried a few variations of this code and ultimately doing it in a few loops was cleanest. The problem with a single large loop was determining whether a call we were visiting was devirtualized or not which isn't entirely clear once going through bit casts.

Also added 3 more tests which cover bit casting the call result value, the returned value, or both. In each case it verifies that the appropriate simplifications were performed.

chandlerc resigned from this revision.Mar 29 2015, 12:31 PM
chandlerc removed a reviewer: chandlerc.

Unsure if this patch is still going anywhere and so resigning. Add me back and rebase if you want me to look at it.

pete abandoned this revision.Mar 30 2015, 9:53 AM

Agreed that this has gone stale. Closing.