Skip to content

Commit 7f6f9f4

Browse files
committed
[NewPM] Make pass adaptors less templatey
Currently PassBuilder.cpp is by far the file that takes longest to compile. This is due to tons of templates being instantiated per pass. Follow PassManager by using wrappers around passes to avoid making the adaptors templated on the pass type. This allows us to move various adaptors' run methods into .cpp files. This reduces the compile time of PassBuilder.cpp on my machine from 66 to 39 seconds. It also reduces the size of opt from 685M to 676M. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D92616
1 parent f628eef commit 7f6f9f4

File tree

8 files changed

+724
-695
lines changed

8 files changed

+724
-695
lines changed

Diff for: llvm/include/llvm/Analysis/CGSCCPassManager.h

+41-477
Large diffs are not rendered by default.

Diff for: llvm/include/llvm/IR/PassManager.h

+13-52
Original file line numberDiff line numberDiff line change
@@ -1228,73 +1228,34 @@ using ModuleAnalysisManagerFunctionProxy =
12281228
/// Note that although function passes can access module analyses, module
12291229
/// analyses are not invalidated while the function passes are running, so they
12301230
/// may be stale. Function analyses will not be stale.
1231-
template <typename FunctionPassT>
12321231
class ModuleToFunctionPassAdaptor
1233-
: public PassInfoMixin<ModuleToFunctionPassAdaptor<FunctionPassT>> {
1232+
: public PassInfoMixin<ModuleToFunctionPassAdaptor> {
12341233
public:
1235-
explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass)
1234+
using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
1235+
1236+
explicit ModuleToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass)
12361237
: Pass(std::move(Pass)) {}
12371238

12381239
/// Runs the function pass across every function in the module.
1239-
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
1240-
FunctionAnalysisManager &FAM =
1241-
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
1242-
1243-
// Request PassInstrumentation from analysis manager, will use it to run
1244-
// instrumenting callbacks for the passes later.
1245-
PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M);
1246-
1247-
PreservedAnalyses PA = PreservedAnalyses::all();
1248-
for (Function &F : M) {
1249-
if (F.isDeclaration())
1250-
continue;
1251-
1252-
// Check the PassInstrumentation's BeforePass callbacks before running the
1253-
// pass, skip its execution completely if asked to (callback returns
1254-
// false).
1255-
if (!PI.runBeforePass<Function>(Pass, F))
1256-
continue;
1257-
1258-
PreservedAnalyses PassPA;
1259-
{
1260-
TimeTraceScope TimeScope(Pass.name(), F.getName());
1261-
PassPA = Pass.run(F, FAM);
1262-
}
1263-
1264-
PI.runAfterPass(Pass, F, PassPA);
1265-
1266-
// We know that the function pass couldn't have invalidated any other
1267-
// function's analyses (that's the contract of a function pass), so
1268-
// directly handle the function analysis manager's invalidation here.
1269-
FAM.invalidate(F, PassPA);
1270-
1271-
// Then intersect the preserved set so that invalidation of module
1272-
// analyses will eventually occur when the module pass completes.
1273-
PA.intersect(std::move(PassPA));
1274-
}
1275-
1276-
// The FunctionAnalysisManagerModuleProxy is preserved because (we assume)
1277-
// the function passes we ran didn't add or remove any functions.
1278-
//
1279-
// We also preserve all analyses on Functions, because we did all the
1280-
// invalidation we needed to do above.
1281-
PA.preserveSet<AllAnalysesOn<Function>>();
1282-
PA.preserve<FunctionAnalysisManagerModuleProxy>();
1283-
return PA;
1284-
}
1240+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
12851241

12861242
static bool isRequired() { return true; }
12871243

12881244
private:
1289-
FunctionPassT Pass;
1245+
std::unique_ptr<PassConceptT> Pass;
12901246
};
12911247

