llvm-project/llvm/lib/Transforms/IPO
Chandler Carruth 20e588e1af [PM/Inliner] Make the new PM's inliner process call edges across an
entire SCC before iterating on newly-introduced call edges resulting
from any inlined function bodies.

This more closely matches the behavior of the old PM's inliner. While it
wasn't really clear to me initially, this behavior is actually essential
to the inliner behaving reasonably in its current design.

Because the inliner is fundamentally a bottom-up inliner and all of its
cost modeling is designed around that it often runs into trouble within
an SCC where we don't have any meaningful bottom-up ordering to use. In
addition to potentially cyclic, infinite inlining that we block with the
inline history mechanism, it can also take seemingly simple call graph
patterns within an SCC and turn them into *insanely* large functions by
accidentally working top-down across the SCC without any of the
threshold limitations that traditional top-down inliners use.

Consider this diabolical monster.cpp file that Richard Smith came up
with to help demonstrate this issue:
```
template <int N> extern const char *str;

void g(const char *);

template <bool K, int N> void f(bool *B, bool *E) {
  if (K)
    g(str<N>);
  if (B == E)
    return;
  if (*B)
    f<true, N + 1>(B + 1, E);
  else
    f<false, N + 1>(B + 1, E);
}
template <> void f<false, MAX>(bool *B, bool *E) { return f<false, 0>(B, E); }
template <> void f<true, MAX>(bool *B, bool *E) { return f<true, 0>(B, E); }

extern bool *arr, *end;
void test() { f<false, 0>(arr, end); }
```

When compiled with '-DMAX=N' for various values of N, this will create an SCC
with a reasonably large number of functions. Previously, the inliner would try
to exhaust the inlining candidates in a single function before moving on. This,
unfortunately, turns it into a top-down inliner within the SCC. Because our
thresholds were never built for that, we will incrementally decide that it is
always worth inlining and proceed to flatten the entire SCC into that one
function.

What's worse, we'll then proceed to the next function, and do the exact same
thing except we'll skip the first function, and so on. And at each step, we'll
also make some of the constant factors larger, which is awesome.

The fix in this patch is the obvious one which makes the new PM's inliner use
the same technique used by the old PM: consider all the call edges across the
entire SCC before beginning to process call edges introduced by inlining. The
result of this is essentially to distribute the inlining across the SCC so that
every function incrementally grows toward the inline thresholds rather than
allowing the inliner to grow one of the functions vastly beyond the threshold.
The code for this is a bit awkward, but it works out OK.

We could consider in the future doing something more powerful here such as
prioritized order (via lowest cost and/or profile info) and/or a code-growth
budget per SCC. However, both of those would require really substantial work
both to design the system in a way that wouldn't break really useful
abstraction decomposition properties of the current inliner and to be tuned
across a reasonably diverse set of code and workloads. It also seems really
risky in many ways. I have only found a single real-world file that triggers
the bad behavior here and it is generated code that has a pretty pathological
pattern. I'm not worried about the inliner not doing an *awesome* job here as
long as it does *ok*. On the other hand, the cases that will be tricky to get
right in a prioritized scheme with a budget will be more common and idiomatic
for at least some frontends (C++ and Rust at least). So while these approaches
are still really interesting, I'm not in a huge rush to go after them. Staying
even closer to the existing PM's behavior, especially when this easy to do,
seems like the right short to medium term approach.

I don't really have a test case that makes sense yet... I'll try to find a
variant of the IR produced by the monster template metaprogram that is both
small enough to be sane and large enough to clearly show when we get this wrong
in the future. But I'm not confident this exists. And the behavior change here
*should* be unobservable without snooping on debug logging. So there isn't
really much to test.

The test case updates come from two incidental changes:
1) We now visit functions in an SCC in the opposite order. I don't think there
   really is a "right" order here, so I just update the test cases.
2) We no longer compute some analyses when an SCC has no call instructions that
   we consider for inlining.

