This is an archive of the discontinued LLVM Phabricator instance.

[llvm] Add interface to drive inlining decision using ML model
ClosedPublic

Authored by mtrofin on Apr 28 2020, 2:06 PM.

Details

Summary

This patch adds the analysis pass and the hook-ups into the inliner. The
implementation of the analysis pass requires optional dependencies be
present, and will be introduced subsequently.

RFC: http://lists.llvm.org/pipermail/llvm-dev/2020-April/140763.html

Diff Detail

Event Timeline

mtrofin created this revision.Apr 28 2020, 2:06 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 28 2020, 2:06 PM
mtrofin updated this revision to Diff 260770.Apr 28 2020, 2:19 PM

added comments

mtrofin updated this revision to Diff 260773.Apr 28 2020, 2:34 PM

Removed unrelated changes

Harbormaster failed remote builds in B55043: Diff 260773!
Harbormaster failed remote builds in B55041: Diff 260770!
davidxl added inline comments.Apr 29 2020, 9:24 AM
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
28 ↗(On Diff #260773)

No other interfaces in the class?

33 ↗(On Diff #260773)

two bools are confusing. Perhaps split them? SetWasDeleted, and SetWasInlined?

Also document this interface.

42 ↗(On Diff #260773)

desided --> decided

50 ↗(On Diff #260773)

nit: shouldInline --> getInlineAdvise?

68 ↗(On Diff #260773)

This comments belongs somewhere else -- perhaps in implementation ?

mtrofin updated this revision to Diff 260947.Apr 29 2020, 9:52 AM
mtrofin marked 8 inline comments as done.

feedback

mtrofin marked 2 inline comments as not done.Apr 29 2020, 9:52 AM
mtrofin added inline comments.
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
28 ↗(On Diff #260773)

Not sure I follow. Maybe I should place InliningAdvisor first in the file, followed by PendingInliningRecord (forward - declaring the latter - the current order is just to avoid that fwd decl)?

33 ↗(On Diff #260773)

The idea was to atomically communicate the conclusion of the inlining operation.

I think the liability of setWasDeleted and setWasInlined would be that:

  • we'd need a 'finish()' method to say we're done, which adds complexity and more statefulness to the design (harder to track); or
  • just rely on the dtor to do that, but that doesn't address the statefulness
  • need to rely on user to remember to call both setWas{Deleted|Inlined}

I realize the current design requires a reader look up and see what the 2 params meant. I think that's a 'lesser evil' than those outlined above.

How about either:

  • I decorate the call sites for recordInlining with comments indicating what the parameters mean, or
  • add 3 public APIs, as follows (new API -> current API)

recordInlining() -> recordInlining(/*CalleeWasDeleted*/false, /*SiteWasInlined*/ true)
recordInliningWithCalleeDeleted() -> recordInlining(/*CalleeWasDeleted*/true, /*SiteWasInlined*/ true)
recordUnsuccessfulInlining() -> recordInlining(/*CalleeWasDeleted*/false, /*SiteWasInlined*/ false)

wdyt?

42 ↗(On Diff #260773)

thanks - I meant 'desired' :)

68 ↗(On Diff #260773)

Reworded.

mtrofin marked an inline comment as done and an inline comment as not done.Apr 29 2020, 9:59 AM
mtrofin added inline comments.
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
50 ↗(On Diff #260773)

sure - I'll leave this open until the review gets closer to the end, since it's easy to refactor, and I'd just want to do it once.

davidxl added inline comments.Apr 29 2020, 10:20 AM
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
28 ↗(On Diff #260773)

what I meant is that this class defined here has no other accessor interfaces (other than one setter).

33 ↗(On Diff #260773)

Making recordInlining private and add wrappers to them sounds good.

mtrofin updated this revision to Diff 261060.Apr 29 2020, 3:31 PM
mtrofin marked 3 inline comments as done.

feedback. Simplified interaction between inliner pass, removed 1 todo

mtrofin added inline comments.Apr 29 2020, 4:01 PM
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
28 ↗(On Diff #260773)

Ah, yes. That's intended - well, 3 setters, with the recent changes.

davidxl added inline comments.Apr 29 2020, 4:26 PM
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
23 ↗(On Diff #261060)

add documentation on MLMode.

84 ↗(On Diff #261060)

Perhaps rename 'AlternativeRecommendation' to 'MLDecision'? or 'MLRecommendation'?

llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
33 ↗(On Diff #261060)

Can this happen, given the option parser filters out other values?

llvm/lib/Passes/PassBuilder.cpp
220

Invalid mode --> Null mode?

llvm/lib/Transforms/IPO/Inliner.cpp
704

why not use it to handle Entry too? If null, does nothing.

mtrofin updated this revision to Diff 261114.Apr 29 2020, 7:45 PM
mtrofin marked 8 inline comments as done.

Feedback

mtrofin added inline comments.Apr 29 2020, 7:52 PM
llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
33 ↗(On Diff #261060)

This happens if we pass Dev (for example) and neither LLVM_HAVE_TF_{API|AOT} are defined. It's what the test tests, too.

llvm/lib/Passes/PassBuilder.cpp
220

How about 'NoML' or 'None'?

This is pretty cool. I've got one high level question and then a few minor things in the patch.

High level: Would it be better to split this out even more rather than the if/elses in the Inliner? i.e. rather than conditionalizing it just have N paths through. It may mean a little bit more duplicated or factored code, but would probably be a little easier to read through.

Thoughts?

-eric

llvm/include/llvm/Analysis/ML/InliningAdvisor.h
33 ↗(On Diff #261114)

Might be nice to just spell them out?

46 ↗(On Diff #261114)

Is there any way we could use an enum(s) instead for these calls rather than boolean arguments?

llvm/lib/Passes/PassBuilder.cpp
735

Extra braces.

763

Can we get a better description of what the cleanup pass is supposed to do? We don't typically have such things and it seems worth calling out in a bit more detail.

davidxl added inline comments.Apr 30 2020, 9:16 AM
llvm/lib/Passes/PassBuilder.cpp
220

NoML or None or just No sound fine.

llvm/lib/Transforms/IPO/Inliner.cpp
844–845

This should be better computed under

if (Advisor) {

  TrivialDecision = ...
  if (noinline)
     continue;
   Mandatory = ...
}
llvm/test/Transforms/Inline/inlining-advisor-default.ll
10

I wonder if it is useful to have a mock mode for testing purpose where the ML code is barebone but not fully statically compiled out.

This is pretty cool. I've got one high level question and then a few minor things in the patch.

High level: Would it be better to split this out even more rather than the if/elses in the Inliner? i.e. rather than conditionalizing it just have N paths through. It may mean a little bit more duplicated or factored code, but would probably be a little easier to read through.

Thoughts?

-eric

I agree - I'll send first some NFC patches cleaning up a bit the current code; then, refactor along the lines you suggested. I think there'll end up being very little, if any, duplication, too!

mtrofin marked 5 inline comments as done.Apr 30 2020, 12:57 PM
mtrofin added inline comments.
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
33 ↗(On Diff #261114)

I.e. 'Release' and 'Development'? I like that. (will send and updated patch once Inliner.cpp refactoring is done, so leaving this and others marked as not 'done')

46 ↗(On Diff #261114)

You mean instead of the 3 members that call into this protected member?

so we have it fleshed out:

enum class InliningOutcome {
  Failed,
  Succeeded,
  SucceededWithCalleeRemoval
}

and then we only have the one virtual, and no protected:

virtual void recordInlining(InliningOutcome Outcome)

Does that capture it?

I'm fine with whatever we all feel is the more usable API. One thing to consider - looking at how the APIs are used, I'd actually prefer 2 methods: 1 method for "it failed", and 1 for "it succeeded", with a bool saying whether the callee will be removed or not (see Inliner.cpp:1213 and below, in this patch)

wdyt?

llvm/test/Transforms/Inline/inlining-advisor-default.ll
10

If we only use that for test, then the 'dev' mode where we just capture logs does exactly that - and I plan on getting a build bot setup for this; and it has a test, of course (and doesn't add complexity)

davidxl added inline comments.Apr 30 2020, 1:43 PM
llvm/test/Transforms/Inline/inlining-advisor-default.ll
10

it might be better to exercise some tests by default (without relying on bot). When there is a breakage, it is also easier for folks to reproduce.

dblaikie added inline comments.May 2 2020, 4:27 PM
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
30–31 ↗(On Diff #260773)

You can leave these off if you like - they're implied by the existence of a user-declared destructor. (that'll automatically delete/remove the copy/move operations)

36–37 ↗(On Diff #260773)

This is the default (well, it'd be public by default, but it can't be called directly because of the presence of a pure virtual function in the class) so you could omit it.

llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
25 ↗(On Diff #260773)

Remove dead code after an unreachable here.

28–35 ↗(On Diff #260773)

I'd probably picture this not using the #ifdef stuff here - InliningAdvisor.h has to be unconditionally compiled anyway (since it provides the IniliningAdvisor base class)... oh - but you weren't planning on unconditionally compiling a .cpp file that implements it? That would be good to avoid - it'd be unfortunate to have a header we have to include with silent contracts about which parts of the header you can use (& we shouldn't be in a position where certain member functions has to be defined in a header or must be defined in the .cc file or there will be subtle problems - that'd be surprising/confusing for maintenance). I'd probably go further and say maybe the whole header should live outside the ML directory? And either it'd provide the InliningAdvisor::create function, and use #ifdefs in its own implementation (seems fair - it's already going to need to test TF_API and TF_AOT to decide which kind of implementations it has available) so it can be called unconditionally - and just returns nullptr if neither API is available.

That could be implemented in llvm/Analysis (non-ML), InliningAdvisorFactory, just a header with one function declared in it, and a single source file implementing it that's just "ifdef TF_API return new TFAPIThing #elseif TF_AOT ... etc")

llvm/lib/Transforms/IPO/Inliner.cpp
704–714

I'm surprised we don't have a scope-guard like device in LLVM already, but one other way to address this (perhaps that's what everyone else has done in LLVM so far) would be to pull the body of the function out into a separate function, so you can easily ensure the end operation is done.

Otherwise, if you prefer to keep it this way it seems like a bit of overkill to make it a class - probably a struct, used {} init rather than a ctor, etc to keep it simple, given it's only used once/immediately.

mtrofin marked 2 inline comments as done.May 2 2020, 5:24 PM
mtrofin added inline comments.
llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
28–35 ↗(On Diff #260773)

I don't follow. The ifdef is in the InliningAdvisorAnalysis.cpp, which is unconditionally compiled.

dblaikie marked an inline comment as done.May 2 2020, 7:49 PM
dblaikie added inline comments.
llvm/include/llvm/Analysis/ML/InliningAdvisor.h
30–31 ↗(On Diff #260773)

Yeah, looks like this comment ended up out-of-place, was writing it based on a previous version of the code. (the email had the right quoted text, FWIW)

& in any case, my comment was incorrect - the user-declared dtor doesn't disable copy/move, so makes sense to leave them.

36–37 ↗(On Diff #260773)

This comment was about the protected defaulted default ctor - well, you still need to define it (because of the deleted copy/move ctors) but you could define it as public as much as as protected - either way no one can instantiate this class because it has pure virtual functions. Not a huge deal either way I guess.

llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
25 ↗(On Diff #260773)

(the "return nullptr;" after "llvm_unreachable" is dead - llvm_unreachable is trap/abort/UB-in-optimized builds, the return is meaningless/would be DCE'd anyway, best to remove it)

28–35 ↗(On Diff #260773)

Ah, sorry, that was a bit rambly.

What I mean is, why is the call to InliningAdvisor::create conditionalized? I assume it's because, while the declaration of InliningAdvisor::create is always available in InliningAdvisor.h, its implementation is not (because, I assume, everything in Analysis/ML is conditionally compiled only if TF is available?). I think it's problematic to have a header that only works because certain parts of it must remain in the header & can't be moved to an implementation file (because there is no unconditionally compiled implementation file to move them to).

Hmm, now I'm confused - the header has parts defined in lib/Analysis (like InliningAdvisorAnalysis::* here) and parts defined in lib/Analysis/MC (like InliningAdvisor::create - well, that isn't defined anywhere right now, it seems - but I assume the idea was to implement it in lib/Analysis/MC?)).

I think it might be tidier to have the lib/Analysis/MC entry point be very small - just the InliningAdvisorAnalysis::create - and if the goal is to have everything in lib/Analysis/MC be conditionally compiled using CMake and the presence of TF, then maybe having a header in lib/Analysis that declares (& defines inline, or out-of-line in its own .cpp file in lib/Analysis, either way) and uses macros to define the implementation as either a no-op (because it can't call into lib/Analysis/MC because it doesn't exist) or as the functional implementation that instantiates the desired class in lib/Analysis/MC).

I think having the factory function always be available, but it either is implemented as a no-op (returning a null unique_ptr) when the library isn't available keeps the boundary in a very clear/small part of the code, not amongst any other code (not that InliningAdvisorAnalysis.cpp is especially long by any means).

I wouldn't put any of the #ifdefs in if they're always false when this patch is committed - that's dead/untested code, which is best not to commit (a comment describing what else might go there is OK though).

I think there's some discussion of having a stub implementation for testing? I think that'd be appropriate to go in with this patch - otherwise there's a lot of dead code (not just these #ifdefs, but all the InliningAdvisor results, etc aren't tested because there's never a non-null implementation in this patch). (I'm not sure how that stub would be powered - either a hardcoded general implementation (does something silly like forcibly inline every second function) with DEBUG outputs to indicate how it's being called - or perhaps reading from an external file to dictate what paths to go down... or unit tested, but that's not usually how optimizations are tested (maybe there's a reasonable amount of unit testing for analyses though? I'm not sure - I haven't looked))

mtrofin marked an inline comment as done.May 2 2020, 8:44 PM
mtrofin added inline comments.
llvm/lib/Analysis/InliningAdvisorAnalysis.cpp
28–35 ↗(On Diff #260773)

Initially, I was planning to implement InliningAdvisor::create in lib/Analysis/ML/InliningAdvisor.cpp. To summarize your proposal, also factoring in the stub implementation proposal:

  • declare a "llvm::createInliningAdvisor" in include/Analysis/ML/InliningAdvisor.h, implement it in lib/Analysis/ML/InliningAdvisor.cpp (instead of the static InliningAdvisor::create)
  • in lib/Analysis/InliningAdvisorAnalysis.cpp, include include/Analysis/ML/InliningAdvisor.h conditionally
  • add the conditional include and the conditional call to llvm::createInliningAdvisor in the patch following this one, when we add the ML stuff
  • for the stub implementation, I see 2 options, with all the above staying the same :
    1. there'll be a 4th MLMode, 'Test' or something
        • the implementation of InliningAdvisor will be a no-op here, in InliningAdvisorAnalysis.cpp
        • the case statement will just new-up that no-op directly (i.e. it won't be going through the llvm::createInliningAdvisor when it gets introduced)
        • the noop would be mimic the codepath for 'Development' mode, when we want to learn starting from the current behavior, and parrot back the cost-based result (i.e. whether shouldInline in Inliner.cpp says "yes" or "no"). That still means we don't test the 'Release' code path in Inliner.cpp, which skips calling shouldInline.
      1. no 4th mode for MLMode, instead:
        • we always have an InliningAdvisor, i.e. even without ML in the picture
        • the default InliningAdvisor performs today's shouldInline
        • Inliner.cpp's code gets simplified - no conditional 'if (Advisor)' or anything. All the InlineCost-based reporting happens in the default InliningAdvisor's corresponding PendingInliningRecord implementation.
        • the Development mode behavior of calling today's decision making process is encapsulated in it, and thus tested there

I'd pitch for option 2 - simpler code, I think

What do folks think? (Probably it'd help the discussion if I made the update to the patch)

mtrofin updated this revision to Diff 262283.May 5 2020, 6:59 PM

Simplified Inliner control flow by factoring out the inlining decision from the pass. This also means we exercise the Inliner.cpp control flow in both ML and non-ML cases.

Removed the 'cleanup' pass, and, instead, created a module pass wrapper for the inliner that manages the necessary state internally.

google-llvm-upstream-contributions added inline comments.
llvm/lib/Passes/PassBuilder.cpp
220

Replaced with 'Default', as we always use an InliningAdvisor.

763

Removed the cleanup pass altogether.

llvm/lib/Transforms/IPO/Inliner.cpp
844–845

Simplified control flow. The reasoning around mandatory and trivial case will go in the ML-specific implementation.

llvm/test/Transforms/Inline/inlining-advisor-default.ll
10

Done. We always use an InliningAdvisor. Also added tests side-by-side the inliner tests that were using the new pass manager, to test the ModuleInlinerPassWrapper. So the control flow in the inliner is tested in all cases, and these 'duplicate' cases test the wrapper and the logic getting the advisor from it.

davidxl added inline comments.May 7 2020, 9:21 AM
llvm/include/llvm/Analysis/InliningAdvisor.h
32 ↗(On Diff #262283)

perhaps use compile time instead of runtime

davidxl added inline comments.May 7 2020, 9:21 AM
llvm/include/llvm/Analysis/InliningAdvisor.h
204 ↗(On Diff #262283)

should this refactoring be done seperately?

llvm/lib/Transforms/IPO/Inliner.cpp
699

Put the advisor computation code into its own helper method?

699

OwnedAdvisor --> DefaultAdvisor or NullAdvisor or NopAdvisor?

mtrofin updated this revision to Diff 262753.May 7 2020, 1:53 PM
mtrofin marked 18 inline comments as done.

incorporated feedback

llvm/include/llvm/Analysis/InliningAdvisor.h
32 ↗(On Diff #262283)

reworded, I think it's more clear now.

204 ↗(On Diff #262283)

Yes, if we're OK with this direction, I'll add first the InliningAdvisor.{h|cpp} with just these functions.

llvm/lib/Passes/PassBuilder.cpp
735

This probably got out of sync with the source, or got addressed by the latest patch.

llvm/lib/Transforms/IPO/Inliner.cpp
699

It's not a Null/Nop advisor, it's today's behavior. Also, you can get a "DefaultAdvisor" through the analysis pass. The key difference here is lifetime management: when InlinerPass is used stand-alone as a SCC pass, we make and own the DefaultInliningAdvisor instance.

704

Un-did the entry handling, because we're using the scope_exit API.

704–714

There is a scope-guarding API! Thanks for the pointer. Addressed.

llvm/test/Transforms/Inline/inlining-advisor-default.ll
10

Done, as we always use an InliningAdvisor. All the bots will test is ML-specific implementation.

mtrofin updated this revision to Diff 263205.May 11 2020, 9:50 AM

updated after related patch landed

davidxl added inline comments.May 11 2020, 10:49 AM
llvm/include/llvm/Analysis/InlineAdvisor.h
50

To make the naming more consistent, suggest changing the name to

InlineAdvise or InlineRecord

111

InliningAdviser --> InlineAdviser

121

perhaps shorten it : getAdvice

158

DefaultInliningAdvisor --> DefaultInlineAdvisor

172

->InlineAdviserAnalysis

llvm/lib/Analysis/InlineAdvisor.cpp
51

DefaultInlineRecord

llvm/lib/Passes/PassBuilder.cpp
628–629

This is for InstrPGO early inlining. I don't see the need to hook up advisor here -- even there is need in the future, it may need a different model. recommend leave this alone and add some comments.

llvm/lib/Transforms/IPO/Inliner.cpp
1069

Is this guard needed?

mtrofin updated this revision to Diff 263229.May 11 2020, 11:35 AM
mtrofin marked 9 inline comments as done.

renames.

will update the names in pass pipeline tests once we close on whether to use the wrapper for InstPGO early inlining.

llvm/lib/Passes/PassBuilder.cpp
628–629

It uses the default advisor. I can see it either way, at the moment it's behaviorally equivalent, the reason I'd use the wrapper here is for uniformity in the pass builder.

llvm/lib/Transforms/IPO/Inliner.cpp
1069

Well... only to avoid creating a wrapper if one isn't needed?

mtrofin updated this revision to Diff 263307.May 11 2020, 4:42 PM

also fixed tests

davidxl added inline comments.May 12 2020, 9:28 AM
llvm/lib/Transforms/IPO/Inliner.cpp
1069

While this is a good change, it seems irrelevant to this patch though.

1073

so this pass injects the inliner pass into the pipeline in a lazy way (on the fly as it runs)?

+tejohnson for a closer look at pass changes.

mtrofin updated this revision to Diff 263488.May 12 2020, 12:14 PM
mtrofin marked 5 inline comments as done.

integration. Added API to register module analyses.

mtrofin added inline comments.May 12 2020, 2:25 PM
llvm/lib/Transforms/IPO/Inliner.cpp
1069

Fair enough - removed. The devirt wrapper is noop with MaxDevirtIterations == 0 anyway.

1073

It's not lazily injected, in the sense that the parent PM is unaffected. We just use a PM as an implementation detail.

tejohnson added inline comments.May 12 2020, 4:56 PM
llvm/test/Other/new-pm-lto-defaults.ll
79

What causes this one to get added?

mtrofin marked 2 inline comments as done.May 12 2020, 6:41 PM
mtrofin added inline comments.
llvm/test/Other/new-pm-lto-defaults.ll
79

See PassBuilder.cpp:1329 - the patch uses the ModuleInlinerWrapper, so that we always inject, canonically, the InlineAdvisor outside the inline pass.

tejohnson added inline comments.May 12 2020, 7:47 PM
llvm/test/Other/new-pm-lto-defaults.ll
79

Right, I understand why the InlineAdvisorAnalysis gets added. But why does LazyCallGraph get added when it wasn't before?

mtrofin updated this revision to Diff 263601.May 12 2020, 9:15 PM
mtrofin marked an inline comment as done.

clarified new-pm-lto-defaults.ll new pass

mtrofin marked 2 inline comments as done.May 12 2020, 9:21 PM
mtrofin added inline comments.
llvm/test/Other/new-pm-lto-defaults.ll
79

Oh! It's actually the devirt pass, which should be a no-op here. If we prefer, for simplicity/clarity, I can bypass using it in Inliner.cpp:1076

tejohnson added inline comments.May 12 2020, 10:26 PM
llvm/test/Other/new-pm-lto-defaults.ll
79

Oh I see. It is a noop because in the regular LTO case there is no simplification pass added to the CGSCC PM, and the inliner pass itself cannot create devirtualization opportunities? The regular LTO pipeline is going to be more sensitive to compile time, what is the overhead of adding this even when it is a noop? Might be better to avoid it.

(just some minor stylistic/formatting things from me)

llvm/lib/Analysis/InlineAdvisor.cpp
103–112

Any particular reason that GetAssumptionCache is a std::function, but GetBFI/TLI/InlineCost are all lambdas without the std::function wrapper? (probably good to make GetAssumptionCache match the others, I guess)

124–125

Prefer std::make_unique if/where possible. (probably written as auto Ret = std::make_unique<DefaultInlineAdvice>(this, CB, OIC, ORE) or just return std::make_unique...;)

142

Drop the () around F here - they're not needed. (also - elsewhere in this patch, there's a bunch of unnecessary ; on function definitions (eg: virtual void OnPassExit(){};) - be good to remove those too)

llvm/lib/Transforms/IPO/Inliner.cpp
678

Usually I'd prefer/suggest using * rather than getValue() on an Optional.

mtrofin updated this revision to Diff 263615.May 12 2020, 11:06 PM
mtrofin marked 4 inline comments as done.

opt-in to devirt

mtrofin updated this revision to Diff 263626.May 12 2020, 11:49 PM

correction

mtrofin added inline comments.May 12 2020, 11:59 PM
llvm/lib/Transforms/IPO/Inliner.cpp
1069

Undid this - see tejohnson's observation about the LTO pipeline sensitivity to compiletime.

llvm/test/Other/new-pm-lto-defaults.ll
79

It's no-op because the MaxDevirtIterations parameter of the ModuleInlinerWrapperPass ctor is 0. I also prefer not instantiating it if not needed - addressed.

I looked deeper, here's what happens:

  • originally, we had this:
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
      InlinerPass(getInlineParamsFromOptLevel(Level))));
  • with the change, we have:
MPM.add(ModuleInlinerWrapper)

Now, ModuleInlinerWrapper has a ModuleToPostOrderCGSCCPassAdaptor wrapping a CGSCCPassManager, which inside has the InlinerPass (or, just before, the ModuleInlinerWrapper had a ModuleToPostOrderCGSCCPassAdaptor wrapping a devirt pass wrapping the CGSCCPassManager wrapping the InlinerPass)

When we used the devirt wrapper, the ModuleToPostOrderCGSCCPassAdaptor's template type parameters included the devirt wrapper type - hence my initially (and incompletely) observing that as a reason for the diff. Now, it includes PassManager as type parameters (and LazyCallGraph, but probably a more apt pattern match is on PassManager though)

I'd argue the CGSCCPassManager doesn't add much overhead in this case (as opposed to the devirt wrapper) - its run method basically goes straight to running the contained pass.

Alternatively, if we want to completely avoid any overhead, we could do some customization in the ModuleInlinerWrapper to avoid using the CGSCCPassManager if there's just the inliner.

A third option I'd prefer not to do is to just instantiate (in this case) the InlinerPass like before. I prefer not going that way because the inliner parameters are now a concept owned by the InlineAdvisor.

WDYT?

The PM changes lgtm

llvm/test/Other/new-pm-lto-defaults.ll
79

I think I agree that wrapping in the additional CGSCC PM shouldn't be a problem. So I think this is fine now with the change to avoid the devirt wrapper.

mtrofin updated this revision to Diff 263746.May 13 2020, 9:17 AM
mtrofin marked 7 inline comments as done.

feedback

llvm/lib/Analysis/InlineAdvisor.cpp
103–112

This is how it was originally, in Inliner.cpp (and still is, it's needed there still). There seems to be a cast issue. I'll investigate separately, as it may involve slightly changing the types of getInlineCost parameters. Left a fixme.

davidxl accepted this revision.May 13 2020, 9:21 AM

LGTM (assuming all pending comments are addressed).

llvm/lib/Transforms/IPO/Inliner.cpp
842

PendingRecord -- IA or Advise

This revision is now accepted and ready to land.May 13 2020, 9:21 AM
mtrofin updated this revision to Diff 263767.May 13 2020, 10:02 AM
mtrofin marked an inline comment as done.

small rename

mtrofin marked an inline comment as done.May 13 2020, 10:03 AM
mtrofin added inline comments.
llvm/lib/Transforms/IPO/Inliner.cpp
842

done

This revision was automatically updated to reflect the committed changes.
skan added a subscriber: skan.May 14 2020, 12:25 AM

Hello, a bisect seems to show this breaks our 2 stage toolchain build from assertion errors:

[12/3658] Building CXX object lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o
FAILED: lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o 
/b/s/w/ir/cache/goma/client/gomacc /b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/./bin/clang++ --sysroot=/b/s/w/ir/k/cipd/linux-amd64  -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib/Support -I/b/s/w/ir/k/llvm-project/llvm/lib/Support -I/b/s/w/ir/k/recipe_cleanup/clangy7u70P/libxml2_install/include/libxml2 -Iinclude -I/b/s/w/ir/k/llvm-project/llvm/include -I/b/s/w/ir/k/recipe_cleanup/clangy7u70P/zlib_install/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wno-comment -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections -flto -ffile-prefix-map=/b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/tools/clang/stage2-bins=../recipe_cleanup/clangy7u70P/llvm_build_dir/tools/clang/stage2-bins -ffile-prefix-map=/b/s/w/ir/k/llvm-project/= -no-canonical-prefixes -O3 -DNDEBUG   -std=c++14  -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -MD -MT lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o -MF lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o.d -o lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o -c /b/s/w/ir/k/llvm-project/llvm/lib/Support/APFloat.cpp
clang++: /b/s/w/ir/k/llvm-project/llvm/lib/Analysis/CodeMetrics.cpp:104: static void llvm::CodeMetrics::collectEphemeralValues(const llvm::Function *, llvm::AssumptionCache *, SmallPtrSetImpl<const llvm::Value *> &): Assertion `I->getParent()->getParent() == F && "Found assumption for the wrong function!"' failed.
clang++: error: clang frontend command failed due to signal (use -v to see invocation)
Fuchsia clang version 11.0.0 (https://fuchsia.googlesource.com/a/third_party/llvm-project 9ed9860d8774b364412ce50bf5d59a8eaee1adb7)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/./bin
clang++: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang++: note: diagnostic msg: /tmp/APFloat-fb32b4.cpp
clang++: note: diagnostic msg: /tmp/APFloat-fb32b4.sh
clang++: note: diagnostic msg: 

********************

Would you mind taking a look and sending out a fix or reverting? Thanks.

Builder: https://luci-milo.appspot.com/p/fuchsia/builders/prod/clang-linux-x64/b8880367188790280224

Hello, a bisect seems to show this breaks our 2 stage toolchain build from assertion errors:

[12/3658] Building CXX object lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o
FAILED: lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o 
/b/s/w/ir/cache/goma/client/gomacc /b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/./bin/clang++ --sysroot=/b/s/w/ir/k/cipd/linux-amd64  -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib/Support -I/b/s/w/ir/k/llvm-project/llvm/lib/Support -I/b/s/w/ir/k/recipe_cleanup/clangy7u70P/libxml2_install/include/libxml2 -Iinclude -I/b/s/w/ir/k/llvm-project/llvm/include -I/b/s/w/ir/k/recipe_cleanup/clangy7u70P/zlib_install/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wno-comment -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections -flto -ffile-prefix-map=/b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/tools/clang/stage2-bins=../recipe_cleanup/clangy7u70P/llvm_build_dir/tools/clang/stage2-bins -ffile-prefix-map=/b/s/w/ir/k/llvm-project/= -no-canonical-prefixes -O3 -DNDEBUG   -std=c++14  -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -MD -MT lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o -MF lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o.d -o lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o -c /b/s/w/ir/k/llvm-project/llvm/lib/Support/APFloat.cpp
clang++: /b/s/w/ir/k/llvm-project/llvm/lib/Analysis/CodeMetrics.cpp:104: static void llvm::CodeMetrics::collectEphemeralValues(const llvm::Function *, llvm::AssumptionCache *, SmallPtrSetImpl<const llvm::Value *> &): Assertion `I->getParent()->getParent() == F && "Found assumption for the wrong function!"' failed.
clang++: error: clang frontend command failed due to signal (use -v to see invocation)
Fuchsia clang version 11.0.0 (https://fuchsia.googlesource.com/a/third_party/llvm-project 9ed9860d8774b364412ce50bf5d59a8eaee1adb7)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /b/s/w/ir/k/recipe_cleanup/clangy7u70P/llvm_build_dir/./bin
clang++: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang++: note: diagnostic msg: /tmp/APFloat-fb32b4.cpp
clang++: note: diagnostic msg: /tmp/APFloat-fb32b4.sh
clang++: note: diagnostic msg: 

********************

Would you mind taking a look and sending out a fix or reverting? Thanks.

Builder: https://luci-milo.appspot.com/p/fuchsia/builders/prod/clang-linux-x64/b8880367188790280224

Looking right now - thanks!

taolq added a subscriber: taolq.May 27 2021, 4:57 AM
taolq removed a subscriber: taolq.May 27 2021, 4:57 AM