This is an archive of the discontinued LLVM Phabricator instance.

[ThinLTO] Add FunctionAttr NoRecurse and ReadAttr propagation to ThinLTO
AbandonedPublic

Authored by ncharlie on Jul 19 2017, 10:09 AM.

Details

Reviewers
davide
tejohnson
Summary

This patch addresses part of Bug 33648. It adds new information to the summary and implements part of the FunctionAttrs pass (propagating read attrs and norecurse attrs). The other part of the pass is not implement at the moment, since it requires argument information which currently is not included in the summary.

Diff Detail

Event Timeline

ncharlie created this revision.Jul 19 2017, 10:09 AM
ncharlie added inline comments.Jul 19 2017, 1:57 PM
lib/Transforms/IPO/FunctionImport.cpp
551

Not sure if this is the best place for this function.

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
409

Not sure if this is the best place for this function.

ncharlie added inline comments.Jul 20 2017, 7:31 AM
lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
413

I'm don't think this entirely correct. The reason I did it this way was so I could reuse the computeFunctionBodyMemoryAccess from the original FunctionAttrs pass. I think I'll need to modify that function a bit to work with the Index so it can access information about functions external to the current module.

ncharlie updated this revision to Diff 107560.Jul 20 2017, 11:08 AM
  • added memory access info to index callgraph edges
  • renamed functions
ncharlie marked an inline comment as done.Jul 20 2017, 11:09 AM

refactored code and removed unnecessary SCCNodes

Just a note: this isn't fully completed yet. I still have to add tests and do some verification, but I wanted to make it's on the right track.

Thanks, that's a very good start! Few comments inline, I didn't understand everything.

include/llvm/IR/ModuleSummaryIndex.h
60

I think we may get to the point with this structure where documenting fields here would be nice.

294

Doc.

366

Doc (including return value).

I'd suggest naming it: `updateCalleeMemAccessKind()`

include/llvm/Transforms/IPO/FunctionAttrs.h
36

DenseMap instead of std::map?

include/llvm/Transforms/IPO/FunctionImport.h
106

Doc (simple).

129

Doc.

lib/Transforms/IPO/FunctionImport.cpp
424

Here I'd expect a better description of "how" you're gonna achieve the API contract, i.e. a high level view about what's involved.

425

