This is an archive of the discontinued LLVM Phabricator instance.

[PM] Make the the new pass manageg support fully generic extra arguments to run methods, both for transform passes and analysis passes.
ClosedPublic

Authored by chandlerc on Jun 17 2016, 12:56 AM.

Details

Summary

This also allows the analysis manager to use a different set of extra
arguments from the pass manager where useful. Consider passes over
analysis produced units of IR like SCCs of the call graph or loops.
Passes of this nature will often want to refer to the analysis result
that was used to compute their IR units (the call graph or LoopInfo).
And for transformations, they may want to communicate special update
information to the outer pass manager. With this change, it becomes
possible to have a run method for a loop pass that looks more like:

PreservedAnalyses run(Loop &L, AnalysisManager<Loop, LoopInfo> &AM,
                      LoopInfo &LI, LoopUpdateRecord &UR);

And to query the analysis manager like:

AM.getResult<MyLoopAnalysis>(L, LI);

This makes accessing the known-available analyses convenient and clear,
and it makes passing customized data structures around easy.

My initial use case is going to be in updating the pass manager layers
when the analysis units of IR change. But there are more use cases here
such as having a layer that lets inner passes signal whether certain
additional passes should be run because of particular simplifications
made. Two desires for this have come up in the past: triggering
additional optimization after successfully unrolling loops, and
triggering additional inlining after collapsing indirect calls to direct
calls.

Despite adding this layer of generic extensibility, the *only* change to
existing, simple usage are for places where we forward declare the
AnalysisManager template. We really shouldn't be doing this because of
the fragility exposed here, but currently it makes coping with the
legacy PM code easier.

My next patch will leverage this functionality to extend the CGSCC pass
capabilities to support updating after CG mutations occur.

Diff Detail

Repository
rL LLVM

Event Timeline

chandlerc updated this revision to Diff 61070.Jun 17 2016, 12:56 AM
chandlerc retitled this revision from to [PM] Make the the new pass manageg support fully generic extra arguments to run methods, both for transform passes and analysis passes..
chandlerc updated this object.
chandlerc added a subscriber: llvm-commits.
silvas added a subscriber: silvas.Jun 17 2016, 1:23 AM

I was initially a bit concerned with the variadics (instead it may be simpler to just group the extra stuff into the IRUnitT when necessary), but this doesn't seem too bad.