12921248
/// A function to deduce a function pass type and wrap it in the
12931249
/// templated adaptor.
12941250
template <typename FunctionPassT>
1295-
ModuleToFunctionPassAdaptor<FunctionPassT>
1251+
ModuleToFunctionPassAdaptor
12961252
createModuleToFunctionPassAdaptor(FunctionPassT Pass) {
1297-
return ModuleToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
1253+
using PassModelT =
1254+
detail::PassModel<Function, FunctionPassT, PreservedAnalyses,
1255+
FunctionAnalysisManager>;
1256+
1257+
return ModuleToFunctionPassAdaptor(
1258+
std::make_unique<PassModelT>(std::move(Pass)));
12981259
}
12991260

13001261
/// A utility pass template to force an analysis result to be available.

Diff for: llvm/include/llvm/Transforms/Scalar/LoopPassManager.h

+19-154
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "llvm/Transforms/Utils/LCSSA.h"
5757
#include "llvm/Transforms/Utils/LoopSimplify.h"
5858
#include "llvm/Transforms/Utils/LoopUtils.h"
59+
#include <memory>
5960

6061
namespace llvm {
6162

@@ -105,7 +106,7 @@ using RequireAnalysisLoopPass =
105106
RequireAnalysisPass<AnalysisT, Loop, LoopAnalysisManager,
106107
LoopStandardAnalysisResults &, LPMUpdater &>;
107108

108-
template <typename LoopPassT> class FunctionToLoopPassAdaptor;
109+
class FunctionToLoopPassAdaptor;
109110

110111
/// This class provides an interface for updating the loop pass manager based
111112
/// on mutations to the loop nest.
@@ -200,7 +201,7 @@ class LPMUpdater {
200201
}
201202

202203
private:
203-
template <typename LoopPassT> friend class llvm::FunctionToLoopPassAdaptor;
204+
friend class llvm::FunctionToLoopPassAdaptor;
204205

205206
/// The \c FunctionToLoopPassAdaptor's worklist of loops to process.
206207
SmallPriorityWorklist<Loop *, 4> &Worklist;
@@ -229,11 +230,15 @@ class LPMUpdater {
229230
/// FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy
230231
/// analysis prior to running the loop passes over the function to enable a \c
231232
/// LoopAnalysisManager to be used within this run safely.
232-
template <typename LoopPassT>
233233
class FunctionToLoopPassAdaptor
234-
: public PassInfoMixin<FunctionToLoopPassAdaptor<LoopPassT>> {
234+
: public PassInfoMixin<FunctionToLoopPassAdaptor> {
235235
public:
236-
explicit FunctionToLoopPassAdaptor(LoopPassT Pass, bool UseMemorySSA = false,
236+
using PassConceptT =
237+
detail::PassConcept<Loop, LoopAnalysisManager,
238+
LoopStandardAnalysisResults &, LPMUpdater &>;
239+
240+
explicit FunctionToLoopPassAdaptor(std::unique_ptr<PassConceptT> Pass,
241+
bool UseMemorySSA = false,
237242
bool UseBlockFrequencyInfo = false,
238243
bool DebugLogging = false)
239244
: Pass(std::move(Pass)), LoopCanonicalizationFPM(DebugLogging),
@@ -244,156 +249,12 @@ class FunctionToLoopPassAdaptor
244249
}
245250

246251
/// Runs the loop passes across every loop in the function.
247-
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
248-
// Before we even compute any loop analyses, first run a miniature function
249-
// pass pipeline to put loops into their canonical form. Note that we can
250-
// directly build up function analyses after this as the function pass
251-
// manager handles all the invalidation at that layer.
252-
PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(F);
253-
254-
PreservedAnalyses PA = PreservedAnalyses::all();
255-
// Check the PassInstrumentation's BeforePass callbacks before running the
256-
// canonicalization pipeline.
257-
if (PI.runBeforePass<Function>(LoopCanonicalizationFPM, F)) {
258-
PA = LoopCanonicalizationFPM.run(F, AM);
259-
PI.runAfterPass<Function>(LoopCanonicalizationFPM, F, PA);
260-
}
261-
262-
// Get the loop structure for this function
263-
LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
264-
265-
// If there are no loops, there is nothing to do here.
266-
if (LI.empty())
267-
return PA;
268-
269-
// Get the analysis results needed by loop passes.
270-
MemorySSA *MSSA = UseMemorySSA
271-
? (&AM.getResult<MemorySSAAnalysis>(F).getMSSA())
272-
: nullptr;
273-
BlockFrequencyInfo *BFI = UseBlockFrequencyInfo && F.hasProfileData()
274-
? (&AM.getResult<BlockFrequencyAnalysis>(F))
275-
: nullptr;
276-
LoopStandardAnalysisResults LAR = {AM.getResult<AAManager>(F),
277-
AM.getResult<AssumptionAnalysis>(F),
278-
AM.getResult<DominatorTreeAnalysis>(F),
279-
AM.getResult<LoopAnalysis>(F),
280-
AM.getResult<ScalarEvolutionAnalysis>(F),
281-
AM.getResult<TargetLibraryAnalysis>(F),
282-
AM.getResult<TargetIRAnalysis>(F),
283-
BFI,
284-
MSSA};
285-
286-
// Setup the loop analysis manager from its proxy. It is important that
287-
// this is only done when there are loops to process and we have built the
288-
// LoopStandardAnalysisResults object. The loop analyses cached in this
289-
// manager have access to those analysis results and so it must invalidate
290-
// itself when they go away.
291-
auto &LAMFP = AM.getResult<LoopAnalysisManagerFunctionProxy>(F);
292-
if (UseMemorySSA)
293-
LAMFP.markMSSAUsed();
294-
LoopAnalysisManager &LAM = LAMFP.getManager();
295-
296-
// A postorder worklist of loops to process.
297-
SmallPriorityWorklist<Loop *, 4> Worklist;
298-
299-
// Register the worklist and loop analysis manager so that loop passes can
300-
// update them when they mutate the loop nest structure.
301-
LPMUpdater Updater(Worklist, LAM);
302-
303-
// Add the loop nests in the reverse order of LoopInfo. See method
304-
// declaration.
305-
appendLoopsToWorklist(LI, Worklist);
306-
307-
#ifndef NDEBUG
308-
PI.pushBeforeNonSkippedPassCallback([&LAR, &LI](StringRef PassID, Any IR) {
309-
if (isSpecialPass(PassID, {"PassManager"}))
310-
return;
311-
assert(any_isa<const Loop *>(IR));
312-
const Loop *L = any_cast<const Loop *>(IR);
313-
assert(L && "Loop should be valid for printing");
314-
315-
// Verify the loop structure and LCSSA form before visiting the loop.
316-
L->verifyLoop();
317-
assert(L->isRecursivelyLCSSAForm(LAR.DT, LI) &&
318-
"Loops must remain in LCSSA form!");
319-
});
320-
#endif
321-
322-
do {
323-
Loop *L = Worklist.pop_back_val();
324-
325-
// Reset the update structure for this loop.
326-
Updater.CurrentL = L;
327-
Updater.SkipCurrentLoop = false;
328-
329-
#ifndef NDEBUG
330-
// Save a parent loop pointer for asserts.
331-
Updater.ParentL = L->getParentLoop();
332-
#endif
333-
// Check the PassInstrumentation's BeforePass callbacks before running the
334-
// pass, skip its execution completely if asked to (callback returns
335-
// false).
336-
if (!PI.runBeforePass<Loop>(Pass, *L))
337-
continue;
338-
339-
PreservedAnalyses PassPA;
340-
{
341-
TimeTraceScope TimeScope(Pass.name());
342-
PassPA = Pass.run(*L, LAM, LAR, Updater);
343-
}
344-
345-
// Do not pass deleted Loop into the instrumentation.
346-
if (Updater.skipCurrentLoop())
347-
PI.runAfterPassInvalidated<Loop>(Pass, PassPA);
348-
else
349-
PI.runAfterPass<Loop>(Pass, *L, PassPA);
350-
351-
// FIXME: We should verify the set of analyses relevant to Loop passes
352-
// are preserved.
353-
354-
// If the loop hasn't been deleted, we need to handle invalidation here.
355-
if (!Updater.skipCurrentLoop())
356-
// We know that the loop pass couldn't have invalidated any other
357-
// loop's analyses (that's the contract of a loop pass), so directly
358-
// handle the loop analysis manager's invalidation here.
359-
LAM.invalidate(*L, PassPA);
360-
361-
// Then intersect the preserved set so that invalidation of module
362-
// analyses will eventually occur when the module pass completes.
363-
PA.intersect(std::move(PassPA));
364-
} while (!Worklist.empty());
365-
366-
#ifndef NDEBUG
367-
PI.popBeforeNonSkippedPassCallback();
368-
#endif
369-
370-
// By definition we preserve the proxy. We also preserve all analyses on
371-
// Loops. This precludes *any* invalidation of loop analyses by the proxy,
372-
// but that's OK because we've taken care to invalidate analyses in the
373-
// loop analysis manager incrementally above.
374-
PA.preserveSet<AllAnalysesOn<Loop>>();
375-
PA.preserve<LoopAnalysisManagerFunctionProxy>();
376-
// We also preserve the set of standard analyses.
377-
PA.preserve<DominatorTreeAnalysis>();
378-
PA.preserve<LoopAnalysis>();
379-
PA.preserve<ScalarEvolutionAnalysis>();
380-
if (UseBlockFrequencyInfo && F.hasProfileData())
381-
PA.preserve<BlockFrequencyAnalysis>();
382-
if (UseMemorySSA)
383-
PA.preserve<MemorySSAAnalysis>();
384-
// FIXME: What we really want to do here is preserve an AA category, but
385-
// that concept doesn't exist yet.
386-
PA.preserve<AAManager>();
387-
PA.preserve<BasicAA>();
388-
PA.preserve<GlobalsAA>();
389-
PA.preserve<SCEVAA>();
390-
return PA;
391-
}
252+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
392253

393254
static bool isRequired() { return true; }
394255

395256
private:
396-
LoopPassT Pass;
257+
std::unique_ptr<PassConceptT> Pass;
397258

398259
FunctionPassManager LoopCanonicalizationFPM;
399260

@@ -404,12 +265,16 @@ class FunctionToLoopPassAdaptor
404265
/// A function to deduce a loop pass type and wrap it in the templated
405266
/// adaptor.
406267
template <typename LoopPassT>
407-
FunctionToLoopPassAdaptor<LoopPassT>
268+
FunctionToLoopPassAdaptor
408269
createFunctionToLoopPassAdaptor(LoopPassT Pass, bool UseMemorySSA = false,
409270
bool UseBlockFrequencyInfo = false,
410271
bool DebugLogging = false) {
411-
return FunctionToLoopPassAdaptor<LoopPassT>(
412-
std::move(Pass), UseMemorySSA, UseBlockFrequencyInfo, DebugLogging);
272+
using PassModelT =
273+
detail::PassModel<Loop, LoopPassT, PreservedAnalyses, LoopAnalysisManager,
274+
LoopStandardAnalysisResults &, LPMUpdater &>;
275+
return FunctionToLoopPassAdaptor(
276+
std::make_unique<PassModelT>(std::move(Pass)), UseMemorySSA,
277+
UseBlockFrequencyInfo, DebugLogging);
413278
}
414279

415280
/// Pass for printing a loop's contents as textual IR.

0 commit comments

Comments
 (0)