naming could help understand. Something like `all_of_calllees` or something like that (may still need a comment.

427
std::function``` is heavy, use ```llvm::function_ref``` here.
430

Are we sure there can't be an alias summary here?

440

early continue:

FunctionSummary *F = dyn_cast<FunctionSummary>(S.get());
if (!F) continue;
...
443

Doc.

445

Not sure why the second condition is needed?

551

Agree, but coherent with the one right below...

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
443

Why do we need to mark the edges?

ncharlie added inline comments.Jul 21 2017, 6:48 AM
lib/Transforms/IPO/FunctionImport.cpp
445

I copied that out of the original FunctionAttrs pass to prevent the function from being marked NoRecurse if it calls itself (http://llvm-cs.pcc.me.uk/lib/Transforms/IPO/FunctionAttrs.cpp#1068).

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
443

I was planning on using that to propagate read attrs up to the caller. For instance:

void x(int *k) { // can't mark readonly since k could be global
  *k++;
}

void j() {
  int i = 5;
  x(&i); // since i is local memory, we can mark j as readnone
}

I'm currently working on implementing this - when I finish I'll update the patch.

tejohnson edited edge metadata.Jul 21 2017, 6:55 AM

Just a note: this isn't fully completed yet. I still have to add tests and do some verification, but I wanted to make it's on the right track.

It looks like you are on the right track from the standpoint of dividing it up into pieces implemented during the compile step (building the index), the thin link (propagating), the backend (applying). I have a few comments after a quick initial perusal. But note when you have something ready for a full review, you should create a new patch that adds llvm-commits as a subscriber.

lib/Transforms/IPO/FunctionAttrs.cpp
94

These used to be continues, I think the change to an early return will mean that not all call site args are analyzed?

lib/Transforms/IPO/FunctionImport.cpp
443

CalleeInfo unused.

But in any case, I don't think the checking here is sufficient as it will only detect self-recursion, not indirect recursion (e.g. A->B->A). For that you need to build the SCC (strongly connected components) on the call graph in the index. See for example addNoRecurseAttrs where it first checks if the SCC has more than one function (in which case there is automatically indirect recursion).

I wonder if the SCC builder in llvm can be made to work for the index call graph? See SCCIterator.h. You'd need to provide GraphTraits for the index graph.

Additionally, the memory access info needs to be propagated during the thin link. See how FunctionAttrs propagates them across the SCC. See addReadAttrs() for example.

559

As mentioned above, this needs to be computed on the SCC.

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
413

This is called from the compile step, so there is no information in the Index for external functions. Here you just want to compute the per function attribute info to put into the index for the global analysis to use during the thin link.

494

Can this just be moved into the ModuleSummaryIndex builder (see ModuleSummaryAnalysis.cpp)? We should do all the building of the index there.

ncharlie updated this revision to Diff 107668.Jul 21 2017, 6:56 AM

Updated as per comments.

Thank you for the feedback and corrections, @mehdi_amini and @tejohnson. I wasn't understanding the purpose of SCCNodes when I initially wrote the patch - thanks for clarifying :)

I'm going to work on GraphTraits for the ModuleSummaryIndex so SCCNodes can be used during the propagation step. After doing that and some cleanup I'll resubmit the patch to llvm-commits, unless anyone has any major modifications I should make to this patch.

lib/Transforms/IPO/FunctionAttrs.cpp
94

It's kinda messed up by the diff, I moved callsite analysis to its own function (analyseCallSite). Line 148 shows where it's called.

lib/Transforms/IPO/FunctionImport.cpp
443

But in any case, I don't think the checking here is sufficient as it will only detect self-recursion, not indirect recursion (e.g. A->B->A).

Ah, good point. Now I see what the SCCNodes are for.

I wonder if the SCC builder in llvm can be made to work for the index call graph? See SCCIterator.h. You'd need to provide GraphTraits for the index graph.

I started looking into this, and I think it'll be possible with a few more iterator types.

mehdi_amini added inline comments.Jul 21 2017, 9:20 PM
lib/Transforms/IPO/FunctionImport.cpp
445

This comment does not display in the right place for me right now, to clarify I'm wondering about this:

if (!S->fflags().NoRecurse ||
    S->getOriginalName() == F->getOriginalName())

So the second check here is intended to check for self-recursion. Are we recording self-recursion in the summaries?
Can we check GUID equality instead of string comparison?
Also we need a test for this exact condition, i.e. a test that would fail with if (!S->fflags().NoRecurse) alone.

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
443

I think it is complex enough that doing it in two patches would be easier to review and assert correctness, catch edge cases, and make sure we have the right level of test coverage.
The first patch could be just doing the "simple case", and then you can extend it with the most advanced one. For the simple case you shouldn't need to touch edges I believe.

Also if possible, I'd even break it so that you first implement propagating only readnone, forget about norecurse and other stuff, and you don't need SCC. Then you can add more stuff. Again we'll have more targeted testing and we are less likely to miss anything in review (and if we need to bisect a failure, it'll be easier to pinpoint the faulty logic as well).

ncharlie added inline comments.Jul 22 2017, 7:29 AM
lib/Transforms/IPO/FunctionImport.cpp
445

Are we recording self-recursion in the summaries?

I think so. I'll double check, but I think this is a redundant check (in which case I'll remove it).

lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
443

Sounds good - I was thinking about splitting it into multiple patches, and I agree with that level of granularity (i.e. a patch for propagating readnone, a patch for readnone propagated across call edges, and a patch for no recurse).

davide edited edge metadata.Jul 24 2017, 11:41 AM

This is a decent start, some comments inline. Thanks!

include/llvm/IR/ModuleSummaryIndex.h
306

Comment?

370–372

Do you need the -> bool ?

lib/Transforms/IPO/FunctionAttrs.cpp
89–94

range for?

121–123

I find this a little harder to read, maybe you can use an explicit continue instead of LLVM_FALLTHROUGH ?

993

spurious new whiteline.

ncharlie abandoned this revision.Jul 31 2017, 8:25 AM

Patch is being split into multiple dependent patches.