2004-06-20 06:11:48 +02:00
|
|
|
//===- Inliner.cpp - Code common to all inliners --------------------------===//
|
2005-04-22 01:48:37 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2005-04-22 01:48:37 +02:00
|
|
|
//
|
2003-10-20 21:43:21 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
2003-08-31 21:10:30 +02:00
|
|
|
//
|
2004-05-23 23:22:17 +02:00
|
|
|
// This file implements the mechanics required to implement inlining without
|
|
|
|
// missing any calls and updating the call graph. The decisions of which calls
|
|
|
|
// are profitable to inline are implemented elsewhere.
|
2003-08-31 21:10:30 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
#include "llvm/Transforms/IPO/Inliner.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/None.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SetVector.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2014-09-01 11:01:39 +02:00
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2016-12-19 09:22:17 +01:00
|
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
[PM/AA] Rebuild LLVM's alias analysis infrastructure in a way compatible
with the new pass manager, and no longer relying on analysis groups.
This builds essentially a ground-up new AA infrastructure stack for
LLVM. The core ideas are the same that are used throughout the new pass
manager: type erased polymorphism and direct composition. The design is
as follows:
- FunctionAAResults is a type-erasing alias analysis results aggregation
interface to walk a single query across a range of results from
different alias analyses. Currently this is function-specific as we
always assume that aliasing queries are *within* a function.
- AAResultBase is a CRTP utility providing stub implementations of
various parts of the alias analysis result concept, notably in several
cases in terms of other more general parts of the interface. This can
be used to implement only a narrow part of the interface rather than
the entire interface. This isn't really ideal, this logic should be
hoisted into FunctionAAResults as currently it will cause
a significant amount of redundant work, but it faithfully models the
behavior of the prior infrastructure.
- All the alias analysis passes are ported to be wrapper passes for the
legacy PM and new-style analysis passes for the new PM with a shared
result object. In some cases (most notably CFL), this is an extremely
naive approach that we should revisit when we can specialize for the
new pass manager.
- BasicAA has been restructured to reflect that it is much more
fundamentally a function analysis because it uses dominator trees and
loop info that need to be constructed for each function.
All of the references to getting alias analysis results have been
updated to use the new aggregation interface. All the preservation and
other pass management code has been updated accordingly.
The way the FunctionAAResultsWrapperPass works is to detect the
available alias analyses when run, and add them to the results object.
This means that we should be able to continue to respect when various
passes are added to the pipeline, for example adding CFL or adding TBAA
passes should just cause their results to be available and to get folded
into this. The exception to this rule is BasicAA which really needs to
be a function pass due to using dominator trees and loop info. As
a consequence, the FunctionAAResultsWrapperPass directly depends on
BasicAA and always includes it in the aggregation.
This has significant implications for preserving analyses. Generally,
most passes shouldn't bother preserving FunctionAAResultsWrapperPass
because rebuilding the results just updates the set of known AA passes.
The exception to this rule are LoopPass instances which need to preserve
all the function analyses that the loop pass manager will end up
needing. This means preserving both BasicAAWrapperPass and the
aggregating FunctionAAResultsWrapperPass.
Now, when preserving an alias analysis, you do so by directly preserving
that analysis. This is only necessary for non-immutable-pass-provided
alias analyses though, and there are only three of interest: BasicAA,
GlobalsAA (formerly GlobalsModRef), and SCEVAA. Usually BasicAA is
preserved when needed because it (like DominatorTree and LoopInfo) is
marked as a CFG-only pass. I've expanded GlobalsAA into the preserved
set everywhere we previously were preserving all of AliasAnalysis, and
I've added SCEVAA in the intersection of that with where we preserve
SCEV itself.
One significant challenge to all of this is that the CGSCC passes were
actually using the alias analysis implementations by taking advantage of
a pretty amazing set of loop holes in the old pass manager's analysis
management code which allowed analysis groups to slide through in many
cases. Moving away from analysis groups makes this problem much more
obvious. To fix it, I've leveraged the flexibility the design of the new
PM components provides to just directly construct the relevant alias
analyses for the relevant functions in the IPO passes that need them.
This is a bit hacky, but should go away with the new pass manager, and
is already in many ways cleaner than the prior state.
Another significant challenge is that various facilities of the old
alias analysis infrastructure just don't fit any more. The most
significant of these is the alias analysis 'counter' pass. That pass
relied on the ability to snoop on AA queries at different points in the
analysis group chain. Instead, I'm planning to build printing
functionality directly into the aggregation layer. I've not included
that in this patch merely to keep it smaller.
Note that all of this needs a nearly complete rewrite of the AA
documentation. I'm planning to do that, but I'd like to make sure the
new design settles, and to flesh out a bit more of what it looks like in
the new pass manager first.
Differential Revision: http://reviews.llvm.org/D12080
llvm-svn: 247167
2015-09-09 19:55:00 +02:00
|
|
|
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
2017-01-20 23:44:04 +01:00
|
|
|
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/Analysis/CGSCCPassManager.h"
|
2003-08-31 21:10:30 +02:00
|
|
|
#include "llvm/Analysis/CallGraph.h"
|
2009-10-13 20:30:07 +02:00
|
|
|
#include "llvm/Analysis/InlineCost.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/Analysis/LazyCallGraph.h"
|
2017-10-10 01:19:02 +02:00
|
|
|
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
|
2016-06-10 00:23:21 +02:00
|
|
|
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
2015-03-23 20:32:43 +01:00
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
2018-06-04 23:23:21 +02:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/Attributes.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
2014-03-04 12:01:28 +01:00
|
|
|
#include "llvm/IR/CallSite.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2014-04-08 18:42:34 +02:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/Function.h"
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
#include "llvm/IR/InstIterator.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/Instruction.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/Metadata.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/Module.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/IR/PassManager.h"
|
|
|
|
#include "llvm/IR/User.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2004-09-02 00:55:40 +02:00
|
|
|
#include "llvm/Support/Debug.h"
|
2009-07-25 02:23:56 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/Transforms/Utils/Cloning.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"
|
2016-12-27 00:43:27 +01:00
|
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
2017-10-19 23:21:30 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <functional>
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
#include <sstream>
|
2017-10-19 23:21:30 +02:00
|
|
|
#include <tuple>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2003-11-21 22:45:31 +01:00
|
|
|
using namespace llvm;
|
2003-11-11 23:41:34 +01:00
|
|
|
|
2014-04-22 04:55:47 +02:00
|
|
|
#define DEBUG_TYPE "inline"
|
|
|
|
|
2006-12-19 23:09:18 +01:00
|
|
|
STATISTIC(NumInlined, "Number of functions inlined");
|
2010-05-01 19:19:38 +02:00
|
|
|
STATISTIC(NumCallsDeleted, "Number of call sites deleted, not inlined");
|
2006-12-19 23:09:18 +01:00
|
|
|
STATISTIC(NumDeleted, "Number of functions deleted because all callers found");
|
2009-08-27 08:29:33 +02:00
|
|
|
STATISTIC(NumMergedAllocas, "Number of allocas merged together");
|
2006-12-19 23:09:18 +01:00
|
|
|
|
2012-06-02 12:20:22 +02:00
|
|
|
// This weirdly named statistic tracks the number of times that, when attempting
|
2012-04-11 12:15:10 +02:00
|
|
|
// to inline a function A into B, we analyze the callers of B in order to see
|
|
|
|
// if those would be more profitable and blocked inline steps.
|
|
|
|
STATISTIC(NumCallerCallersAnalyzed, "Number of caller-callers analyzed");
|
|
|
|
|
2016-08-17 04:40:23 +02:00
|
|
|
/// Flag to disable manual alloca merging.
|
|
|
|
///
|
|
|
|
/// Merging of allocas was originally done as a stack-size saving technique
|
|
|
|
/// prior to LLVM's code generator having support for stack coloring based on
|
|
|
|
/// lifetime markers. It is now in the process of being removed. To experiment
|
|
|
|
/// with disabling it and relying fully on lifetime marker based stack
|
|
|
|
/// coloring, you can pass this flag to LLVM.
|
|
|
|
static cl::opt<bool>
|
|
|
|
DisableInlinedAllocaMerging("disable-inlined-alloca-merging",
|
|
|
|
cl::init(false), cl::Hidden);
|
|
|
|
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
namespace {
|
2017-10-19 23:21:30 +02:00
|
|
|
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
enum class InlinerFunctionImportStatsOpts {
|
|
|
|
No = 0,
|
|
|
|
Basic = 1,
|
|
|
|
Verbose = 2,
|
|
|
|
};
|
|
|
|
|
2017-10-19 23:21:30 +02:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
static cl::opt<InlinerFunctionImportStatsOpts> InlinerFunctionImportStats(
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
"inliner-function-import-stats",
|
|
|
|
cl::init(InlinerFunctionImportStatsOpts::No),
|
|
|
|
cl::values(clEnumValN(InlinerFunctionImportStatsOpts::Basic, "basic",
|
|
|
|
"basic statistics"),
|
|
|
|
clEnumValN(InlinerFunctionImportStatsOpts::Verbose, "verbose",
|
2016-10-08 21:41:06 +02:00
|
|
|
"printing of statistics for each inlined function")),
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
cl::Hidden, cl::desc("Enable inliner stats for imported functions"));
|
|
|
|
|
2018-08-28 17:27:25 +02:00
|
|
|
/// Flag to add inline messages as callsite attributes 'inline-remark'.
|
|
|
|
static cl::opt<bool>
|
|
|
|
InlineRemarkAttribute("inline-remark-attribute", cl::init(false),
|
|
|
|
cl::Hidden,
|
|
|
|
cl::desc("Enable adding inline-remark attribute to"
|
|
|
|
" callsites processed by inliner but decided"
|
|
|
|
" to be not inlined"));
|
|
|
|
|
2017-10-19 23:21:30 +02:00
|
|
|
LegacyInlinerBase::LegacyInlinerBase(char &ID) : CallGraphSCCPass(ID) {}
|
2003-08-31 21:10:30 +02:00
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
LegacyInlinerBase::LegacyInlinerBase(char &ID, bool InsertLifetime)
|
2016-03-08 01:36:35 +01:00
|
|
|
: CallGraphSCCPass(ID), InsertLifetime(InsertLifetime) {}
|
2008-01-12 07:49:13 +01:00
|
|
|
|
2015-03-10 17:42:24 +01:00
|
|
|
/// For this class, we declare that we require and preserve the call graph.
|
|
|
|
/// If the derived class implements this method, it should
|
2007-01-31 00:28:39 +01:00
|
|
|
/// always explicitly call the implementation here.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
void LegacyInlinerBase::getAnalysisUsage(AnalysisUsage &AU) const {
|
2016-12-19 09:22:17 +01:00
|
|
|
AU.addRequired<AssumptionCacheTracker>();
|
2016-06-10 00:23:21 +02:00
|
|
|
AU.addRequired<ProfileSummaryInfoWrapperPass>();
|
[PM/AA] Rebuild LLVM's alias analysis infrastructure in a way compatible
with the new pass manager, and no longer relying on analysis groups.
This builds essentially a ground-up new AA infrastructure stack for
LLVM. The core ideas are the same that are used throughout the new pass
manager: type erased polymorphism and direct composition. The design is
as follows:
- FunctionAAResults is a type-erasing alias analysis results aggregation
interface to walk a single query across a range of results from
different alias analyses. Currently this is function-specific as we
always assume that aliasing queries are *within* a function.
- AAResultBase is a CRTP utility providing stub implementations of
various parts of the alias analysis result concept, notably in several
cases in terms of other more general parts of the interface. This can
be used to implement only a narrow part of the interface rather than
the entire interface. This isn't really ideal, this logic should be
hoisted into FunctionAAResults as currently it will cause
a significant amount of redundant work, but it faithfully models the
behavior of the prior infrastructure.
- All the alias analysis passes are ported to be wrapper passes for the
legacy PM and new-style analysis passes for the new PM with a shared
result object. In some cases (most notably CFL), this is an extremely
naive approach that we should revisit when we can specialize for the
new pass manager.
- BasicAA has been restructured to reflect that it is much more
fundamentally a function analysis because it uses dominator trees and
loop info that need to be constructed for each function.
All of the references to getting alias analysis results have been
updated to use the new aggregation interface. All the preservation and
other pass management code has been updated accordingly.
The way the FunctionAAResultsWrapperPass works is to detect the
available alias analyses when run, and add them to the results object.
This means that we should be able to continue to respect when various
passes are added to the pipeline, for example adding CFL or adding TBAA
passes should just cause their results to be available and to get folded
into this. The exception to this rule is BasicAA which really needs to
be a function pass due to using dominator trees and loop info. As
a consequence, the FunctionAAResultsWrapperPass directly depends on
BasicAA and always includes it in the aggregation.
This has significant implications for preserving analyses. Generally,
most passes shouldn't bother preserving FunctionAAResultsWrapperPass
because rebuilding the results just updates the set of known AA passes.
The exception to this rule are LoopPass instances which need to preserve
all the function analyses that the loop pass manager will end up
needing. This means preserving both BasicAAWrapperPass and the
aggregating FunctionAAResultsWrapperPass.
Now, when preserving an alias analysis, you do so by directly preserving
that analysis. This is only necessary for non-immutable-pass-provided
alias analyses though, and there are only three of interest: BasicAA,
GlobalsAA (formerly GlobalsModRef), and SCEVAA. Usually BasicAA is
preserved when needed because it (like DominatorTree and LoopInfo) is
marked as a CFG-only pass. I've expanded GlobalsAA into the preserved
set everywhere we previously were preserving all of AliasAnalysis, and
I've added SCEVAA in the intersection of that with where we preserve
SCEV itself.
One significant challenge to all of this is that the CGSCC passes were
actually using the alias analysis implementations by taking advantage of
a pretty amazing set of loop holes in the old pass manager's analysis
management code which allowed analysis groups to slide through in many
cases. Moving away from analysis groups makes this problem much more
obvious. To fix it, I've leveraged the flexibility the design of the new
PM components provides to just directly construct the relevant alias
analyses for the relevant functions in the IPO passes that need them.
This is a bit hacky, but should go away with the new pass manager, and
is already in many ways cleaner than the prior state.
Another significant challenge is that various facilities of the old
alias analysis infrastructure just don't fit any more. The most
significant of these is the alias analysis 'counter' pass. That pass
relied on the ability to snoop on AA queries at different points in the
analysis group chain. Instead, I'm planning to build printing
functionality directly into the aggregation layer. I've not included
that in this patch merely to keep it smaller.
Note that all of this needs a nearly complete rewrite of the AA
documentation. I'm planning to do that, but I'd like to make sure the
new design settles, and to flesh out a bit more of what it looks like in
the new pass manager first.
Differential Revision: http://reviews.llvm.org/D12080
llvm-svn: 247167
2015-09-09 19:55:00 +02:00
|
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
[AA] Hoist the logic to reformulate various AA queries in terms of other
parts of the AA interface out of the base class of every single AA
result object.
Because this logic reformulates the query in terms of some other aspect
of the API, it would easily cause O(n^2) query patterns in alias
analysis. These could in turn be magnified further based on the number
of call arguments, and then further based on the number of AA queries
made for a particular call. This ended up causing problems for Rust that
were actually noticable enough to get a bug (PR26564) and probably other
places as well.
When originally re-working the AA infrastructure, the desire was to
regularize the pattern of refinement without losing any generality.
While I think it was successful, that is clearly proving to be too
costly. And the cost is needless: we gain no actual improvement for this
generality of making a direct query to tbaa actually be able to
re-use some other alias analysis's refinement logic for one of the other
APIs, or some such. In short, this is entirely wasted work.
To the extent possible, delegation to other API surfaces should be done
at the aggregation layer so that we can avoid re-walking the
aggregation. In fact, this significantly simplifies the logic as we no
longer need to smuggle the aggregation layer into each alias analysis
(or the TargetLibraryInfo into each alias analysis just so we can form
argument memory locations!).
However, we also have some delegation logic inside of BasicAA and some
of it even makes sense. When the delegation logic is baking in specific
knowledge of aliasing properties of the LLVM IR, as opposed to simply
reformulating the query to utilize a different alias analysis interface
entry point, it makes a lot of sense to restrict that logic to
a different layer such as BasicAA. So one aspect of the delegation that
was in every AA base class is that when we don't have operand bundles,
we re-use function AA results as a fallback for callsite alias results.
This relies on the IR properties of calls and functions w.r.t. aliasing,
and so seems a better fit to BasicAA. I've lifted the logic up to that
point where it seems to be a natural fit. This still does a bit of
redundant work (we query function attributes twice, once via the
callsite and once via the function AA query) but it is *exactly* twice
here, no more.
The end result is that all of the delegation logic is hoisted out of the
base class and into either the aggregation layer when it is a pure
retargeting to a different API surface, or into BasicAA when it relies
on the IR's aliasing properties. This should fix the quadratic query
pattern reported in PR26564, although I don't have a stand-alone test
case to reproduce it.
It also seems general goodness. Now the numerous AAs that don't need
target library info don't carry it around and depend on it. I think
I can even rip out the general access to the aggregation layer and only
expose that in BasicAA as it is the only place where we re-query in that
manner.
However, this is a non-trivial change to the AA infrastructure so I want
to get some additional eyes on this before it lands. Sadly, it can't
wait long because we should really cherry pick this into 3.8 if we're
going to go this route.
Differential Revision: http://reviews.llvm.org/D17329
llvm-svn: 262490
2016-03-02 16:56:53 +01:00
|
|
|
getAAResultsAnalysisUsage(AU);
|
2012-12-27 12:17:15 +01:00
|
|
|
CallGraphSCCPass::getAnalysisUsage(AU);
|
2007-01-31 00:28:39 +01:00
|
|
|
}
|
|
|
|
|
2017-10-19 23:21:30 +02:00
|
|
|
using InlinedArrayAllocasTy = DenseMap<ArrayType *, std::vector<AllocaInst *>>;
|
2009-08-27 08:29:33 +02:00
|
|
|
|
2016-08-17 04:40:23 +02:00
|
|
|
/// Look at all of the allocas that we inlined through this call site. If we
|
|
|
|
/// have already inlined other allocas through other calls into this function,
|
|
|
|
/// then we know that they have disjoint lifetimes and that we can merge them.
|
2009-08-27 08:29:33 +02:00
|
|
|
///
|
2016-08-17 04:40:23 +02:00
|
|
|
/// There are many heuristics possible for merging these allocas, and the
|
|
|
|
/// different options have different tradeoffs. One thing that we *really*
|
|
|
|
/// don't want to hurt is SRoA: once inlining happens, often allocas are no
|
|
|
|
/// longer address taken and so they can be promoted.
|
|
|
|
///
|
|
|
|
/// Our "solution" for that is to only merge allocas whose outermost type is an
|
|
|
|
/// array type. These are usually not promoted because someone is using a
|
|
|
|
/// variable index into them. These are also often the most important ones to
|
|
|
|
/// merge.
|
|
|
|
///
|
|
|
|
/// A better solution would be to have real memory lifetime markers in the IR
|
|
|
|
/// and not have the inliner do any merging of allocas at all. This would
|
|
|
|
/// allow the backend to do proper stack slot coloring of all allocas that
|
|
|
|
/// *actually make it to the backend*, which is really what we want.
|
|
|
|
///
|
|
|
|
/// Because we don't have this information, we do this simple and useful hack.
|
|
|
|
static void mergeInlinedArrayAllocas(
|
|
|
|
Function *Caller, InlineFunctionInfo &IFI,
|
|
|
|
InlinedArrayAllocasTy &InlinedArrayAllocas, int InlineHistory) {
|
2016-08-03 03:02:31 +02:00
|
|
|
SmallPtrSet<AllocaInst *, 16> UsedAllocas;
|
|
|
|
|
Fix PR8735, a really terrible problem in the inliner's "alloca merging"
optimization.
Consider:
static void foo() {
A = alloca
...
}
static void bar() {
B = alloca
...
call foo();
}
void main() {
bar()
}
The inliner proceeds bottom up, but lets pretend it decides not to inline foo
into bar. When it gets to main, it inlines bar into main(), and says "hey, I
just inlined an alloca "B" into main, lets remember that. Then it keeps going
and finds that it now contains a call to foo. It decides to inline foo into
main, and says "hey, foo has an alloca A, and I have an alloca B from another
inlined call site, lets reuse it". The problem with this of course, is that
the lifetime of A and B are nested, not disjoint.
Unfortunately I can't create a reasonable testcase for this: the one in the
PR is both huge and extremely sensitive, because you minor tweaks end up
causing foo to get inlined into bar too early. We already have tests for the
basic alloca merging optimization and this does not break them.
llvm-svn: 120995
2010-12-06 08:52:42 +01:00
|
|
|
// When processing our SCC, check to see if CS was inlined from some other
|
|
|
|
// call site. For example, if we're processing "A" in this code:
|
|
|
|
// A() { B() }
|
|
|
|
// B() { x = alloca ... C() }
|
|
|
|
// C() { y = alloca ... }
|
|
|
|
// Assume that C was not inlined into B initially, and so we're processing A
|
|
|
|
// and decide to inline B into A. Doing this makes an alloca available for
|
|
|
|
// reuse and makes a callsite (C) available for inlining. When we process
|
|
|
|
// the C call site we don't want to do any alloca merging between X and Y
|
|
|
|
// because their scopes are not disjoint. We could make this smarter by
|
|
|
|
// keeping track of the inline history for each alloca in the
|
|
|
|
// InlinedArrayAllocas but this isn't likely to be a significant win.
|
2016-08-03 03:02:31 +02:00
|
|
|
if (InlineHistory != -1) // Only do merging for top-level call sites in SCC.
|
2016-08-17 04:40:23 +02:00
|
|
|
return;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Loop over all the allocas we have so far and see if they can be merged with
|
|
|
|
// a previously inlined alloca. If not, remember that we had it.
|
2016-08-03 03:02:31 +02:00
|
|
|
for (unsigned AllocaNo = 0, e = IFI.StaticAllocas.size(); AllocaNo != e;
|
|
|
|
++AllocaNo) {
|
2010-04-23 01:07:58 +02:00
|
|
|
AllocaInst *AI = IFI.StaticAllocas[AllocaNo];
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Don't bother trying to merge array allocations (they will usually be
|
|
|
|
// canonicalized to be an allocation *of* an array), or allocations whose
|
|
|
|
// type is not itself an array (because we're afraid of pessimizing SRoA).
|
2011-07-18 06:54:35 +02:00
|
|
|
ArrayType *ATy = dyn_cast<ArrayType>(AI->getAllocatedType());
|
2014-04-25 07:29:35 +02:00
|
|
|
if (!ATy || AI->isArrayAllocation())
|
2009-08-27 08:29:33 +02:00
|
|
|
continue;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Get the list of all available allocas for this array type.
|
2016-08-03 03:02:31 +02:00
|
|
|
std::vector<AllocaInst *> &AllocasForType = InlinedArrayAllocas[ATy];
|
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Loop over the allocas in AllocasForType to see if we can reuse one. Note
|
|
|
|
// that we have to be careful not to reuse the same "available" alloca for
|
|
|
|
// multiple different allocas that we just inlined, we use the 'UsedAllocas'
|
|
|
|
// set to keep track of which "available" allocas are being used by this
|
|
|
|
// function. Also, AllocasForType can be empty of course!
|
|
|
|
bool MergedAwayAlloca = false;
|
2015-06-25 21:28:24 +02:00
|
|
|
for (AllocaInst *AvailableAlloca : AllocasForType) {
|
2013-07-16 19:10:55 +02:00
|
|
|
unsigned Align1 = AI->getAlignment(),
|
|
|
|
Align2 = AvailableAlloca->getAlignment();
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// The available alloca has to be in the right function, not in some other
|
|
|
|
// function in this SCC.
|
|
|
|
if (AvailableAlloca->getParent() != AI->getParent())
|
|
|
|
continue;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// If the inlined function already uses this alloca then we can't reuse
|
|
|
|
// it.
|
2014-11-19 08:49:26 +01:00
|
|
|
if (!UsedAllocas.insert(AvailableAlloca).second)
|
2009-08-27 08:29:33 +02:00
|
|
|
continue;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Otherwise, we *can* reuse it, RAUW AI into AvailableAlloca and declare
|
|
|
|
// success!
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " ***MERGED ALLOCA: " << *AI
|
|
|
|
<< "\n\t\tINTO: " << *AvailableAlloca << '\n');
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2015-09-29 02:30:19 +02:00
|
|
|
// Move affected dbg.declare calls immediately after the new alloca to
|
2016-11-20 14:19:49 +01:00
|
|
|
// avoid the situation when a dbg.declare precedes its alloca.
|
2015-09-29 02:30:19 +02:00
|
|
|
if (auto *L = LocalAsMetadata::getIfExists(AI))
|
|
|
|
if (auto *MDV = MetadataAsValue::getIfExists(AI->getContext(), L))
|
|
|
|
for (User *U : MDV->users())
|
|
|
|
if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(U))
|
|
|
|
DDI->moveBefore(AvailableAlloca->getNextNode());
|
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
AI->replaceAllUsesWith(AvailableAlloca);
|
2013-07-16 19:10:55 +02:00
|
|
|
|
2013-07-17 16:32:41 +02:00
|
|
|
if (Align1 != Align2) {
|
|
|
|
if (!Align1 || !Align2) {
|
2015-03-04 19:43:29 +01:00
|
|
|
const DataLayout &DL = Caller->getParent()->getDataLayout();
|
|
|
|
unsigned TypeAlign = DL.getABITypeAlignment(AI->getAllocatedType());
|
2013-07-17 16:32:41 +02:00
|
|
|
|
|
|
|
Align1 = Align1 ? Align1 : TypeAlign;
|
|
|
|
Align2 = Align2 ? Align2 : TypeAlign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Align1 > Align2)
|
|
|
|
AvailableAlloca->setAlignment(AI->getAlignment());
|
|
|
|
}
|
2013-07-16 19:10:55 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
AI->eraseFromParent();
|
|
|
|
MergedAwayAlloca = true;
|
|
|
|
++NumMergedAllocas;
|
2014-04-25 07:29:35 +02:00
|
|
|
IFI.StaticAllocas[AllocaNo] = nullptr;
|
2009-08-27 08:29:33 +02:00
|
|
|
break;
|
|
|
|
}
|
2005-04-22 01:48:37 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// If we already nuked the alloca, we're done with it.
|
|
|
|
if (MergedAwayAlloca)
|
|
|
|
continue;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// If we were unable to merge away the alloca either because there are no
|
|
|
|
// allocas of the right type available or because we reused them all
|
|
|
|
// already, remember that this alloca came from an inlined function and mark
|
|
|
|
// it used so we don't reuse it for other allocas from this inline
|
|
|
|
// operation.
|
|
|
|
AllocasForType.push_back(AI);
|
|
|
|
UsedAllocas.insert(AI);
|
2004-05-23 23:22:17 +02:00
|
|
|
}
|
2016-08-17 04:40:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If it is possible to inline the specified call site,
|
|
|
|
/// do so and update the CallGraph for this operation.
|
|
|
|
///
|
|
|
|
/// This function also does some basic book-keeping to update the IR. The
|
|
|
|
/// InlinedArrayAllocas map keeps track of any allocas that are already
|
|
|
|
/// available from other functions inlined into the caller. If we are able to
|
|
|
|
/// inline this call site we attempt to reuse already available allocas or add
|
|
|
|
/// any new allocas to the set if not possible.
|
2018-08-28 17:27:25 +02:00
|
|
|
static InlineResult InlineCallIfPossible(
|
2016-08-17 04:40:23 +02:00
|
|
|
CallSite CS, InlineFunctionInfo &IFI,
|
|
|
|
InlinedArrayAllocasTy &InlinedArrayAllocas, int InlineHistory,
|
|
|
|
bool InsertLifetime, function_ref<AAResults &(Function &)> &AARGetter,
|
|
|
|
ImportedFunctionsInliningStatistics &ImportedFunctionsStats) {
|
|
|
|
Function *Callee = CS.getCalledFunction();
|
|
|
|
Function *Caller = CS.getCaller();
|
|
|
|
|
|
|
|
AAResults &AAR = AARGetter(*Callee);
|
|
|
|
|
|
|
|
// Try to inline the function. Get the list of static allocas that were
|
|
|
|
// inlined.
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
InlineResult IR = InlineFunction(CS, IFI, &AAR, InsertLifetime);
|
|
|
|
if (!IR)
|
|
|
|
return IR;
|
2016-08-17 04:40:23 +02:00
|
|
|
|
|
|
|
if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
|
|
|
|
ImportedFunctionsStats.recordInline(*Caller, *Callee);
|
|
|
|
|
|
|
|
AttributeFuncs::mergeAttributesForInlining(*Caller, *Callee);
|
|
|
|
|
|
|
|
if (!DisableInlinedAllocaMerging)
|
|
|
|
mergeInlinedArrayAllocas(Caller, IFI, InlinedArrayAllocas, InlineHistory);
|
2016-08-03 03:02:31 +02:00
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
return IR; // success
|
2003-08-31 21:10:30 +02:00
|
|
|
}
|
2010-01-20 18:51:28 +01:00
|
|
|
|
2016-07-23 06:22:50 +02:00
|
|
|
/// Return true if inlining of CS can block the caller from being
|
|
|
|
/// inlined which is proved to be more beneficial. \p IC is the
|
|
|
|
/// estimated inline cost associated with callsite \p CS.
|
2017-01-30 17:15:14 +01:00
|
|
|
/// \p TotalSecondaryCost will be set to the estimated cost of inlining the
|
|
|
|
/// caller if \p CS is suppressed for inlining.
|
2016-07-23 06:22:50 +02:00
|
|
|
static bool
|
|
|
|
shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC,
|
|
|
|
int &TotalSecondaryCost,
|
2016-08-06 14:33:46 +02:00
|
|
|
function_ref<InlineCost(CallSite CS)> GetInlineCost) {
|
2016-04-30 00:59:36 +02:00
|
|
|
// For now we only handle local or inline functions.
|
|
|
|
if (!Caller->hasLocalLinkage() && !Caller->hasLinkOnceODRLinkage())
|
|
|
|
return false;
|
2019-01-05 03:26:29 +01:00
|
|
|
// If the cost of inlining CS is non-positive, it is not going to prevent the
|
|
|
|
// caller from being inlined into its callers and hence we don't need to
|
|
|
|
// defer.
|
|
|
|
if (IC.getCost() <= 0)
|
|
|
|
return false;
|
2016-04-30 00:59:36 +02:00
|
|
|
// Try to detect the case where the current inlining candidate caller (call
|
|
|
|
// it B) is a static or linkonce-ODR function and is an inlining candidate
|
|
|
|
// elsewhere, and the current candidate callee (call it C) is large enough
|
|
|
|
// that inlining it into B would make B too big to inline later. In these
|
|
|
|
// circumstances it may be best not to inline C into B, but to inline B into
|
|
|
|
// its callers.
|
|
|
|
//
|
|
|
|
// This only applies to static and linkonce-ODR functions because those are
|
|
|
|
// expected to be available for inlining in the translation units where they
|
|
|
|
// are used. Thus we will always have the opportunity to make local inlining
|
|
|
|
// decisions. Importantly the linkonce-ODR linkage covers inline functions
|
|
|
|
// and templates in C++.
|
|
|
|
//
|
|
|
|
// FIXME: All of this logic should be sunk into getInlineCost. It relies on
|
|
|
|
// the internal implementation of the inline cost metrics rather than
|
|
|
|
// treating them as truly abstract units etc.
|
|
|
|
TotalSecondaryCost = 0;
|
|
|
|
// The candidate cost to be imposed upon the current function.
|
2017-03-22 13:01:57 +01:00
|
|
|
int CandidateCost = IC.getCost() - 1;
|
2019-01-05 03:26:29 +01:00
|
|
|
// If the caller has local linkage and can be inlined to all its callers, we
|
|
|
|
// can apply a huge negative bonus to TotalSecondaryCost.
|
|
|
|
bool ApplyLastCallBonus = Caller->hasLocalLinkage() && !Caller->hasOneUse();
|
2016-04-30 00:59:36 +02:00
|
|
|
// This bool tracks what happens if we DO inline C into B.
|
|
|
|
bool inliningPreventsSomeOuterInline = false;
|
|
|
|
for (User *U : Caller->users()) {
|
2019-01-05 03:26:29 +01:00
|
|
|
// If the caller will not be removed (either because it does not have a
|
|
|
|
// local linkage or because the LastCallToStaticBonus has been already
|
|
|
|
// applied), then we can exit the loop early.
|
|
|
|
if (!ApplyLastCallBonus && TotalSecondaryCost >= IC.getCost())
|
|
|
|
return false;
|
2016-04-30 00:59:36 +02:00
|
|
|
CallSite CS2(U);
|
|
|
|
|
|
|
|
// If this isn't a call to Caller (it could be some other sort
|
|
|
|
// of reference) skip it. Such references will prevent the caller
|
|
|
|
// from being removed.
|
|
|
|
if (!CS2 || CS2.getCalledFunction() != Caller) {
|
2019-01-05 03:26:29 +01:00
|
|
|
ApplyLastCallBonus = false;
|
2016-04-30 00:59:36 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-23 06:22:50 +02:00
|
|
|
InlineCost IC2 = GetInlineCost(CS2);
|
2016-04-30 00:59:36 +02:00
|
|
|
++NumCallerCallersAnalyzed;
|
|
|
|
if (!IC2) {
|
2019-01-05 03:26:29 +01:00
|
|
|
ApplyLastCallBonus = false;
|
2016-04-30 00:59:36 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (IC2.isAlways())
|
|
|
|
continue;
|
|
|
|
|
2016-11-04 04:00:52 +01:00
|
|
|
// See if inlining of the original callsite would erase the cost delta of
|
2016-04-30 00:59:36 +02:00
|
|
|
// this callsite. We subtract off the penalty for the call instruction,
|
|
|
|
// which we would be deleting.
|
|
|
|
if (IC2.getCostDelta() <= CandidateCost) {
|
|
|
|
inliningPreventsSomeOuterInline = true;
|
|
|
|
TotalSecondaryCost += IC2.getCost();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If all outer calls to Caller would get inlined, the cost for the last
|
|
|
|
// one is set very low by getInlineCost, in anticipation that Caller will
|
|
|
|
// be removed entirely. We did not account for this above unless there
|
|
|
|
// is only one caller of Caller.
|
2019-01-05 03:26:29 +01:00
|
|
|
if (ApplyLastCallBonus)
|
2016-08-10 23:15:22 +02:00
|
|
|
TotalSecondaryCost -= InlineConstants::LastCallToStaticBonus;
|
2016-04-30 00:59:36 +02:00
|
|
|
|
|
|
|
if (inliningPreventsSomeOuterInline && TotalSecondaryCost < IC.getCost())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
static std::basic_ostream<char> &operator<<(std::basic_ostream<char> &R,
|
|
|
|
const ore::NV &Arg) {
|
|
|
|
return R << Arg.Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class RemarkT>
|
|
|
|
RemarkT &operator<<(RemarkT &&R, const InlineCost &IC) {
|
|
|
|
using namespace ore;
|
|
|
|
if (IC.isAlways()) {
|
|
|
|
R << "(cost=always)";
|
|
|
|
} else if (IC.isNever()) {
|
|
|
|
R << "(cost=never)";
|
|
|
|
} else {
|
|
|
|
R << "(cost=" << ore::NV("Cost", IC.getCost())
|
|
|
|
<< ", threshold=" << ore::NV("Threshold", IC.getThreshold()) << ")";
|
|
|
|
}
|
|
|
|
if (const char *Reason = IC.getReason())
|
|
|
|
R << ": " << ore::NV("Reason", Reason);
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string inlineCostStr(const InlineCost &IC) {
|
|
|
|
std::stringstream Remark;
|
|
|
|
Remark << IC;
|
|
|
|
return Remark.str();
|
|
|
|
}
|
|
|
|
|
2017-08-21 18:45:47 +02:00
|
|
|
/// Return the cost only if the inliner should attempt to inline at the given
|
|
|
|
/// CallSite. If we return the cost, we will emit an optimisation remark later
|
|
|
|
/// using that cost, so we won't do so from this function.
|
|
|
|
static Optional<InlineCost>
|
|
|
|
shouldInline(CallSite CS, function_ref<InlineCost(CallSite CS)> GetInlineCost,
|
|
|
|
OptimizationRemarkEmitter &ORE) {
|
2016-09-28 01:47:03 +02:00
|
|
|
using namespace ore;
|
2017-10-19 23:21:30 +02:00
|
|
|
|
2016-07-23 06:22:50 +02:00
|
|
|
InlineCost IC = GetInlineCost(CS);
|
2016-09-28 01:47:03 +02:00
|
|
|
Instruction *Call = CS.getInstruction();
|
|
|
|
Function *Callee = CS.getCalledFunction();
|
2017-01-30 17:22:45 +01:00
|
|
|
Function *Caller = CS.getCaller();
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2008-10-30 20:26:59 +01:00
|
|
|
if (IC.isAlways()) {
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " Inlining " << inlineCostStr(IC)
|
2018-05-14 14:53:11 +02:00
|
|
|
<< ", Call: " << *CS.getInstruction() << "\n");
|
2017-08-21 18:45:47 +02:00
|
|
|
return IC;
|
2008-10-30 20:26:59 +01:00
|
|
|
}
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2008-10-30 20:26:59 +01:00
|
|
|
if (IC.isNever()) {
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " NOT Inlining " << inlineCostStr(IC)
|
2018-05-14 14:53:11 +02:00
|
|
|
<< ", Call: " << *CS.getInstruction() << "\n");
|
2017-09-20 01:00:55 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "NeverInline", Call)
|
2017-01-30 17:22:45 +01:00
|
|
|
<< NV("Callee", Callee) << " not inlined into "
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
<< NV("Caller", Caller) << " because it should never be inlined "
|
|
|
|
<< IC;
|
2017-09-20 01:00:55 +02:00
|
|
|
});
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
return IC;
|
2008-10-30 20:26:59 +01:00
|
|
|
}
|
2016-08-03 03:02:31 +02:00
|
|
|
|
Initial commit for the rewrite of the inline cost analysis to operate
on a per-callsite walk of the called function's instructions, in
breadth-first order over the potentially reachable set of basic blocks.
This is a major shift in how inline cost analysis works to improve the
accuracy and rationality of inlining decisions. A brief outline of the
algorithm this moves to:
- Build a simplification mapping based on the callsite arguments to the
function arguments.
- Push the entry block onto a worklist of potentially-live basic blocks.
- Pop the first block off of the *front* of the worklist (for
breadth-first ordering) and walk its instructions using a custom
InstVisitor.
- For each instruction's operands, re-map them based on the
simplification mappings available for the given callsite.
- Compute any simplification possible of the instruction after
re-mapping, and store that back int othe simplification mapping.
- Compute any bonuses, costs, or other impacts of the instruction on the
cost metric.
- When the terminator is reached, replace any conditional value in the
terminator with any simplifications from the mapping we have, and add
any successors which are not proven to be dead from these
simplifications to the worklist.
- Pop the next block off of the front of the worklist, and repeat.
- As soon as the cost of inlining exceeds the threshold for the
callsite, stop analyzing the function in order to bound cost.
The primary goal of this algorithm is to perfectly handle dead code
paths. We do not want any code in trivially dead code paths to impact
inlining decisions. The previous metric was *extremely* flawed here, and
would always subtract the average cost of two successors of
a conditional branch when it was proven to become an unconditional
branch at the callsite. There was no handling of wildly different costs
between the two successors, which would cause inlining when the path
actually taken was too large, and no inlining when the path actually
taken was trivially simple. There was also no handling of the code
*path*, only the immediate successors. These problems vanish completely
now. See the added regression tests for the shiny new features -- we
skip recursive function calls, SROA-killing instructions, and high cost
complex CFG structures when dead at the callsite being analyzed.
Switching to this algorithm required refactoring the inline cost
interface to accept the actual threshold rather than simply returning
a single cost. The resulting interface is pretty bad, and I'm planning
to do lots of interface cleanup after this patch.
Several other refactorings fell out of this, but I've tried to minimize
them for this patch. =/ There is still more cleanup that can be done
here. Please point out anything that you see in review.
I've worked really hard to try to mirror at least the spirit of all of
the previous heuristics in the new model. It's not clear that they are
all correct any more, but I wanted to minimize the change in this single
patch, it's already a bit ridiculous. One heuristic that is *not* yet
mirrored is to allow inlining of functions with a dynamic alloca *if*
the caller has a dynamic alloca. I will add this back, but I think the
most reasonable way requires changes to the inliner itself rather than
just the cost metric, and so I've deferred this for a subsequent patch.
The test case is XFAIL-ed until then.
As mentioned in the review mail, this seems to make Clang run about 1%
to 2% faster in -O0, but makes its binary size grow by just under 4%.
I've looked into the 4% growth, and it can be fixed, but requires
changes to other parts of the inliner.
llvm-svn: 153812
2012-03-31 14:42:41 +02:00
|
|
|
if (!IC) {
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " NOT Inlining " << inlineCostStr(IC)
|
2018-05-14 14:53:11 +02:00
|
|
|
<< ", Call: " << *CS.getInstruction() << "\n");
|
2017-09-20 01:00:55 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "TooCostly", Call)
|
2017-01-30 17:22:45 +01:00
|
|
|
<< NV("Callee", Callee) << " not inlined into "
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
<< NV("Caller", Caller) << " because too costly to inline " << IC;
|
2017-09-20 01:00:55 +02:00
|
|
|
});
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
return IC;
|
2008-10-29 02:02:02 +01:00
|
|
|
}
|
2009-10-09 02:11:32 +02:00
|
|
|
|
2016-04-30 00:59:36 +02:00
|
|
|
int TotalSecondaryCost = 0;
|
2016-07-23 06:22:50 +02:00
|
|
|
if (shouldBeDeferred(Caller, CS, IC, TotalSecondaryCost, GetInlineCost)) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " NOT Inlining: " << *CS.getInstruction()
|
|
|
|
<< " Cost = " << IC.getCost()
|
|
|
|
<< ", outer Cost = " << TotalSecondaryCost << '\n');
|
2017-10-11 19:12:59 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "IncreaseCostInOtherContexts",
|
2017-01-30 17:22:45 +01:00
|
|
|
Call)
|
2016-09-28 01:47:03 +02:00
|
|
|
<< "Not inlining. Cost of inlining " << NV("Callee", Callee)
|
|
|
|
<< " increases the cost of inlining " << NV("Caller", Caller)
|
2017-10-11 19:12:59 +02:00
|
|
|
<< " in other contexts";
|
|
|
|
});
|
2017-08-21 18:45:47 +02:00
|
|
|
|
|
|
|
// IC does not bool() to false, so get an InlineCost that will.
|
|
|
|
// This will not be inspected to make an error message.
|
|
|
|
return None;
|
2009-10-09 02:11:32 +02:00
|
|
|
}
|
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " Inlining " << inlineCostStr(IC)
|
2018-05-14 14:53:11 +02:00
|
|
|
<< ", Call: " << *CS.getInstruction() << '\n');
|
2017-08-21 18:45:47 +02:00
|
|
|
return IC;
|
2008-10-29 02:02:02 +01:00
|
|
|
}
|
2003-08-31 21:10:30 +02:00
|
|
|
|
2015-03-10 17:42:24 +01:00
|
|
|
/// Return true if the specified inline history ID
|
2010-05-01 03:05:10 +02:00
|
|
|
/// indicates an inline history that includes the specified function.
|
2016-08-03 03:02:31 +02:00
|
|
|
static bool InlineHistoryIncludes(
|
|
|
|
Function *F, int InlineHistoryID,
|
|
|
|
const SmallVectorImpl<std::pair<Function *, int>> &InlineHistory) {
|
2010-05-01 03:05:10 +02:00
|
|
|
while (InlineHistoryID != -1) {
|
|
|
|
assert(unsigned(InlineHistoryID) < InlineHistory.size() &&
|
|
|
|
"Invalid inline history ID");
|
|
|
|
if (InlineHistory[InlineHistoryID].first == F)
|
|
|
|
return true;
|
|
|
|
InlineHistoryID = InlineHistory[InlineHistoryID].second;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool LegacyInlinerBase::doInitialization(CallGraph &CG) {
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
|
|
|
|
ImportedFunctionsStats.setModuleInfo(CG.getModule());
|
|
|
|
return false; // No changes to CallGraph.
|
|
|
|
}
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool LegacyInlinerBase::runOnSCC(CallGraphSCC &SCC) {
|
2016-04-23 00:06:11 +02:00
|
|
|
if (skipSCC(SCC))
|
|
|
|
return false;
|
2016-05-23 23:57:54 +02:00
|
|
|
return inlineCalls(SCC);
|
|
|
|
}
|
2016-04-23 00:06:11 +02:00
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
static void emit_inlined_into(OptimizationRemarkEmitter &ORE, DebugLoc &DLoc,
|
|
|
|
const BasicBlock *Block, const Function &Callee,
|
|
|
|
const Function &Caller, const InlineCost &IC) {
|
|
|
|
ORE.emit([&]() {
|
|
|
|
bool AlwaysInline = IC.isAlways();
|
|
|
|
StringRef RemarkName = AlwaysInline ? "AlwaysInline" : "Inlined";
|
|
|
|
return OptimizationRemark(DEBUG_TYPE, RemarkName, DLoc, Block)
|
|
|
|
<< ore::NV("Callee", &Callee) << " inlined into "
|
|
|
|
<< ore::NV("Caller", &Caller) << " with " << IC;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-28 17:27:25 +02:00
|
|
|
static void setInlineRemark(CallSite &CS, StringRef message) {
|
|
|
|
if (!InlineRemarkAttribute)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Attribute attr = Attribute::get(CS->getContext(), "inline-remark", message);
|
|
|
|
CS.addAttribute(AttributeList::FunctionIndex, attr);
|
|
|
|
}
|
|
|
|
|
2016-07-23 06:22:50 +02:00
|
|
|
static bool
|
|
|
|
inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
|
2016-12-19 09:22:17 +01:00
|
|
|
std::function<AssumptionCache &(Function &)> GetAssumptionCache,
|
2016-07-23 06:22:50 +02:00
|
|
|
ProfileSummaryInfo *PSI, TargetLibraryInfo &TLI,
|
|
|
|
bool InsertLifetime,
|
2016-08-06 14:33:46 +02:00
|
|
|
function_ref<InlineCost(CallSite CS)> GetInlineCost,
|
|
|
|
function_ref<AAResults &(Function &)> AARGetter,
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
ImportedFunctionsInliningStatistics &ImportedFunctionsStats) {
|
2016-08-03 03:02:31 +02:00
|
|
|
SmallPtrSet<Function *, 8> SCCFunctions;
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Inliner visiting SCC:");
|
2015-06-20 09:12:33 +02:00
|
|
|
for (CallGraphNode *Node : SCC) {
|
|
|
|
Function *F = Node->getFunction();
|
2016-08-03 03:02:31 +02:00
|
|
|
if (F)
|
|
|
|
SCCFunctions.insert(F);
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " " << (F ? F->getName() : "INDIRECTNODE"));
|
2003-08-31 21:10:30 +02:00
|
|
|
}
|
|
|
|
|
2004-05-23 23:22:17 +02:00
|
|
|
// Scan through and identify all call sites ahead of time so that we only
|
|
|
|
// inline call sites in the original functions, not call sites that result
|
|
|
|
// from inlining other functions.
|
2010-05-01 03:05:10 +02:00
|
|
|
SmallVector<std::pair<CallSite, int>, 16> CallSites;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2010-05-01 03:05:10 +02:00
|
|
|
// When inlining a callee produces new call sites, we want to keep track of
|
|
|
|
// the fact that they were inlined from the callee. This allows us to avoid
|
|
|
|
// infinite inlining in some obscure cases. To represent this, we use an
|
|
|
|
// index into the InlineHistory vector.
|
2016-08-03 03:02:31 +02:00
|
|
|
SmallVector<std::pair<Function *, int>, 8> InlineHistory;
|
2004-05-23 23:22:17 +02:00
|
|
|
|
2015-06-20 09:12:33 +02:00
|
|
|
for (CallGraphNode *Node : SCC) {
|
|
|
|
Function *F = Node->getFunction();
|
2016-08-26 22:21:05 +02:00
|
|
|
if (!F || F->isDeclaration())
|
2016-08-03 03:02:31 +02:00
|
|
|
continue;
|
|
|
|
|
2016-08-26 22:21:05 +02:00
|
|
|
OptimizationRemarkEmitter ORE(F);
|
2015-06-20 09:12:33 +02:00
|
|
|
for (BasicBlock &BB : *F)
|
|
|
|
for (Instruction &I : BB) {
|
|
|
|
CallSite CS(cast<Value>(&I));
|
2009-10-09 02:11:32 +02:00
|
|
|
// If this isn't a call, or it is a call to an intrinsic, it can
|
2009-08-31 07:34:32 +02:00
|
|
|
// never be inlined.
|
2010-07-29 00:50:26 +02:00
|
|
|
if (!CS || isa<IntrinsicInst>(I))
|
2009-08-27 05:51:50 +02:00
|
|
|
continue;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-31 07:34:32 +02:00
|
|
|
// If this is a direct call to an external function, we can never inline
|
|
|
|
// it. If it is an indirect call, inlining may resolve it to be a
|
|
|
|
// direct call, so we keep it.
|
2015-07-19 17:48:07 +02:00
|
|
|
if (Function *Callee = CS.getCalledFunction())
|
2016-08-26 22:21:05 +02:00
|
|
|
if (Callee->isDeclaration()) {
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-27 22:55:07 +02:00
|
|
|
using namespace ore;
|
2017-10-19 23:21:30 +02:00
|
|
|
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, "unavailable definition");
|
2017-10-11 19:12:59 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-27 22:55:07 +02:00
|
|
|
<< NV("Callee", Callee) << " will not be inlined into "
|
2016-09-27 23:58:17 +02:00
|
|
|
<< NV("Caller", CS.getCaller())
|
|
|
|
<< " because its definition is unavailable"
|
2017-10-11 19:12:59 +02:00
|
|
|
<< setIsVerbose();
|
|
|
|
});
|
2015-07-19 17:48:07 +02:00
|
|
|
continue;
|
2016-08-26 22:21:05 +02:00
|
|
|
}
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2010-05-01 03:05:10 +02:00
|
|
|
CallSites.push_back(std::make_pair(CS, -1));
|
2009-08-27 05:51:50 +02:00
|
|
|
}
|
|
|
|
}
|
2003-08-31 21:10:30 +02:00
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << ": " << CallSites.size() << " call sites.\n");
|
2005-04-22 01:48:37 +02:00
|
|
|
|
2010-04-20 02:47:08 +02:00
|
|
|
// If there are no calls in this function, exit early.
|
|
|
|
if (CallSites.empty())
|
|
|
|
return false;
|
2015-07-02 16:25:09 +02:00
|
|
|
|
2004-05-23 23:22:17 +02:00
|
|
|
// Now that we have all of the call sites, move the ones to functions in the
|
|
|
|
// current SCC to the end of the list.
|
|
|
|
unsigned FirstCallInSCC = CallSites.size();
|
|
|
|
for (unsigned i = 0; i < FirstCallInSCC; ++i)
|
2010-05-01 03:05:10 +02:00
|
|
|
if (Function *F = CallSites[i].first.getCalledFunction())
|
2004-05-23 23:22:17 +02:00
|
|
|
if (SCCFunctions.count(F))
|
|
|
|
std::swap(CallSites[i--], CallSites[--FirstCallInSCC]);
|
2005-04-22 01:48:37 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
InlinedArrayAllocasTy InlinedArrayAllocas;
|
2017-05-10 01:21:10 +02:00
|
|
|
InlineFunctionInfo InlineInfo(&CG, &GetAssumptionCache, PSI);
|
2015-01-04 13:03:27 +01:00
|
|
|
|
2004-05-23 23:22:17 +02:00
|
|
|
// Now that we have all of the call sites, loop over them and inline them if
|
|
|
|
// it looks profitable to do so.
|
|
|
|
bool Changed = false;
|
|
|
|
bool LocalChange;
|
|
|
|
do {
|
|
|
|
LocalChange = false;
|
|
|
|
// Iterate over the outer loop because inlining functions can cause indirect
|
|
|
|
// calls to become direct calls.
|
2015-06-20 09:12:33 +02:00
|
|
|
// CallSites may be modified inside so ranged for loop can not be used.
|
2009-08-27 05:51:50 +02:00
|
|
|
for (unsigned CSi = 0; CSi != CallSites.size(); ++CSi) {
|
2010-05-01 03:05:10 +02:00
|
|
|
CallSite CS = CallSites[CSi].first;
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-11-12 08:56:08 +01:00
|
|
|
Function *Caller = CS.getCaller();
|
2009-08-27 08:29:33 +02:00
|
|
|
Function *Callee = CS.getCalledFunction();
|
2009-11-12 08:56:08 +01:00
|
|
|
|
2017-06-09 05:29:20 +02:00
|
|
|
// We can only inline direct calls to non-declarations.
|
|
|
|
if (!Callee || Callee->isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
2017-06-13 04:24:09 +02:00
|
|
|
Instruction *Instr = CS.getInstruction();
|
|
|
|
|
|
|
|
bool IsTriviallyDead = isInstructionTriviallyDead(Instr, &TLI);
|
|
|
|
|
|
|
|
int InlineHistoryID;
|
|
|
|
if (!IsTriviallyDead) {
|
|
|
|
// If this call site was obtained by inlining another function, verify
|
|
|
|
// that the include path for the function did not include the callee
|
|
|
|
// itself. If so, we'd be recursively inlining the same function,
|
|
|
|
// which would provide the same callsites, which would cause us to
|
|
|
|
// infinitely inline.
|
|
|
|
InlineHistoryID = CallSites[CSi].second;
|
|
|
|
if (InlineHistoryID != -1 &&
|
2018-08-28 17:27:25 +02:00
|
|
|
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) {
|
|
|
|
setInlineRemark(CS, "recursive");
|
2017-06-13 04:24:09 +02:00
|
|
|
continue;
|
2018-08-28 17:27:25 +02:00
|
|
|
}
|
2017-06-13 04:24:09 +02:00
|
|
|
}
|
|
|
|
|
2017-06-13 01:01:17 +02:00
|
|
|
// FIXME for new PM: because of the old PM we currently generate ORE and
|
|
|
|
// in turn BFI on demand. With the new PM, the ORE dependency should
|
|
|
|
// just become a regular analysis dependency.
|
|
|
|
OptimizationRemarkEmitter ORE(Caller);
|
|
|
|
|
2017-08-21 18:45:47 +02:00
|
|
|
Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE);
|
2017-06-13 01:01:17 +02:00
|
|
|
// If the policy determines that we should inline this function,
|
|
|
|
// delete the call instead.
|
2018-08-28 17:27:25 +02:00
|
|
|
if (!OIC.hasValue()) {
|
|
|
|
setInlineRemark(CS, "deferred");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!OIC.getValue()) {
|
|
|
|
// shouldInline() call returned a negative inline cost that explains
|
|
|
|
// why this callsite should not be inlined.
|
|
|
|
setInlineRemark(CS, inlineCostStr(*OIC));
|
2017-06-13 01:01:17 +02:00
|
|
|
continue;
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
}
|
2017-06-13 01:01:17 +02:00
|
|
|
|
2009-11-12 08:56:08 +01:00
|
|
|
// If this call site is dead and it is to a readonly function, we should
|
|
|
|
// just delete the call instead of trying to inline it, regardless of
|
|
|
|
// size. This happens because IPSCCP propagates the result out of the
|
|
|
|
// call and then we're left with the dead call.
|
2017-06-13 04:24:09 +02:00
|
|
|
if (IsTriviallyDead) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " -> Deleting dead call: " << *Instr << "\n");
|
2009-11-12 08:56:08 +01:00
|
|
|
// Update the call graph by deleting the edge from Callee to Caller.
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, "trivially dead");
|
2019-04-19 07:59:42 +02:00
|
|
|
CG[Caller]->removeCallEdgeFor(*cast<CallBase>(CS.getInstruction()));
|
2017-06-13 04:24:09 +02:00
|
|
|
Instr->eraseFromParent();
|
2009-11-12 08:56:08 +01:00
|
|
|
++NumCallsDeleted;
|
|
|
|
} else {
|
2014-04-17 14:22:14 +02:00
|
|
|
// Get DebugLoc to report. CS will be invalid after Inliner.
|
2017-08-21 18:45:47 +02:00
|
|
|
DebugLoc DLoc = CS->getDebugLoc();
|
2016-08-10 02:44:44 +02:00
|
|
|
BasicBlock *Block = CS.getParent();
|
2014-05-22 16:19:46 +02:00
|
|
|
|
2010-04-23 01:37:35 +02:00
|
|
|
// Attempt to inline the function.
|
2017-01-30 17:22:45 +01:00
|
|
|
using namespace ore;
|
2017-10-19 23:21:30 +02:00
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
InlineResult IR = InlineCallIfPossible(
|
|
|
|
CS, InlineInfo, InlinedArrayAllocas, InlineHistoryID,
|
|
|
|
InsertLifetime, AARGetter, ImportedFunctionsStats);
|
|
|
|
if (!IR) {
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
|
2017-10-11 19:12:59 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc,
|
|
|
|
Block)
|
|
|
|
<< NV("Callee", Callee) << " will not be inlined into "
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
<< NV("Caller", Caller) << ": " << NV("Reason", IR.message);
|
2017-10-11 19:12:59 +02:00
|
|
|
});
|
2009-11-12 08:56:08 +01:00
|
|
|
continue;
|
2014-05-22 16:19:46 +02:00
|
|
|
}
|
2009-11-12 08:56:08 +01:00
|
|
|
++NumInlined;
|
2014-04-08 18:42:34 +02:00
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
emit_inlined_into(ORE, DLoc, Block, *Callee, *Caller, *OIC);
|
2014-04-08 18:42:34 +02:00
|
|
|
|
2010-05-01 03:26:13 +02:00
|
|
|
// If inlining this function gave us any new call sites, throw them
|
2010-04-23 01:37:35 +02:00
|
|
|
// onto our worklist to process. They are useful inline candidates.
|
2010-05-01 03:26:13 +02:00
|
|
|
if (!InlineInfo.InlinedCalls.empty()) {
|
2010-05-01 03:05:10 +02:00
|
|
|
// Create a new inline history entry for this, so that we remember
|
|
|
|
// that these new callsites came about due to inlining Callee.
|
|
|
|
int NewHistoryID = InlineHistory.size();
|
|
|
|
InlineHistory.push_back(std::make_pair(Callee, InlineHistoryID));
|
|
|
|
|
2015-06-20 09:12:33 +02:00
|
|
|
for (Value *Ptr : InlineInfo.InlinedCalls)
|
2012-03-25 06:03:40 +02:00
|
|
|
CallSites.push_back(std::make_pair(CallSite(Ptr), NewHistoryID));
|
2010-04-23 20:37:01 +02:00
|
|
|
}
|
2009-11-12 08:56:08 +01:00
|
|
|
}
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-11-12 08:56:08 +01:00
|
|
|
// If we inlined or deleted the last possible call site to the function,
|
|
|
|
// delete the function body now.
|
|
|
|
if (Callee && Callee->use_empty() && Callee->hasLocalLinkage() &&
|
2009-08-31 07:34:32 +02:00
|
|
|
// TODO: Can remove if in SCC now.
|
2009-08-31 05:15:49 +02:00
|
|
|
!SCCFunctions.count(Callee) &&
|
|
|
|
// The function may be apparently dead, but if there are indirect
|
|
|
|
// callgraph references to the node, we cannot delete it yet, this
|
|
|
|
// could invalidate the CGSCC iterator.
|
|
|
|
CG[Callee]->getNumReferences() == 0) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " -> Deleting dead function: "
|
|
|
|
<< Callee->getName() << "\n");
|
2009-08-27 08:29:33 +02:00
|
|
|
CallGraphNode *CalleeNode = CG[Callee];
|
2015-07-02 16:25:09 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Remove any call graph edges from the callee to its callees.
|
|
|
|
CalleeNode->removeAllCalledFunctions();
|
2016-08-03 03:02:31 +02:00
|
|
|
|
2009-08-27 08:29:33 +02:00
|
|
|
// Removing the node for callee from the call graph and delete it.
|
2016-03-08 01:36:35 +01:00
|
|
|
delete CG.removeFunctionFromModule(CalleeNode);
|
2009-08-27 08:29:33 +02:00
|
|
|
++NumDeleted;
|
|
|
|
}
|
2009-08-27 05:51:50 +02:00
|
|
|
|
2016-08-03 03:02:31 +02:00
|
|
|
// Remove this call site from the list. If possible, use
|
2009-08-27 05:51:50 +02:00
|
|
|
// swap/pop_back for efficiency, but do not use it if doing so would
|
|
|
|
// move a call site to a function in this SCC before the
|
|
|
|
// 'FirstCallInSCC' barrier.
|
2010-04-17 00:42:17 +02:00
|
|
|
if (SCC.isSingular()) {
|
2010-05-31 14:50:41 +02:00
|
|
|
CallSites[CSi] = CallSites.back();
|
2009-08-27 05:51:50 +02:00
|
|
|
CallSites.pop_back();
|
|
|
|
} else {
|
2016-08-03 03:02:31 +02:00
|
|
|
CallSites.erase(CallSites.begin() + CSi);
|
2003-08-31 21:10:30 +02:00
|
|
|
}
|
2009-08-27 05:51:50 +02:00
|
|
|
--CSi;
|
|
|
|
|
|
|
|
Changed = true;
|
|
|
|
LocalChange = true;
|
|
|
|
}
|
2004-05-23 23:22:17 +02:00
|
|
|
} while (LocalChange);
|
2003-08-31 21:10:30 +02:00
|
|
|
|
2004-04-08 08:34:31 +02:00
|
|
|
return Changed;
|
2003-08-31 21:10:30 +02:00
|
|
|
}
|
2003-11-11 23:41:34 +01:00
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool LegacyInlinerBase::inlineCalls(CallGraphSCC &SCC) {
|
2016-07-23 06:22:50 +02:00
|
|
|
CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
|
2016-12-19 09:22:17 +01:00
|
|
|
ACT = &getAnalysis<AssumptionCacheTracker>();
|
2018-11-19 06:23:16 +01:00
|
|
|
PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
|
2016-07-23 06:22:50 +02:00
|
|
|
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
2016-12-19 09:22:17 +01:00
|
|
|
auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
|
|
|
|
return ACT->getAssumptionCache(F);
|
|
|
|
};
|
|
|
|
return inlineCallsImpl(SCC, CG, GetAssumptionCache, PSI, TLI, InsertLifetime,
|
2016-07-23 06:22:50 +02:00
|
|
|
[this](CallSite CS) { return getInlineCost(CS); },
|
2017-02-10 00:11:52 +01:00
|
|
|
LegacyAARGetter(*this), ImportedFunctionsStats);
|
2016-07-23 06:22:50 +02:00
|
|
|
}
|
|
|
|
|
2015-03-10 17:42:24 +01:00
|
|
|
/// Remove now-dead linkonce functions at the end of
|
|
|
|
/// processing to avoid breaking the SCC traversal.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool LegacyInlinerBase::doFinalization(CallGraph &CG) {
|
Added ThinLTO inlining statistics
Summary:
copypasta doc of ImportedFunctionsInliningStatistics class
\brief Calculate and dump ThinLTO specific inliner stats.
The main statistics are:
(1) Number of inlined imported functions,
(2) Number of imported functions inlined into importing module (indirect),
(3) Number of non imported functions inlined into importing module
(indirect).
The difference between first and the second is that first stat counts
all performed inlines on imported functions, but the second one only the
functions that have been eventually inlined to a function in the importing
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is
possible to e.g. import function `A`, `B` and then inline `B` to `A`,
and after this `A` might be too big to be inlined into some other function
that calls it. It calculates this statistic by building graph, where
the nodes are functions, and edges are performed inlines and then by marking
the edges starting from not imported function.
If `Verbose` is set to true, then it also dumps statistics
per each inlined function, sorted by the greatest inlines count like
- number of performed inlines
- number of performed inlines to importing module
Reviewers: eraman, tejohnson, mehdi_amini
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D22491
llvm-svn: 277089
2016-07-29 02:27:16 +02:00
|
|
|
if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
|
|
|
|
ImportedFunctionsStats.dump(InlinerFunctionImportStats ==
|
|
|
|
InlinerFunctionImportStatsOpts::Verbose);
|
2008-11-05 02:39:16 +01:00
|
|
|
return removeDeadFunctions(CG);
|
|
|
|
}
|
|
|
|
|
2015-03-10 17:42:24 +01:00
|
|
|
/// Remove dead functions that are not included in DNR (Do Not Remove) list.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool LegacyInlinerBase::removeDeadFunctions(CallGraph &CG,
|
|
|
|
bool AlwaysInlineOnly) {
|
2016-08-03 03:02:31 +02:00
|
|
|
SmallVector<CallGraphNode *, 16> FunctionsToRemove;
|
2016-12-27 00:43:27 +01:00
|
|
|
SmallVector<Function *, 16> DeadFunctionsInComdats;
|
2015-05-05 22:14:22 +02:00
|
|
|
|
|
|
|
auto RemoveCGN = [&](CallGraphNode *CGN) {
|
|
|
|
// Remove any call graph edges from the function to its callees.
|
|
|
|
CGN->removeAllCalledFunctions();
|
|
|
|
|
|
|
|
// Remove any edges from the external node to the function's call graph
|
|
|
|
// node. These edges might have been made irrelegant due to
|
|
|
|
// optimization of the program.
|
|
|
|
CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);
|
|
|
|
|
|
|
|
// Removing the node for callee from the call graph and delete it.
|
|
|
|
FunctionsToRemove.push_back(CGN);
|
|
|
|
};
|
2004-04-21 22:44:33 +02:00
|
|
|
|
|
|
|
// Scan for all of the functions, looking for ones that should now be removed
|
|
|
|
// from the program. Insert the dead ones in the FunctionsToRemove set.
|
2015-08-05 22:55:50 +02:00
|
|
|
for (const auto &I : CG) {
|
|
|
|
CallGraphNode *CGN = I.second.get();
|
2009-08-27 05:51:50 +02:00
|
|
|
Function *F = CGN->getFunction();
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
llvm-svn: 152903
2012-03-16 07:10:13 +01:00
|
|
|
if (!F || F->isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Handle the case when this function is called and we only want to care
|
|
|
|
// about always-inline functions. This is a bit of a hack to share code
|
|
|
|
// between here and the InlineAlways pass.
|
2015-02-14 02:11:29 +01:00
|
|
|
if (AlwaysInlineOnly && !F->hasFnAttribute(Attribute::AlwaysInline))
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
llvm-svn: 152903
2012-03-16 07:10:13 +01:00
|
|
|
continue;
|
|
|
|
|
2009-08-27 05:51:50 +02:00
|
|
|
// If the only remaining users of the function are dead constants, remove
|
|
|
|
// them.
|
|
|
|
F->removeDeadConstantUsers();
|
|
|
|
|
2011-10-20 07:23:42 +02:00
|
|
|
if (!F->isDefTriviallyDead())
|
2009-08-27 05:51:50 +02:00
|
|
|
continue;
|
2014-10-08 21:32:32 +02:00
|
|
|
|
|
|
|
// It is unsafe to drop a function with discardable linkage from a COMDAT
|
|
|
|
// without also dropping the other members of the COMDAT.
|
|
|
|
// The inliner doesn't visit non-function entities which are in COMDAT
|
|
|
|
// groups so it is unsafe to do so *unless* the linkage is local.
|
2015-05-05 22:14:22 +02:00
|
|
|
if (!F->hasLocalLinkage()) {
|
2016-12-27 00:43:27 +01:00
|
|
|
if (F->hasComdat()) {
|
|
|
|
DeadFunctionsInComdats.push_back(F);
|
2015-05-05 22:14:22 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2009-08-27 05:51:50 +02:00
|
|
|
|
2015-05-05 22:14:22 +02:00
|
|
|
RemoveCGN(CGN);
|
|
|
|
}
|
|
|
|
if (!DeadFunctionsInComdats.empty()) {
|
2016-12-27 00:43:27 +01:00
|
|
|
// Filter out the functions whose comdats remain alive.
|
|
|
|
filterDeadComdatFunctions(CG.getModule(), DeadFunctionsInComdats);
|
|
|
|
// Remove the rest.
|
|
|
|
for (Function *F : DeadFunctionsInComdats)
|
|
|
|
RemoveCGN(CG[F]);
|
2004-04-21 00:06:53 +02:00
|
|
|
}
|
2015-05-05 22:14:22 +02:00
|
|
|
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
llvm-svn: 152903
2012-03-16 07:10:13 +01:00
|
|
|
if (FunctionsToRemove.empty())
|
|
|
|
return false;
|
2004-04-21 22:44:33 +02:00
|
|
|
|
|
|
|
// Now that we know which functions to delete, do so. We didn't want to do
|
|
|
|
// this inline, because that would invalidate our CallGraph::iterator
|
|
|
|
// objects. :(
|
2009-08-27 05:51:50 +02:00
|
|
|
//
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
llvm-svn: 152903
2012-03-16 07:10:13 +01:00
|
|
|
// Note that it doesn't matter that we are iterating over a non-stable order
|
2009-08-27 05:51:50 +02:00
|
|
|
// here to do this, it doesn't matter which order the functions are deleted
|
|
|
|
// in.
|
2012-04-01 12:41:24 +02:00
|
|
|
array_pod_sort(FunctionsToRemove.begin(), FunctionsToRemove.end());
|
2016-08-03 03:02:31 +02:00
|
|
|
FunctionsToRemove.erase(
|
|
|
|
std::unique(FunctionsToRemove.begin(), FunctionsToRemove.end()),
|
|
|
|
FunctionsToRemove.end());
|
2015-06-25 21:28:24 +02:00
|
|
|
for (CallGraphNode *CGN : FunctionsToRemove) {
|
2016-03-08 01:36:35 +01:00
|
|
|
delete CG.removeFunctionFromModule(CGN);
|
2004-04-21 22:44:33 +02:00
|
|
|
++NumDeleted;
|
|
|
|
}
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
llvm-svn: 152903
2012-03-16 07:10:13 +01:00
|
|
|
return true;
|
2004-04-21 00:06:53 +02:00
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
2018-06-28 22:07:47 +02:00
|
|
|
InlinerPass::~InlinerPass() {
|
|
|
|
if (ImportedFunctionsStats) {
|
|
|
|
assert(InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No);
|
|
|
|
ImportedFunctionsStats->dump(InlinerFunctionImportStats ==
|
|
|
|
InlinerFunctionImportStatsOpts::Verbose);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
|
|
|
|
CGSCCAnalysisManager &AM, LazyCallGraph &CG,
|
|
|
|
CGSCCUpdateResult &UR) {
|
|
|
|
const ModuleAnalysisManager &MAM =
|
|
|
|
AM.getResult<ModuleAnalysisManagerCGSCCProxy>(InitialC, CG).getManager();
|
|
|
|
bool Changed = false;
|
|
|
|
|
|
|
|
assert(InitialC.size() > 0 && "Cannot handle an empty SCC!");
|
|
|
|
Module &M = *InitialC.begin()->getFunction().getParent();
|
|
|
|
ProfileSummaryInfo *PSI = MAM.getCachedResult<ProfileSummaryAnalysis>(M);
|
|
|
|
|
2018-06-28 22:07:47 +02:00
|
|
|
if (!ImportedFunctionsStats &&
|
|
|
|
InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) {
|
|
|
|
ImportedFunctionsStats =
|
|
|
|
llvm::make_unique<ImportedFunctionsInliningStatistics>();
|
|
|
|
ImportedFunctionsStats->setModuleInfo(M);
|
|
|
|
}
|
|
|
|
|
[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 12:35:40 +01:00
|
|
|
// We use a single common worklist for calls across the entire SCC. We
|
|
|
|
// process these in-order and append new calls introduced during inlining to
|
|
|
|
// the end.
|
|
|
|
//
|
|
|
|
// Note that this particular order of processing is actually critical to
|
|
|
|
// avoid very bad behaviors. Consider *highly connected* call graphs where
|
|
|
|
// each function contains a small amonut of code and a couple of calls to
|
|
|
|
// other functions. Because the LLVM inliner is fundamentally a bottom-up
|
|
|
|
// inliner, it can handle gracefully the fact that these all appear to be
|
|
|
|
// reasonable inlining candidates as it will flatten things until they become
|
|
|
|
// too big to inline, and then move on and flatten another batch.
|
|
|
|
//
|
|
|
|
// However, when processing call edges *within* an SCC we cannot rely on this
|
|
|
|
// bottom-up behavior. As a consequence, with heavily connected *SCCs* of
|
|
|
|
// functions we can end up incrementally inlining N calls into each of
|
|
|
|
// N functions because each incremental inlining decision looks good and we
|
|
|
|
// don't have a topological ordering to prevent explosions.
|
|
|
|
//
|
|
|
|
// To compensate for this, we don't process transitive edges made immediate
|
|
|
|
// by inlining until we've done one pass of inlining across the entire SCC.
|
|
|
|
// Large, highly connected SCCs still lead to some amount of code bloat in
|
|
|
|
// this model, but it is uniformly spread across all the functions in the SCC
|
|
|
|
// and eventually they all become too large to inline, rather than
|
|
|
|
// incrementally maknig a single function grow in a super linear fashion.
|
|
|
|
SmallVector<std::pair<CallSite, int>, 16> Calls;
|
|
|
|
|
2018-05-08 03:45:46 +02:00
|
|
|
FunctionAnalysisManager &FAM =
|
|
|
|
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(InitialC, CG)
|
|
|
|
.getManager();
|
|
|
|
|
[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 12:35:40 +01:00
|
|
|
// Populate the initial list of calls in this SCC.
|
|
|
|
for (auto &N : InitialC) {
|
2018-05-08 03:45:46 +02:00
|
|
|
auto &ORE =
|
|
|
|
FAM.getResult<OptimizationRemarkEmitterAnalysis>(N.getFunction());
|
[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 12:35:40 +01:00
|
|
|
// We want to generally process call sites top-down in order for
|
|
|
|
// simplifications stemming from replacing the call with the returned value
|
|
|
|
// after inlining to be visible to subsequent inlining decisions.
|
|
|
|
// FIXME: Using instructions sequence is a really bad way to do this.
|
|
|
|
// Instead we should do an actual RPO walk of the function body.
|
|
|
|
for (Instruction &I : instructions(N.getFunction()))
|
|
|
|
if (auto CS = CallSite(&I))
|
2018-05-08 03:45:46 +02:00
|
|
|
if (Function *Callee = CS.getCalledFunction()) {
|
[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 12:35:40 +01:00
|
|
|
if (!Callee->isDeclaration())
|
|
|
|
Calls.push_back({CS, -1});
|
2018-05-08 03:45:46 +02:00
|
|
|
else if (!isa<IntrinsicInst>(I)) {
|
|
|
|
using namespace ore;
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, "unavailable definition");
|
2018-05-08 03:45:46 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
|
|
|
|
<< NV("Callee", Callee) << " will not be inlined into "
|
|
|
|
<< NV("Caller", CS.getCaller())
|
|
|
|
<< " because its definition is unavailable"
|
|
|
|
<< setIsVerbose();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
[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 12:35:40 +01:00
|
|
|
}
|
|
|
|
if (Calls.empty())
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
|
|
|
|
// Capture updatable variables for the current SCC and RefSCC.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
auto *C = &InitialC;
|
|
|
|
auto *RC = &C->getOuterRefSCC();
|
|
|
|
|
2016-12-27 07:46:20 +01:00
|
|
|
// When inlining a callee produces new call sites, we want to keep track of
|
|
|
|
// the fact that they were inlined from the callee. This allows us to avoid
|
|
|
|
// infinite inlining in some obscure cases. To represent this, we use an
|
|
|
|
// index into the InlineHistory vector.
|
|
|
|
SmallVector<std::pair<Function *, int>, 16> InlineHistory;
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
|
|
|
// Track a set vector of inlined callees so that we can augment the caller
|
|
|
|
// with all of their edges in the call graph before pruning out the ones that
|
|
|
|
// got simplified away.
|
|
|
|
SmallSetVector<Function *, 4> InlinedCallees;
|
|
|
|
|
|
|
|
// Track the dead functions to delete once finished with inlining calls. We
|
|
|
|
// defer deleting these to make it easier to handle the call graph updates.
|
|
|
|
SmallVector<Function *, 4> DeadFunctions;
|
|
|
|
|
[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 12:35:40 +01:00
|
|
|
// Loop forward over all of the calls. Note that we cannot cache the size as
|
|
|
|
// inlining can introduce new calls that need to be processed.
|
|
|
|
for (int i = 0; i < (int)Calls.size(); ++i) {
|
|
|
|
// We expect the calls to typically be batched with sequences of calls that
|
|
|
|
// have the same caller, so we first set up some shared infrastructure for
|
|
|
|
// this caller. We also do any pruning we can at this layer on the caller
|
|
|
|
// alone.
|
|
|
|
Function &F = *Calls[i].first.getCaller();
|
|
|
|
LazyCallGraph::Node &N = *CG.lookup(F);
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
if (CG.lookupSCC(N) != C)
|
|
|
|
continue;
|
2019-04-05 00:40:06 +02:00
|
|
|
if (F.hasOptNone()) {
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(Calls[i].first, "optnone attribute");
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
continue;
|
2018-08-28 17:27:25 +02:00
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Inlining calls in: " << F.getName() << "\n");
|
2017-01-22 11:33:58 +01:00
|
|
|
|
2017-01-22 11:34:01 +01:00
|
|
|
// Get a FunctionAnalysisManager via a proxy for this particular node. We
|
|
|
|
// do this each time we visit a node as the SCC may have changed and as
|
|
|
|
// we're going to mutate this particular function we want to make sure the
|
|
|
|
// proxy is in place to forward any invalidation events. We can use the
|
|
|
|
// manager we get here for looking up results for functions other than this
|
|
|
|
// node however because those functions aren't going to be mutated by this
|
|
|
|
// pass.
|
|
|
|
FunctionAnalysisManager &FAM =
|
|
|
|
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(*C, CG)
|
|
|
|
.getManager();
|
2017-08-21 22:00:09 +02:00
|
|
|
|
|
|
|
// Get the remarks emission analysis for the caller.
|
|
|
|
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
|
|
|
|
|
2017-01-22 11:34:01 +01:00
|
|
|
std::function<AssumptionCache &(Function &)> GetAssumptionCache =
|
|
|
|
[&](Function &F) -> AssumptionCache & {
|
|
|
|
return FAM.getResult<AssumptionAnalysis>(F);
|
|
|
|
};
|
|
|
|
auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & {
|
|
|
|
return FAM.getResult<BlockFrequencyAnalysis>(F);
|
|
|
|
};
|
|
|
|
|
|
|
|
auto GetInlineCost = [&](CallSite CS) {
|
|
|
|
Function &Callee = *CS.getCalledFunction();
|
|
|
|
auto &CalleeTTI = FAM.getResult<TargetIRAnalysis>(Callee);
|
2019-02-21 03:57:52 +01:00
|
|
|
bool RemarksEnabled =
|
|
|
|
Callee.getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled(
|
|
|
|
DEBUG_TYPE);
|
2017-01-22 11:34:01 +01:00
|
|
|
return getInlineCost(CS, Params, CalleeTTI, GetAssumptionCache, {GetBFI},
|
2019-02-21 03:57:52 +01:00
|
|
|
PSI, RemarksEnabled ? &ORE : nullptr);
|
2017-01-22 11:34:01 +01:00
|
|
|
};
|
|
|
|
|
[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 12:35:40 +01:00
|
|
|
// Now process as many calls as we have within this caller in the sequnece.
|
|
|
|
// We bail out as soon as the caller has to change so we can update the
|
|
|
|
// call graph and prepare the context of that new caller.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
bool DidInline = false;
|
[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 12:35:40 +01:00
|
|
|
for (; i < (int)Calls.size() && Calls[i].first.getCaller() == &F; ++i) {
|
2016-12-27 07:46:20 +01:00
|
|
|
int InlineHistoryID;
|
|
|
|
CallSite CS;
|
[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 12:35:40 +01:00
|
|
|
std::tie(CS, InlineHistoryID) = Calls[i];
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
Function &Callee = *CS.getCalledFunction();
|
|
|
|
|
2016-12-27 07:46:20 +01:00
|
|
|
if (InlineHistoryID != -1 &&
|
2018-08-28 17:27:25 +02:00
|
|
|
InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) {
|
|
|
|
setInlineRemark(CS, "recursive");
|
2016-12-27 07:46:20 +01:00
|
|
|
continue;
|
2018-08-28 17:27:25 +02:00
|
|
|
}
|
2016-12-27 07:46:20 +01:00
|
|
|
|
2017-08-02 04:09:22 +02:00
|
|
|
// Check if this inlining may repeat breaking an SCC apart that has
|
|
|
|
// already been split once before. In that case, inlining here may
|
|
|
|
// trigger infinite inlining, much like is prevented within the inliner
|
|
|
|
// itself by the InlineHistory above, but spread across CGSCC iterations
|
|
|
|
// and thus hidden from the full inline history.
|
|
|
|
if (CG.lookupSCC(*CG.lookup(Callee)) == C &&
|
|
|
|
UR.InlinedInternalEdges.count({&N, C})) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Skipping inlining internal SCC edge from a node "
|
|
|
|
"previously split out of this SCC by inlining: "
|
|
|
|
<< F.getName() << " -> " << Callee.getName() << "\n");
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, "recursive SCC split");
|
2017-08-02 04:09:22 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-08-21 18:45:47 +02:00
|
|
|
Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE);
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
// Check whether we want to inline this callsite.
|
2018-08-28 17:27:25 +02:00
|
|
|
if (!OIC.hasValue()) {
|
|
|
|
setInlineRemark(CS, "deferred");
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
continue;
|
2018-08-28 17:27:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!OIC.getValue()) {
|
|
|
|
// shouldInline() call returned a negative inline cost that explains
|
|
|
|
// why this callsite should not be inlined.
|
|
|
|
setInlineRemark(CS, inlineCostStr(*OIC));
|
|
|
|
continue;
|
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
2017-01-20 23:44:04 +01:00
|
|
|
// Setup the data structure used to plumb customization into the
|
|
|
|
// `InlineFunction` routine.
|
|
|
|
InlineFunctionInfo IFI(
|
2017-05-10 01:21:10 +02:00
|
|
|
/*cg=*/nullptr, &GetAssumptionCache, PSI,
|
2017-01-20 23:44:04 +01:00
|
|
|
&FAM.getResult<BlockFrequencyAnalysis>(*(CS.getCaller())),
|
|
|
|
&FAM.getResult<BlockFrequencyAnalysis>(Callee));
|
|
|
|
|
2017-08-21 18:45:47 +02:00
|
|
|
// Get DebugLoc to report. CS will be invalid after Inliner.
|
|
|
|
DebugLoc DLoc = CS->getDebugLoc();
|
|
|
|
BasicBlock *Block = CS.getParent();
|
|
|
|
|
|
|
|
using namespace ore;
|
2017-10-19 23:21:30 +02:00
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
InlineResult IR = InlineFunction(CS, IFI);
|
|
|
|
if (!IR) {
|
2018-08-28 17:27:25 +02:00
|
|
|
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
|
2017-10-11 19:12:59 +02:00
|
|
|
ORE.emit([&]() {
|
|
|
|
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
|
|
|
|
<< NV("Callee", &Callee) << " will not be inlined into "
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
<< NV("Caller", &F) << ": " << NV("Reason", IR.message);
|
2017-10-11 19:12:59 +02:00
|
|
|
});
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
continue;
|
2017-08-21 18:45:47 +02:00
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
DidInline = true;
|
|
|
|
InlinedCallees.insert(&Callee);
|
|
|
|
|
2018-08-14 17:19:14 +02:00
|
|
|
++NumInlined;
|
|
|
|
|
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338969
2018-08-05 16:53:08 +02:00
|
|
|
emit_inlined_into(ORE, DLoc, Block, Callee, F, *OIC);
|
2017-08-21 18:45:47 +02:00
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
// Add any new callsites to defined functions to the worklist.
|
2016-12-27 07:46:20 +01:00
|
|
|
if (!IFI.InlinedCallSites.empty()) {
|
|
|
|
int NewHistoryID = InlineHistory.size();
|
|
|
|
InlineHistory.push_back({&Callee, InlineHistoryID});
|
|
|
|
for (CallSite &CS : reverse(IFI.InlinedCallSites))
|
|
|
|
if (Function *NewCallee = CS.getCalledFunction())
|
|
|
|
if (!NewCallee->isDeclaration())
|
|
|
|
Calls.push_back({CS, NewHistoryID});
|
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
2018-06-28 22:07:47 +02:00
|
|
|
if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
|
|
|
|
ImportedFunctionsStats->recordInline(F, Callee);
|
|
|
|
|
2016-12-27 04:39:54 +01:00
|
|
|
// Merge the attributes based on the inlining.
|
|
|
|
AttributeFuncs::mergeAttributesForInlining(F, Callee);
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
// For local functions, check whether this makes the callee trivially
|
|
|
|
// dead. In that case, we can drop the body of the function eagerly
|
|
|
|
// which may reduce the number of callers of other functions to one,
|
|
|
|
// changing inline cost thresholds.
|
|
|
|
if (Callee.hasLocalLinkage()) {
|
|
|
|
// To check this we also need to nuke any dead constant uses (perhaps
|
|
|
|
// made dead by this operation on other functions).
|
|
|
|
Callee.removeDeadConstantUsers();
|
2017-07-19 06:12:25 +02:00
|
|
|
if (Callee.use_empty() && !CG.isLibFunction(Callee)) {
|
2017-03-16 11:45:42 +01:00
|
|
|
Calls.erase(
|
|
|
|
std::remove_if(Calls.begin() + i + 1, Calls.end(),
|
|
|
|
[&Callee](const std::pair<CallSite, int> &Call) {
|
|
|
|
return Call.first.getCaller() == &Callee;
|
|
|
|
}),
|
|
|
|
Calls.end());
|
2017-01-24 13:55:57 +01:00
|
|
|
// Clear the body and queue the function itself for deletion when we
|
|
|
|
// finish inlining and call graph updates.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
// Note that after this point, it is an error to do anything other
|
|
|
|
// than use the callee's address or delete it.
|
|
|
|
Callee.dropAllReferences();
|
|
|
|
assert(find(DeadFunctions, &Callee) == DeadFunctions.end() &&
|
|
|
|
"Cannot put cause a function to become dead twice!");
|
|
|
|
DeadFunctions.push_back(&Callee);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[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 12:35:40 +01:00
|
|
|
// Back the call index up by one to put us in a good position to go around
|
|
|
|
// the outer loop.
|
|
|
|
--i;
|
|
|
|
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
if (!DidInline)
|
|
|
|
continue;
|
|
|
|
Changed = true;
|
|
|
|
|
2016-12-28 04:13:12 +01:00
|
|
|
// Add all the inlined callees' edges as ref edges to the caller. These are
|
|
|
|
// by definition trivial edges as we always have *some* transitive ref edge
|
|
|
|
// chain. While in some cases these edges are direct calls inside the
|
|
|
|
// callee, they have to be modeled in the inliner as reference edges as
|
|
|
|
// there may be a reference edge anywhere along the chain from the current
|
|
|
|
// caller to the callee that causes the whole thing to appear like
|
|
|
|
// a (transitive) reference edge that will require promotion to a call edge
|
|
|
|
// below.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
for (Function *InlinedCallee : InlinedCallees) {
|
|
|
|
LazyCallGraph::Node &CalleeN = *CG.lookup(*InlinedCallee);
|
[PM/LCG] Teach the LazyCallGraph how to replace a function without
disturbing the graph or having to update edges.
This is motivated by porting argument promotion to the new pass manager.
Because of how LLVM IR Function objects work, in order to change their
signature a new object needs to be created. This is efficient and
straight forward in the IR but previously was very hard to implement in
LCG. We could easily replace the function a node in the graph
represents. The challenging part is how to handle updating the edges in
the graph.
LCG previously used an edge to a raw function to represent a node that
had not yet been scanned for calls and references. This was the core
of its laziness. However, that model causes this kind of update to be
very hard:
1) The keys to lookup an edge need to be `Function*`s that would all
need to be updated when we update the node.
2) There will be some unknown number of edges that haven't transitioned
from `Function*` edges to `Node*` edges.
All of this complexity isn't necessary. Instead, we can always build
a node around any function, always pointing edges at it and always using
it as the key to lookup an edge. To maintain the laziness, we need to
sink the *edges* of a node into a secondary object and explicitly model
transitioning a node from empty to populated by scanning the function.
This design seems much cleaner in a number of ways, but importantly
there is now exactly *one* place where the `Function*` has to be
updated!
Some other cleanups that fall out of this include having something to
model the *entry* edges more accurately. Rather than hand rolling parts
of the node in the graph itself, we have an explicit `EdgeSequence`
object that gives us exactly the functionality needed. We also have
a consistent place to define the edge iterators and can use them for
both the entry edges and the internal edges of the graph.
The API used to model the separation between a node and its edges is
intentionally very thin as most clients are expected to deal with nodes
that have populated edges. We model this exactly as an optional does
with an additional method to populate the edges when that is
a reasonable thing for a client to do. This is based on API design
suggestions from Richard Smith and David Blaikie, credit goes to them
for helping pick how to model this without it being either too explicit
or too implicit.
The patch is somewhat noisy due to shifting around iterator types and
new syntax for walking the edges of a node, but most of the
functionality change is in the `Edge`, `EdgeSequence`, and `Node` types.
Differential Revision: https://reviews.llvm.org/D29577
llvm-svn: 294653
2017-02-10 00:24:13 +01:00
|
|
|
for (LazyCallGraph::Edge &E : *CalleeN)
|
|
|
|
RC->insertTrivialRefEdge(N, E.getNode());
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, since we have made changes we have at least removed
|
|
|
|
// a call instruction. However, in the process we do some incremental
|
|
|
|
// simplification of the surrounding code. This simplification can
|
|
|
|
// essentially do all of the same things as a function pass and we can
|
|
|
|
// re-use the exact same logic for updating the call graph to reflect the
|
2017-08-02 04:09:22 +02:00
|
|
|
// change.
|
|
|
|
LazyCallGraph::SCC *OldC = C;
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
C = &updateCGAndAnalysisManagerForFunctionPass(CG, *C, N, AM, UR);
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Updated inlining SCC: " << *C << "\n");
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
RC = &C->getOuterRefSCC();
|
2017-08-02 04:09:22 +02:00
|
|
|
|
|
|
|
// If this causes an SCC to split apart into multiple smaller SCCs, there
|
|
|
|
// is a subtle risk we need to prepare for. Other transformations may
|
|
|
|
// expose an "infinite inlining" opportunity later, and because of the SCC
|
|
|
|
// mutation, we will revisit this function and potentially re-inline. If we
|
|
|
|
// do, and that re-inlining also has the potentially to mutate the SCC
|
|
|
|
// structure, the infinite inlining problem can manifest through infinite
|
|
|
|
// SCC splits and merges. To avoid this, we capture the originating caller
|
|
|
|
// node and the SCC containing the call edge. This is a slight over
|
|
|
|
// approximation of the possible inlining decisions that must be avoided,
|
2018-10-24 01:29:45 +02:00
|
|
|
// but is relatively efficient to store. We use C != OldC to know when
|
|
|
|
// a new SCC is generated and the original SCC may be generated via merge
|
|
|
|
// in later iterations.
|
|
|
|
//
|
|
|
|
// It is also possible that even if no new SCC is generated
|
|
|
|
// (i.e., C == OldC), the original SCC could be split and then merged
|
|
|
|
// into the same one as itself. and the original SCC will be added into
|
|
|
|
// UR.CWorklist again, we want to catch such cases too.
|
|
|
|
//
|
2017-08-02 04:09:22 +02:00
|
|
|
// FIXME: This seems like a very heavyweight way of retaining the inline
|
|
|
|
// history, we should look for a more efficient way of tracking it.
|
2018-10-24 01:29:45 +02:00
|
|
|
if ((C != OldC || UR.CWorklist.count(OldC)) &&
|
|
|
|
llvm::any_of(InlinedCallees, [&](Function *Callee) {
|
2017-08-02 04:09:22 +02:00
|
|
|
return CG.lookupSCC(*CG.lookup(*Callee)) == OldC;
|
|
|
|
})) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Inlined an internal call edge and split an SCC, "
|
|
|
|
"retaining this to avoid infinite inlining.\n");
|
2017-08-02 04:09:22 +02:00
|
|
|
UR.InlinedInternalEdges.insert({&N, OldC});
|
|
|
|
}
|
|
|
|
InlinedCallees.clear();
|
[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 12:35:40 +01:00
|
|
|
}
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
|
|
|
|
// Now that we've finished inlining all of the calls across this SCC, delete
|
|
|
|
// all of the trivially dead functions, updating the call graph and the CGSCC
|
|
|
|
// pass manager in the process.
|
|
|
|
//
|
|
|
|
// Note that this walks a pointer set which has non-deterministic order but
|
|
|
|
// that is OK as all we do is delete things and add pointers to unordered
|
|
|
|
// sets.
|
|
|
|
for (Function *DeadF : DeadFunctions) {
|
|
|
|
// Get the necessary information out of the call graph and nuke the
|
2017-01-24 13:55:57 +01:00
|
|
|
// function there. Also, cclear out any cached analyses.
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
auto &DeadC = *CG.lookupSCC(*CG.lookup(*DeadF));
|
2017-01-24 13:55:57 +01:00
|
|
|
FunctionAnalysisManager &FAM =
|
|
|
|
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(DeadC, CG)
|
|
|
|
.getManager();
|
2017-09-28 04:45:42 +02:00
|
|
|
FAM.clear(*DeadF, DeadF->getName());
|
|
|
|
AM.clear(DeadC, DeadC.getName());
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
auto &DeadRC = DeadC.getOuterRefSCC();
|
|
|
|
CG.removeDeadFunction(*DeadF);
|
|
|
|
|
|
|
|
// Mark the relevant parts of the call graph as invalid so we don't visit
|
|
|
|
// them.
|
|
|
|
UR.InvalidatedSCCs.insert(&DeadC);
|
|
|
|
UR.InvalidatedRefSCCs.insert(&DeadRC);
|
|
|
|
|
|
|
|
// And delete the actual function from the module.
|
|
|
|
M.getFunctionList().erase(DeadF);
|
2018-08-14 17:19:14 +02:00
|
|
|
++NumDeleted;
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
}
|
[PM] Finish implementing and fix a chain of bugs uncovered by testing
the invalidation propagation logic from an SCC to a Function.
I wrote the infrastructure to test this but didn't actually use it in
the unit test where it was designed to be used. =[ My bad. Once
I actually added it to the test case I discovered that it also hadn't
been properly implemented, so I've implemented it. The logic in the FAM
proxy for an SCC pass to propagate invalidation follows the same ideas
as the FAM proxy for a Module pass, but the implementation is a bit
different to reflect the fact that it is forwarding just for an SCC.
However, implementing this correctly uncovered a surprising "bug" (it
was conservatively correct but relatively very expensive) in how we
handle invalidation when splitting one SCC into multiple SCCs. We did an
eager invalidation when in reality we should be deferring invaliadtion
for the *current* SCC to the CGSCC pass manager and just invaliating the
newly constructed SCCs. Otherwise we end up invalidating too much too
soon. This was exposed by the inliner test case that I've updated. Now,
we invalidate *just* the split off '(test1_f)' SCC when doing the CG
update, and then the inliner finishes and invalidates the '(test1_g,
test1_h)' SCC's analyses. The first few attempts at fixing this hit
still more bugs, but all of those are covered by existing tests. For
example, the inliner should also preserve the FAM proxy to avoid
unnecesasry invalidation, and this is safe because the CG update
routines it uses handle any necessary adjustments to the FAM proxy.
Finally, the unittests for the CGSCC pass manager needed a bunch of
updates where we weren't correctly preserving the FAM proxy because it
hadn't been fully implemented and failing to preserve it didn't matter.
Note that this doesn't yet fix the current crasher due to MemSSA finding
a stale dominator tree, but without this the fix to that crasher doesn't
really make any sense when testing because it relies on the proxy
behavior.
llvm-svn: 307487
2017-07-09 05:59:31 +02:00
|
|
|
|
|
|
|
if (!Changed)
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
|
|
|
|
// Even if we change the IR, we update the core CGSCC data structures and so
|
|
|
|
// can preserve the proxy to the function analysis manager.
|
|
|
|
PreservedAnalyses PA;
|
|
|
|
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
|
|
|
|
return PA;
|
[PM] Provide an initial, minimal port of the inliner to the new pass manager.
This doesn't implement *every* feature of the existing inliner, but
tries to implement the most important ones for building a functional
optimization pipeline and beginning to sort out bugs, regressions, and
other problems.
Notable, but intentional omissions:
- No alloca merging support. Why? Because it isn't clear we want to do
this at all. Active discussion and investigation is going on to remove
it, so for simplicity I omitted it.
- No support for trying to iterate on "internally" devirtualized calls.
Why? Because it adds what I suspect is inappropriate coupling for
little or no benefit. We will have an outer iteration system that
tracks devirtualization including that from function passes and
iterates already. We should improve that rather than approximate it
here.
- Optimization remarks. Why? Purely to make the patch smaller, no other
reason at all.
The last one I'll probably work on almost immediately. But I wanted to
skip it in the initial patch to try to focus the change as much as
possible as there is already a lot of code moving around and both of
these *could* be skipped without really disrupting the core logic.
A summary of the different things happening here:
1) Adding the usual new PM class and rigging.
2) Fixing minor underlying assumptions in the inline cost analysis or
inline logic that don't generally hold in the new PM world.
3) Adding the core pass logic which is in essence a loop over the calls
in the nodes in the call graph. This is a bit duplicated from the old
inliner, but only a handful of lines could realistically be shared.
(I tried at first, and it really didn't help anything.) All told,
this is only about 100 lines of code, and most of that is the
mechanics of wiring up analyses from the new PM world.
4) Updating the LazyCallGraph (in the new PM) based on the *newly
inlined* calls and references. This is very minimal because we cannot
form cycles.
5) When inlining removes the last use of a function, eagerly nuking the
body of the function so that any "one use remaining" inline cost
heuristics are immediately refined, and queuing these functions to be
completely deleted once inlining is complete and the call graph
updated to reflect that they have become dead.
6) After all the inlining for a particular function, updating the
LazyCallGraph and the CGSCC pass manager to reflect the
function-local simplifications that are done immediately and
internally by the inline utilties. These are the exact same
fundamental set of CG updates done by arbitrary function passes.
7) Adding a bunch of test cases to specifically target CGSCC and other
subtle aspects in the new PM world.
Many thanks to the careful review from Easwaran and Sanjoy and others!
Differential Revision: https://reviews.llvm.org/D24226
llvm-svn: 290161
2016-12-20 04:15:32 +01:00
|
|
|
}
|