llvm-svn: 297374
2017-03-09 11:35:40 +00:00
..
AlwaysInliner.cpp [PM] Teach the always inliner in the new pass manager to support 2016-12-26 23:43:27 +00:00
ArgumentPromotion.cpp [PM] Port ArgumentPromotion to the new pass manager. 2017-02-09 23:46:27 +00:00
BarrierNoopPass.cpp
CMakeLists.txt IPO: Introduce ThinLTOBitcodeWriter pass. 2016-12-16 00:26:30 +00:00
ConstantMerge.cpp Don't merge global constants with non-dbg metadata. 2017-03-09 00:03:37 +00:00
CrossDSOCFI.cpp Consistently use ModuleAnalysisManager 2016-08-09 00:28:38 +00:00
DeadArgumentElimination.cpp Replace some callers of setTailCall with setTailCallKind 2016-11-25 22:35:09 +00:00
ElimAvailExtern.cpp [PM] Remove support for omitting the AnalysisManager argument to new 2016-06-17 00:11:01 +00:00
ExtractGV.cpp Apply clang-tidy's modernize-loop-convert to most of lib/Transforms. 2016-06-26 12:28:59 +00:00
ForceFunctionAttrs.cpp [PM] Remove support for omitting the AnalysisManager argument to new 2016-06-17 00:11:01 +00:00
FunctionAttrs.cpp FunctionAttrs: Factor out a function for querying memory access of a specific copy of a function. NFC. 2017-02-14 00:28:13 +00:00
FunctionImport.cpp Perform symbol binding for .symver versioned symbols 2017-03-09 00:19:49 +00:00
GlobalDCE.cpp Global DCE performance improvement 2017-01-27 19:48:57 +00:00
GlobalOpt.cpp [Analysis] Add LibFunc_ prefix to enums in TargetLibraryInfo. (NFC) 2017-01-23 23:16:46 +00:00
GlobalSplit.cpp Fix one-after-the-end type metadata handling in globalsplit. 2017-03-07 22:18:48 +00:00
IPConstantPropagation.cpp [IPCP] Don't propagate return value for naked functions. 2017-02-04 19:44:14 +00:00
IPO.cpp Introduce GlobalSplit pass. 2016-11-16 23:40:26 +00:00
InferFunctionAttrs.cpp Consistently use ModuleAnalysisManager 2016-08-09 00:28:38 +00:00
InlineSimple.cpp Improve PGO support for the new inliner 2017-01-20 22:44:04 +00:00
Inliner.cpp [PM/Inliner] Make the new PM's inliner process call edges across an 2017-03-09 11:35:40 +00:00
Internalize.cpp Consistently use ModuleAnalysisManager 2016-08-09 00:28:38 +00:00
LLVMBuild.txt Add missing library dep. 2016-12-16 00:43:00 +00:00
LoopExtractor.cpp Apply clang-tidy's modernize-loop-convert to most of lib/Transforms. 2016-06-26 12:28:59 +00:00
LowerTypeTests.cpp Rename LowerTypeTestsSummaryAction to PassSummaryAction. NFCI. 2017-02-09 21:45:01 +00:00
MergeFunctions.cpp Use print() instead of dump() in code 2017-01-28 06:53:55 +00:00
PartialInlining.cpp Apply clang-tidy's performance-unnecessary-value-param to LLVM. 2017-01-13 14:39:03 +00:00
PassManagerBuilder.cpp Disable gvn-hoist (PR32153) 2017-03-06 21:10:40 +00:00
PruneEH.cpp [PruneEH] Be correct in the face IPO 2016-10-03 19:35:30 +00:00
SampleProfile.cpp Remove the sample pgo annotation heuristic that uses call count to annotate basic block count. 2017-03-06 17:49:59 +00:00
StripDeadPrototypes.cpp [PM] Remove support for omitting the AnalysisManager argument to new 2016-06-17 00:11:01 +00:00
StripSymbols.cpp [IR] Remove the DIExpression field from DIGlobalVariable. 2016-12-20 02:09:43 +00:00
ThinLTOBitcodeWriter.cpp ThinLTOBitcodeWriter: Do not follow operand edges of type GlobalValue when looking for virtual functions. 2017-03-02 23:10:17 +00:00
WholeProgramDevirt.cpp WholeProgramDevirt: Implement importing for uniform ret val opt. 2017-03-09 01:11:15 +00:00