include/llvm/IR/PassManager.h
965 ↗(On Diff #61070)

Why do you need a partial specialization here? Shouldn't it just work if you propagate the variadics into the run method too? If not, a comment would be appreciated.

unittests/IR/PassManagerTest.cpp
382 ↗(On Diff #61070)

Nit: The capture here seems to be a leftover.

chandlerc marked 2 inline comments as done.Jun 23 2016, 4:10 PM
chandlerc added inline comments.
include/llvm/IR/PassManager.h
965 ↗(On Diff #61070)

Because if there are extra arguments to the run method, there might be extra arguments to the getResult method, and we can't guess effectively how to map from one set of extra arguments to the other. Instead of trying, we just only provide the specialization for where there are no extra arguments at either level. CGSCC stuff has to provide its own specialization to handle the correct mapping from run-level extra arguments to getResult-level extra arguments.

(Comment updated)

chandlerc updated this revision to Diff 61740.Jun 23 2016, 4:13 PM
chandlerc marked an inline comment as done.

Update with code review feedback and rebase.

chandlerc updated this revision to Diff 66629.Aug 3 2016, 2:25 AM

Rebase and ping.

How do you plan to marshal the variadic arguments for analyses with a unified analysis manager for all IRUnit's (w/ dependency tracking)? That seems annoying.

I should have some code for the unified analysis manager up today hopefully.

I hear your argument (IIRC we discussed this at a social) about back pointers being somewhat annoying, but the ability to use just a void* to represent the information passed to an analysis makes it much easier to have a unified analysis manager.

Note that this issue doesn't apply to transformations since they don't participate in the analysis management.

How do you plan to marshal the variadic arguments for analyses with a unified analysis manager for all IRUnit's (w/ dependency tracking)? That seems annoying.

You can see how I plan to use this with analysis managers in the next patch where I customize the CGSCC pass manager to handle mapping the extra arguments.

While it is unfortunate that we cannot use fully generic code in that case, it didn't seem like a significant burden and I suspect in some cases will be a necessary customization anyways in order to get the desired behavior.

I should have some code for the unified analysis manager up today hopefully.

Ok, but I don't want to hold up progress waiting on a different design. In my opinion, it doesn't really make sense to pursue both of these directions concurrently in tree because of how much overlap they have and the fact that they seem likely to hold each other up.

I understand that you would prefer the design you are pursuing, but unless you have really serious concerns with *this* design that you can express, or there is widespread consensus that we should stop pursuing this design, I'd like to make progress.

I hear your argument (IIRC we discussed this at a social) about back pointers being somewhat annoying, but the ability to use just a void* to represent the information passed to an analysis makes it much easier to have a unified analysis manager.

I don't think I understand the connection you see between up pointers and using a 'void*' to represent the information passed to an analysis. Can you re-explain this? Sorry if it just isn't clicking for me....

That said, in general I would like to not sacrifice type safety because of concerns around mapping arguments from one interface to another though.

Ok, but I don't want to hold up progress waiting on a different design. In my opinion, it doesn't really make sense to pursue both of these directions concurrently in tree because of how much overlap they have and the fact that they seem likely to hold each other up.

The current design of the analysis manager has a fatal bug (no dependency tracking). I'm fixing it. The bug is so fatal that the "new PM" cannot be run on any realistic workload without segfaulting or use-after-free. So the entirety of the "new PM" will be nothing but a toy (essentially dead code) until this is fixed.

Please bear with me as I fix it.

I understand that you would prefer the design you are pursuing, but unless you have really serious concerns with *this* design that you can express, or there is widespread consensus that we should stop pursuing this design, I'd like to make progress.

I will make that proposal once we have an analysis manager that has basic correctness (which should hopefully be soon).

I hear your argument (IIRC we discussed this at a social) about back pointers being somewhat annoying, but the ability to use just a void* to represent the information passed to an analysis makes it much easier to have a unified analysis manager.

I don't think I understand the connection you see between up pointers and using a 'void*' to represent the information passed to an analysis. Can you re-explain this? Sorry if it just isn't clicking for me....

That said, in general I would like to not sacrifice type safety because of concerns around mapping arguments from one interface to another though.

The issue is that for a unified analysis manager, AnalysisPassConcept is not templated (on IRUnitT and couldn't be on the ExtraArgTs). Therefore, we need to pass a type-erased object through its run method. Currently, the type-erased IRUnit can be passed as a void*, and then the AnalysisPassModel (which *is* templated on IRUnitT) just casts it back since it knows the right type.
At least with the current registration stuff, all we need right now for type-safety is tracking which IRUnit it is (and there are 4 discrete values which is easy to track).

Or to put it another way, the ideas you are running with in this patch is very intimately tied to having the analysis manager templated on the signature of the associated run method for analyses it manages. A unified analysis manager (which seems like it was the agreed upon design for solving dependency tracking) must type-erase the information you have baked into the template arguments of AnalysisPassConcept here.
At least with the way that the registration stuff works now, you would need to find a way to type-erase the exact signature of the run method in order to get type-safety.

sanjoy accepted this revision.Aug 19 2016, 1:17 AM
sanjoy added a reviewer: sanjoy.
sanjoy added a subscriber: sanjoy.

lgtm with some minor questions / comments inline.

include/llvm/IR/PassManager.h
970 ↗(On Diff #66629)

s/arguements/arguments/

975 ↗(On Diff #66629)

Have you considered making this building block instead be:

template <typename AnalysisK, typename IRUnitT, typename... ExtraArgTs>
struct RequireAnalysisPass<AnalysisK<IRUnitT, ExtraArgTs>, IRUnitT, AnalysisManager<IRUnitT, ExtraArgTs>> {
  PreservedAnalyses run(IRUnitT &Arg, AnalysisManager<IRUnitT> &AM, ExtraArgTs... &&args) {
    (void)AM.template getResult<AnalysisT>(Arg, std::forward(args));

    return PreservedAnalyses::all();
  }
};

and use cases that want something other than std::forward can specialize this differently?

unittests/IR/PassManagerTest.cpp
342 ↗(On Diff #66629)

Minor: just make this a struct?

This revision is now accepted and ready to land.Aug 19 2016, 1:17 AM
chandlerc marked an inline comment as done.Aug 19 2016, 2:51 AM

Thanks, submitting. Happy to follow-up on any of these issues (or other issues) in subsequent commits!

include/llvm/IR/PassManager.h
975 ↗(On Diff #66629)

I looked at this and it's kind of awkward to do....

If you do as you suggest, I'm worried using exactly one extra argument will become ambiguous with variants which specify a particular AnalysisManagerT and no extra arguments.

It essentially makes the specializations harder to control. And I have no use case today.

So for now, I think I prefer keeping this boring. If you see a reliable way to do what you suggest, please let me know and I'm happy to incorporate it, but so far I don't see one.

unittests/IR/PassManagerTest.cpp
342 ↗(On Diff #66629)

I've been fairly consistently keeping the PassID static member private, which is why this is a class. I can reverse that if you feel strongly in a follow-up commit, but this isn't the only place where this happens.

This revision was automatically updated to reflect the committed changes.