-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Analysis] Avoid running transform passes that have just been run #112092
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-coroutines Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds a new analysis pass to track a set of passes and their parameters to see if we can avoid running transform passes that have just been run. The current implementation only skips redundant InstCombine runs. I will add support for other passes in follow-up patches. Compile time improvement: http://llvm-compile-time-tracker.com/compare.php?from=76007138f4ffd4e0f510d12b5e8cad529c21f24d&to=64134cf07ea7eb39c60320087c0c5afdc16c3a2b&stat=instructions%3Au Patch is 24.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112092.diff 20 Files Affected:
diff --git a/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h b/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h
new file mode 100644
index 00000000000000..bd2520b22db903
--- /dev/null
+++ b/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h
@@ -0,0 +1,109 @@
+//===- LastRunTrackingAnalysis.h - Avoid running redundant pass -*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is an analysis pass to track a set of passes that have been run, so that
+// we can avoid running a pass again if there is no change since the last run of
+// the pass.
+//
+// In this pass we track a set of passes S for each function with the following
+// transition rules:
+// 1. If pass P make changes, set S = {P}.
+// 2. If pass P doesn't make changes, set S = S + {P}.
+//
+// Before running a pass P which satisfies P(P(x)) == P(x), we check if P is in
+// S. If so, we skip this pass since we know that there will be no change.
+//
+// Notes:
+// 1. Some transform passes have parameters that may vary in the optimization
+// pipeline. We should check if parameters in current run is compatible with
+// that in the last run.
+// 2. Module passes are specially handled. If a module pass make changes, we
+// clear all sets.
+// 3. This pass only tracks at the function level. Loop passes are not
+// supported for now.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
+#define LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/PassManager.h"
+#include <functional>
+
+namespace llvm {
+
+/// This class is used to track the last run of a set of module/function passes.
+/// Invalidation are conservatively handled by the pass manager if a pass
+/// doesn't explicitly preserve the result.
+/// If we want to skip a pass, we should define a unique ID \p PassID to
+/// identify the pass, which is usually a pointer to a static member. If a pass
+/// has parameters, they should be stored in a struct \p OptionT with a method
+/// bool isCompatibleWith(const OptionT& LastOpt) const to check compatibility.
+class LastRunTrackingInfo {
+public:
+ using PassID = const void *;
+ using OptionPtr = const void *;
+ // CompatibilityCheckFn is a closure that stores the parameters of last run.
+ using CompatibilityCheckFn = std::function<bool(OptionPtr)>;
+
+ /// Check if we should skip a pass.
+ /// \param ID The unique ID of the pass.
+ /// \param Opt The parameters of the pass. If the pass has no parameters, use
+ /// shouldSkip(PassID ID) instead.
+ /// \return True if we should skip the pass.
+ /// \sa shouldSkip(PassID ID)
+ template <typename OptionT>
+ bool shouldSkip(PassID ID, const OptionT &Opt) const {
+ return shouldSkipImpl(ID, &Opt);
+ }
+ bool shouldSkip(PassID ID) const { return shouldSkipImpl(ID, nullptr); }
+
+ /// Update the tracking info.
+ /// \param ID The unique ID of the pass.
+ /// \param Changed Whether the pass makes changes.
+ /// \param Opt The parameters of the pass. It must have the same type as the
+ /// parameters of the last run. If the pass has no parameters, use
+ /// update(PassID ID, bool Changed) instead.
+ /// \sa update(PassID ID, bool Changed)
+ template <typename OptionT>
+ void update(PassID ID, bool Changed, const OptionT &Opt) {
+ updateImpl(ID, Changed, [Opt](OptionPtr Ptr) {
+ return static_cast<const OptionT *>(Ptr)->isCompatibleWith(Opt);
+ });
+ }
+ void update(PassID ID, bool Changed) {
+ updateImpl(ID, Changed, CompatibilityCheckFn{});
+ }
+
+private:
+ bool shouldSkipImpl(PassID ID, OptionPtr Ptr) const;
+ void updateImpl(PassID ID, bool Changed, CompatibilityCheckFn CheckFn);
+
+ DenseMap<PassID, CompatibilityCheckFn> TrackedPasses;
+};
+
+/// A function/module analysis which provides an empty \c LastRunTrackingInfo.
+class LastRunTrackingAnalysis final
+ : public AnalysisInfoMixin<LastRunTrackingAnalysis> {
+ friend AnalysisInfoMixin<LastRunTrackingAnalysis>;
+ static AnalysisKey Key;
+
+public:
+ using Result = LastRunTrackingInfo;
+ LastRunTrackingInfo run(Function &F, FunctionAnalysisManager &) {
+ return LastRunTrackingInfo();
+ }
+ LastRunTrackingInfo run(Module &M, ModuleAnalysisManager &) {
+ return LastRunTrackingInfo();
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
index b4f0166239520a..5203f4cfeb976b 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
@@ -43,12 +43,20 @@ struct InstCombineOptions {
MaxIterations = Value;
return *this;
}
+
+ /// Only enable skipping in standard optimization pipeline.
+ bool isCompatibleWith(const InstCombineOptions &LastOption) const {
+ return !VerifyFixpoint && !LastOption.VerifyFixpoint &&
+ MaxIterations == InstCombineDefaultMaxIterations &&
+ LastOption.MaxIterations == InstCombineDefaultMaxIterations;
+ }
};
class InstCombinePass : public PassInfoMixin<InstCombinePass> {
private:
InstructionWorklist Worklist;
InstCombineOptions Options;
+ static char ID;
public:
explicit InstCombinePass(InstCombineOptions Opts = {});
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 393803fad89383..0db5b80f336cb5 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -79,6 +79,7 @@ add_llvm_component_library(LLVMAnalysis
InstructionPrecedenceTracking.cpp
InstructionSimplify.cpp
InteractiveModelRunner.cpp
+ LastRunTrackingAnalysis.cpp
LazyBranchProbabilityInfo.cpp
LazyBlockFrequencyInfo.cpp
LazyCallGraph.cpp
diff --git a/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp b/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp
new file mode 100644
index 00000000000000..9add9a598f2b03
--- /dev/null
+++ b/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp
@@ -0,0 +1,51 @@
+//===- LastRunTrackingAnalysis.cpp - Avoid running redundant pass -*- C++ -*-=//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is an analysis pass to track a set of passes that have been run, so that
+// we can avoid running a pass again if there is no change since the last run of
+// the pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "last-run-tracking"
+STATISTIC(NumSkippedPasses, "Number of skipped passes");
+STATISTIC(NumLRTQueries, "Number of LastRunTracking queries");
+
+static cl::opt<bool>
+ DisableLastRunTracking("disable-last-run-tracking", cl::Hidden,
+ cl::desc("Disable last run tracking"),
+ cl::init(false));
+
+bool LastRunTrackingInfo::shouldSkipImpl(PassID ID, OptionPtr Ptr) const {
+ if (DisableLastRunTracking)
+ return false;
+ ++NumLRTQueries;
+ auto Iter = TrackedPasses.find(ID);
+ if (Iter == TrackedPasses.end())
+ return false;
+ if (!Iter->second || Iter->second(Ptr)) {
+ ++NumSkippedPasses;
+ return true;
+ }
+ return false;
+}
+
+void LastRunTrackingInfo::updateImpl(PassID ID, bool Changed,
+ CompatibilityCheckFn CheckFn) {
+ if (Changed)
+ TrackedPasses.clear();
+ TrackedPasses[ID] = std::move(CheckFn);
+}
+
+AnalysisKey LastRunTrackingAnalysis::Key;
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f47f8ca35d7737..e515a86d1bf310 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -46,6 +46,7 @@
#include "llvm/Analysis/InlineAdvisor.h"
#include "llvm/Analysis/InlineSizeEstimatorAnalysis.h"
#include "llvm/Analysis/InstCount.h"
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Analysis/Lint.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 90859c18c4f499..55fb8135ddd41c 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -25,6 +25,7 @@ MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
MODULE_ANALYSIS("dxil-resource", DXILResourceAnalysis())
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
+MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
MODULE_ANALYSIS("module-summary", ModuleSummaryIndexAnalysis())
MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
@@ -285,6 +286,7 @@ FUNCTION_ANALYSIS(
MachineFunctionAnalysis(static_cast<const LLVMTargetMachine *>(TM)))
FUNCTION_ANALYSIS("gc-function", GCFunctionAnalysis())
FUNCTION_ANALYSIS("inliner-size-estimator", InlineSizeEstimatorAnalysis())
+FUNCTION_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis())
FUNCTION_ANALYSIS("loops", LoopAnalysis())
FUNCTION_ANALYSIS("memdep", MemoryDependenceAnalysis())
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 954c4cf19c2077..1a512cae7bf778 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -47,6 +47,7 @@
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
@@ -5538,8 +5539,15 @@ void InstCombinePass::printPipeline(
OS << '>';
}
+char InstCombinePass::ID = 0;
+
PreservedAnalyses InstCombinePass::run(Function &F,
FunctionAnalysisManager &AM) {
+ auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F);
+ // No changes since last InstCombine pass, exit early.
+ if (LRT.shouldSkip(&ID, Options))
+ return PreservedAnalyses::all();
+
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
@@ -5555,12 +5563,16 @@ PreservedAnalyses InstCombinePass::run(Function &F,
auto *BPI = AM.getCachedResult<BranchProbabilityAnalysis>(F);
if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE,
- BFI, BPI, PSI, Options))
+ BFI, BPI, PSI, Options)) {
// No changes, all analyses are preserved.
+ LRT.update(&ID, /*Changed=*/false, Options);
return PreservedAnalyses::all();
+ }
// Mark all the analyses that instcombine updates as preserved.
PreservedAnalyses PA;
+ LRT.update(&ID, /*Changed=*/true, Options);
+ PA.preserve<LastRunTrackingAnalysis>();
PA.preserveSet<CFGAnalyses>();
return PA;
}
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index 55dbdb1b8366d6..7cf035b0c6f376 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -118,6 +118,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 5543472df685b0..3d2d80da96785d 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,7 @@
; CHECK-O23SZ-NEXT: Running pass: ConstantMergePass
; CHECK-O23SZ-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O23SZ-NEXT: Running pass: InstCombinePass
+; CHECK-O23SZ-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass
; CHECK-EP-Peephole-NEXT: Running pass: NoOpFunctionPass
; CHECK-O23SZ-NEXT: Running pass: ExpandVariadicsPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index fcf84dc5e11051..ed13402e1c4b15 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -54,6 +54,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 4d5b5e733a87c2..c82c34f7ff01e7 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -39,6 +39,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 62b81ac7cad03f..d375747547d61f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -48,6 +48,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: AAManager on foo
; CHECK-O-NEXT: Running analysis: BasicAA
; CHECK-O-NEXT: Running analysis: ScopedNoAliasAA
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index ab04f80abc5722..5aacd26def2be5 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -86,6 +86,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
index c5fc4d57539c5f..f6a94065968038 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
@@ -50,6 +50,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
@@ -122,6 +123,7 @@
; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis
; CHECK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: BlockFrequencyAnalysis on foo
; CHECK-O-NEXT: Running analysis: BranchProbabilityAnalysis on foo
; CHECK-O-NEXT: Running analysis: LoopAnalysis on foo
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
index 096110f775b04f..48a9433d249996 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
@@ -53,6 +53,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis on foo
; CHECK-O-NEXT: Running analysis: AAManager on foo
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
index f456b6e7bc8583..1908b31f52db39 100644
--- a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
+++ b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
@@ -33,9 +33,11 @@ cleanup: ; preds = %loop
define i32 @main() {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @print(i32 4)
-; CHECK-NEXT: call void @print(i32 5), !noalias !0
-; CHECK-NEXT: call void @print(i32 6), !noalias !3
+; CHECK-NEXT: tail call void @print(i32 4)
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 5), !noalias [[META0]]
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 6), !noalias [[META3]]
; CHECK-NEXT: ret i32 0
;
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll
index b12a646ef53f9f..e0484c6d669410 100644
--- a/llvm/test/Transforms/Coroutines/coro-retcon.ll
+++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll
@@ -43,8 +43,10 @@ define i32 @main() {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @print(i32 4)
-; CHECK-NEXT: tail call void @print(i32 5), !noalias !0
-; CHECK-NEXT: tail call void @print(i32 6), !noalias !3
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 5), !noalias [[META0]]
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 6), !noalias [[META3]]
; CHECK-NEXT: ret i32 0
;
; CORO-LABEL: @main(
diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt
index a3f4c10fcb9ad2..76d16513d93417 100644
--- a/llvm/unittests/Analysis/CMakeLists.txt
+++ b/llvm/unittests/Analysis/CMakeLists.txt
@@ -33,6 +33,7 @@ set(ANALYSIS_TEST_SOURCES
InlineCostTest.cpp
IRSimilarityIdentifierTest.cpp
IVDescriptorsTest.cpp
+ LastRunTrackingAnalysisTest.cpp
LazyCallGraphTest.cpp
LoadsTest.cpp
LoopInfoTest.cpp
diff --git a/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp b/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
new file mode 100644
index 00000000000000..37b9d1edbf29d2
--- /dev/null
+++ b/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
@@ -0,0 +1,117 @@
+//===--- LastRunTrackingAnalysisTest.cpp - LastRunTrackingAnalysis tests---===//
+//
+// 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
+//
+//===---------------------------------------------------------------------...
[truncated]
|
@llvm/pr-subscribers-llvm-analysis Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds a new analysis pass to track a set of passes and their parameters to see if we can avoid running transform passes that have just been run. The current implementation only skips redundant InstCombine runs. I will add support for other passes in follow-up patches. Compile time improvement: http://llvm-compile-time-tracker.com/compare.php?from=76007138f4ffd4e0f510d12b5e8cad529c21f24d&to=64134cf07ea7eb39c60320087c0c5afdc16c3a2b&stat=instructions%3Au Patch is 24.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112092.diff 20 Files Affected:
diff --git a/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h b/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h
new file mode 100644
index 00000000000000..bd2520b22db903
--- /dev/null
+++ b/llvm/include/llvm/Analysis/LastRunTrackingAnalysis.h
@@ -0,0 +1,109 @@
+//===- LastRunTrackingAnalysis.h - Avoid running redundant pass -*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is an analysis pass to track a set of passes that have been run, so that
+// we can avoid running a pass again if there is no change since the last run of
+// the pass.
+//
+// In this pass we track a set of passes S for each function with the following
+// transition rules:
+// 1. If pass P make changes, set S = {P}.
+// 2. If pass P doesn't make changes, set S = S + {P}.
+//
+// Before running a pass P which satisfies P(P(x)) == P(x), we check if P is in
+// S. If so, we skip this pass since we know that there will be no change.
+//
+// Notes:
+// 1. Some transform passes have parameters that may vary in the optimization
+// pipeline. We should check if parameters in current run is compatible with
+// that in the last run.
+// 2. Module passes are specially handled. If a module pass make changes, we
+// clear all sets.
+// 3. This pass only tracks at the function level. Loop passes are not
+// supported for now.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
+#define LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/PassManager.h"
+#include <functional>
+
+namespace llvm {
+
+/// This class is used to track the last run of a set of module/function passes.
+/// Invalidation are conservatively handled by the pass manager if a pass
+/// doesn't explicitly preserve the result.
+/// If we want to skip a pass, we should define a unique ID \p PassID to
+/// identify the pass, which is usually a pointer to a static member. If a pass
+/// has parameters, they should be stored in a struct \p OptionT with a method
+/// bool isCompatibleWith(const OptionT& LastOpt) const to check compatibility.
+class LastRunTrackingInfo {
+public:
+ using PassID = const void *;
+ using OptionPtr = const void *;
+ // CompatibilityCheckFn is a closure that stores the parameters of last run.
+ using CompatibilityCheckFn = std::function<bool(OptionPtr)>;
+
+ /// Check if we should skip a pass.
+ /// \param ID The unique ID of the pass.
+ /// \param Opt The parameters of the pass. If the pass has no parameters, use
+ /// shouldSkip(PassID ID) instead.
+ /// \return True if we should skip the pass.
+ /// \sa shouldSkip(PassID ID)
+ template <typename OptionT>
+ bool shouldSkip(PassID ID, const OptionT &Opt) const {
+ return shouldSkipImpl(ID, &Opt);
+ }
+ bool shouldSkip(PassID ID) const { return shouldSkipImpl(ID, nullptr); }
+
+ /// Update the tracking info.
+ /// \param ID The unique ID of the pass.
+ /// \param Changed Whether the pass makes changes.
+ /// \param Opt The parameters of the pass. It must have the same type as the
+ /// parameters of the last run. If the pass has no parameters, use
+ /// update(PassID ID, bool Changed) instead.
+ /// \sa update(PassID ID, bool Changed)
+ template <typename OptionT>
+ void update(PassID ID, bool Changed, const OptionT &Opt) {
+ updateImpl(ID, Changed, [Opt](OptionPtr Ptr) {
+ return static_cast<const OptionT *>(Ptr)->isCompatibleWith(Opt);
+ });
+ }
+ void update(PassID ID, bool Changed) {
+ updateImpl(ID, Changed, CompatibilityCheckFn{});
+ }
+
+private:
+ bool shouldSkipImpl(PassID ID, OptionPtr Ptr) const;
+ void updateImpl(PassID ID, bool Changed, CompatibilityCheckFn CheckFn);
+
+ DenseMap<PassID, CompatibilityCheckFn> TrackedPasses;
+};
+
+/// A function/module analysis which provides an empty \c LastRunTrackingInfo.
+class LastRunTrackingAnalysis final
+ : public AnalysisInfoMixin<LastRunTrackingAnalysis> {
+ friend AnalysisInfoMixin<LastRunTrackingAnalysis>;
+ static AnalysisKey Key;
+
+public:
+ using Result = LastRunTrackingInfo;
+ LastRunTrackingInfo run(Function &F, FunctionAnalysisManager &) {
+ return LastRunTrackingInfo();
+ }
+ LastRunTrackingInfo run(Module &M, ModuleAnalysisManager &) {
+ return LastRunTrackingInfo();
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_LASTRUNTRACKINGANALYSIS_H
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
index b4f0166239520a..5203f4cfeb976b 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h
@@ -43,12 +43,20 @@ struct InstCombineOptions {
MaxIterations = Value;
return *this;
}
+
+ /// Only enable skipping in standard optimization pipeline.
+ bool isCompatibleWith(const InstCombineOptions &LastOption) const {
+ return !VerifyFixpoint && !LastOption.VerifyFixpoint &&
+ MaxIterations == InstCombineDefaultMaxIterations &&
+ LastOption.MaxIterations == InstCombineDefaultMaxIterations;
+ }
};
class InstCombinePass : public PassInfoMixin<InstCombinePass> {
private:
InstructionWorklist Worklist;
InstCombineOptions Options;
+ static char ID;
public:
explicit InstCombinePass(InstCombineOptions Opts = {});
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 393803fad89383..0db5b80f336cb5 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -79,6 +79,7 @@ add_llvm_component_library(LLVMAnalysis
InstructionPrecedenceTracking.cpp
InstructionSimplify.cpp
InteractiveModelRunner.cpp
+ LastRunTrackingAnalysis.cpp
LazyBranchProbabilityInfo.cpp
LazyBlockFrequencyInfo.cpp
LazyCallGraph.cpp
diff --git a/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp b/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp
new file mode 100644
index 00000000000000..9add9a598f2b03
--- /dev/null
+++ b/llvm/lib/Analysis/LastRunTrackingAnalysis.cpp
@@ -0,0 +1,51 @@
+//===- LastRunTrackingAnalysis.cpp - Avoid running redundant pass -*- C++ -*-=//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is an analysis pass to track a set of passes that have been run, so that
+// we can avoid running a pass again if there is no change since the last run of
+// the pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "last-run-tracking"
+STATISTIC(NumSkippedPasses, "Number of skipped passes");
+STATISTIC(NumLRTQueries, "Number of LastRunTracking queries");
+
+static cl::opt<bool>
+ DisableLastRunTracking("disable-last-run-tracking", cl::Hidden,
+ cl::desc("Disable last run tracking"),
+ cl::init(false));
+
+bool LastRunTrackingInfo::shouldSkipImpl(PassID ID, OptionPtr Ptr) const {
+ if (DisableLastRunTracking)
+ return false;
+ ++NumLRTQueries;
+ auto Iter = TrackedPasses.find(ID);
+ if (Iter == TrackedPasses.end())
+ return false;
+ if (!Iter->second || Iter->second(Ptr)) {
+ ++NumSkippedPasses;
+ return true;
+ }
+ return false;
+}
+
+void LastRunTrackingInfo::updateImpl(PassID ID, bool Changed,
+ CompatibilityCheckFn CheckFn) {
+ if (Changed)
+ TrackedPasses.clear();
+ TrackedPasses[ID] = std::move(CheckFn);
+}
+
+AnalysisKey LastRunTrackingAnalysis::Key;
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f47f8ca35d7737..e515a86d1bf310 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -46,6 +46,7 @@
#include "llvm/Analysis/InlineAdvisor.h"
#include "llvm/Analysis/InlineSizeEstimatorAnalysis.h"
#include "llvm/Analysis/InstCount.h"
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Analysis/Lint.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 90859c18c4f499..55fb8135ddd41c 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -25,6 +25,7 @@ MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
MODULE_ANALYSIS("dxil-resource", DXILResourceAnalysis())
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
+MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
MODULE_ANALYSIS("module-summary", ModuleSummaryIndexAnalysis())
MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
@@ -285,6 +286,7 @@ FUNCTION_ANALYSIS(
MachineFunctionAnalysis(static_cast<const LLVMTargetMachine *>(TM)))
FUNCTION_ANALYSIS("gc-function", GCFunctionAnalysis())
FUNCTION_ANALYSIS("inliner-size-estimator", InlineSizeEstimatorAnalysis())
+FUNCTION_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis())
FUNCTION_ANALYSIS("loops", LoopAnalysis())
FUNCTION_ANALYSIS("memdep", MemoryDependenceAnalysis())
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 954c4cf19c2077..1a512cae7bf778 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -47,6 +47,7 @@
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/LastRunTrackingAnalysis.h"
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
@@ -5538,8 +5539,15 @@ void InstCombinePass::printPipeline(
OS << '>';
}
+char InstCombinePass::ID = 0;
+
PreservedAnalyses InstCombinePass::run(Function &F,
FunctionAnalysisManager &AM) {
+ auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F);
+ // No changes since last InstCombine pass, exit early.
+ if (LRT.shouldSkip(&ID, Options))
+ return PreservedAnalyses::all();
+
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
@@ -5555,12 +5563,16 @@ PreservedAnalyses InstCombinePass::run(Function &F,
auto *BPI = AM.getCachedResult<BranchProbabilityAnalysis>(F);
if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE,
- BFI, BPI, PSI, Options))
+ BFI, BPI, PSI, Options)) {
// No changes, all analyses are preserved.
+ LRT.update(&ID, /*Changed=*/false, Options);
return PreservedAnalyses::all();
+ }
// Mark all the analyses that instcombine updates as preserved.
PreservedAnalyses PA;
+ LRT.update(&ID, /*Changed=*/true, Options);
+ PA.preserve<LastRunTrackingAnalysis>();
PA.preserveSet<CFGAnalyses>();
return PA;
}
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index 55dbdb1b8366d6..7cf035b0c6f376 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -118,6 +118,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 5543472df685b0..3d2d80da96785d 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,7 @@
; CHECK-O23SZ-NEXT: Running pass: ConstantMergePass
; CHECK-O23SZ-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O23SZ-NEXT: Running pass: InstCombinePass
+; CHECK-O23SZ-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass
; CHECK-EP-Peephole-NEXT: Running pass: NoOpFunctionPass
; CHECK-O23SZ-NEXT: Running pass: ExpandVariadicsPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index fcf84dc5e11051..ed13402e1c4b15 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -54,6 +54,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 4d5b5e733a87c2..c82c34f7ff01e7 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -39,6 +39,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 62b81ac7cad03f..d375747547d61f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -48,6 +48,7 @@
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: AAManager on foo
; CHECK-O-NEXT: Running analysis: BasicAA
; CHECK-O-NEXT: Running analysis: ScopedNoAliasAA
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index ab04f80abc5722..5aacd26def2be5 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -86,6 +86,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
index c5fc4d57539c5f..f6a94065968038 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
@@ -50,6 +50,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: BasicAA
@@ -122,6 +123,7 @@
; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis
; CHECK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: BlockFrequencyAnalysis on foo
; CHECK-O-NEXT: Running analysis: BranchProbabilityAnalysis on foo
; CHECK-O-NEXT: Running analysis: LoopAnalysis on foo
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
index 096110f775b04f..48a9433d249996 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
@@ -53,6 +53,7 @@
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: PromotePass
; CHECK-O-NEXT: Running pass: InstCombinePass
+; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis
; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis on foo
; CHECK-O-NEXT: Running analysis: AAManager on foo
; CHECK-O-NEXT: Running analysis: BasicAA
diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
index f456b6e7bc8583..1908b31f52db39 100644
--- a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
+++ b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll
@@ -33,9 +33,11 @@ cleanup: ; preds = %loop
define i32 @main() {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @print(i32 4)
-; CHECK-NEXT: call void @print(i32 5), !noalias !0
-; CHECK-NEXT: call void @print(i32 6), !noalias !3
+; CHECK-NEXT: tail call void @print(i32 4)
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 5), !noalias [[META0]]
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 6), !noalias [[META3]]
; CHECK-NEXT: ret i32 0
;
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll
index b12a646ef53f9f..e0484c6d669410 100644
--- a/llvm/test/Transforms/Coroutines/coro-retcon.ll
+++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll
@@ -43,8 +43,10 @@ define i32 @main() {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @print(i32 4)
-; CHECK-NEXT: tail call void @print(i32 5), !noalias !0
-; CHECK-NEXT: tail call void @print(i32 6), !noalias !3
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 5), !noalias [[META0]]
+; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]])
+; CHECK-NEXT: tail call void @print(i32 6), !noalias [[META3]]
; CHECK-NEXT: ret i32 0
;
; CORO-LABEL: @main(
diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt
index a3f4c10fcb9ad2..76d16513d93417 100644
--- a/llvm/unittests/Analysis/CMakeLists.txt
+++ b/llvm/unittests/Analysis/CMakeLists.txt
@@ -33,6 +33,7 @@ set(ANALYSIS_TEST_SOURCES
InlineCostTest.cpp
IRSimilarityIdentifierTest.cpp
IVDescriptorsTest.cpp
+ LastRunTrackingAnalysisTest.cpp
LazyCallGraphTest.cpp
LoadsTest.cpp
LoopInfoTest.cpp
diff --git a/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp b/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
new file mode 100644
index 00000000000000..37b9d1edbf29d2
--- /dev/null
+++ b/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
@@ -0,0 +1,117 @@
+//===--- LastRunTrackingAnalysisTest.cpp - LastRunTrackingAnalysis tests---===//
+//
+// 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
+//
+//===---------------------------------------------------------------------...
[truncated]
|
If necessary, I can try to address some fixed point iteration problems in InstCombine to reduce IR diff. I am not certain whether it is worth doing. |
auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F); | ||
// No changes since last InstCombine pass, exit early. | ||
if (LRT.shouldSkip(&ID, Options)) | ||
return PreservedAnalyses::all(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought, but could we instead bake this into the passmanager itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't agree. Only some canonicalization/cleanup passes benefit from this optimization. Moving the logic into PassManager may introduce higher overhead.
BTW, we cannot do this since InstCombine/SimplifyCFG have pass parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed about keeping this out of the pass manager, the pass manager shouldn't know which passes are supposed to be idempotent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know much about the new pass manager, but conceptually there is a lot of overlap between:
- tracking which analyses are valid, and invalidating them when a pass changes something (and doesn't explicitly preserve that analysis)
- tracking which passes have been run, and no pass since then has changed anything.
In the old pass manager you could almost implement this by making a pass P depend on itself:
AU.addUsedIfAvailableID(ID); // depend on myself
and then in its runOn*
method, check whether it is still "available" from a previous run (obviously you would only do this part in an idempotent pass):
if (mustPreserveAnalysisID(ID)) // is my ID still available?
return false;
Is there any way to do something similar in the new pass manager? I.e. have the pass manager be responsible for tracking which passes are still "available", even if it does not know which ones are idempotent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the legacy pass manager, analyses were special passes. in the new pass manager, analyses and passes are separate concepts, so that sort of hack doesn't really work. and that doesn't solve the pass parameter issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no way to get the parameters going into a pass from the new manager?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no way to get the parameters going into a pass from the new manager?
no, I'm not sure how that would work. pass parameters are specified when constructing the pass, none of the pass manager infrastructure can access pass params because that's not really part of the public API of a pass
// | ||
// Notes: | ||
// 1. Some transform passes have parameters that may vary in the optimization | ||
// pipeline. We should check if parameters in current run is compatible with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
treating each pass+pass parameter separately seems logically nicer, rather than grouping runs of a pass with different parameters together
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain it further? Did you mean make LastRunTrackingAnalysis
template class to avoid using DenseMap
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't have a specific implementation in mind, I meant that we should treat simplifycfg<params1>
and simplifycfg<params2>
separately just like simplifycfg<params1>
and instcombine
.
auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F); | ||
// No changes since last InstCombine pass, exit early. | ||
if (LRT.shouldSkip(&ID, Options)) | ||
return PreservedAnalyses::all(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed about keeping this out of the pass manager, the pass manager shouldn't know which passes are supposed to be idempotent
|
||
/// Only enable skipping when two versions of parameters are exactly the same. | ||
bool isCompatibleWith(const InstCombineOptions &LastOption) const { | ||
return VerifyFixpoint == LastOption.VerifyFixpoint && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VerifyFixpoint
doesn't affect the output, it just crashes if an extra round causes changes
and given that the current intent of instcombine is to almost always ensure everything is done in one iteration, I don't think we need isCompatibleWith
for instcombine. @nikic
given this, perhaps we should start with simplifycfg instead of instcombine since simplifycfg has pass params, and add some lit tests that make sure we skip a simplifycfg rerun if the params are the same and don't skip if params are different. we might need to add debug logging and check for that in the test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given this, perhaps we should start with simplifycfg instead of instcombine since simplifycfg has pass params, and add some lit tests that make sure we skip a simplifycfg rerun if the params are the same and don't skip if params are different.
I plan to support SimplifyCFG in the subsequent patch. I have added some unittests for passes with parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still drop the instcombine options checking here given my previous comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
the compile time numbers look great btw :) |
fcb9b4f
to
e0de7f4
Compare
if (DisableLastRunTracking) | ||
return false; | ||
++NumLRTQueries; | ||
auto Iter = TrackedPasses.find(ID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't handle if we have multiple SimplifyCFGs with different pass params. I think it would be nice to support that given how many different SimplifyCFG runs with different params there are in the pipeline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SimplifyCFGPass runs with params in the default<O3>
pipeline:
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
; no-switch-range-to-icmp -> switch-range-to-icmp
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
; no-hoist-common-insts -> hoist-common-insts, no-sink-common-insts -> sink-common-insts
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
; no-forward-switch-cond -> forward-switch-cond, no-switch-to-lookup -> switch-to-lookup, keep-loops -> no-keep-loops
SimplifyCFGPass<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
; forward-switch-cond -> no-forward-switch-cond, hoist-common-insts -> no-hoist-common-insts, sink-common-insts -> no-sink-common-insts, no-hoist-loads-stores-with-cond-faulting -> hoist-loads-stores-with-cond-faulting
SimplifyCFGPass<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>
I cannot imagine we can benefit from a more fine-grained caching scheme. The isCompatibleWith
interface should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sgtm. I do think what I suggested is a little nicer logically, but you've convinced me it's unnecessary
if (DisableLastRunTracking) | ||
return false; | ||
++NumLRTQueries; | ||
auto Iter = TrackedPasses.find(ID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sgtm. I do think what I suggested is a little nicer logically, but you've convinced me it's unnecessary
// 1. Some transform passes have parameters that may vary in the optimization | ||
// pipeline. We should check if parameters in current run is compatible with | ||
// that in the last run. | ||
// 2. Module passes are specially handled. If a module pass make changes, we |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean "module passes are specially handled"? it looks like they're treated the same as function passes
I plan to land this patch on Nov 6th if there are no more comments. |
bb9d0da
to
783b6ea
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/5224 Here is the relevant piece of the build log for the reference
|
Fixed by 84745da. |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/145/builds/2991 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/52/builds/3525 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/146/builds/1541 Here is the relevant piece of the build log for the reference
|
auto Iter = TrackedPasses.find(ID); | ||
if (Iter == TrackedPasses.end()) | ||
return false; | ||
if (!Iter->second || Iter->second(Ptr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might hit a bug with updateImpl
& shouldSkipImpl
. Given such calling sequence:
- In one run of
InstCombinePass::run
, callsLRT.update(&ID, /*Changed=*/true);
1.1updateImpl(ID, Changed, CompatibilityCheckFn{});
1.2 TheTrackedPasses
is cleared, thenTrackedPasses[ID]
set with a null function pointer - In next run of
InstCombinePass::run
, checkingLRT.shouldSkip(&ID)
2.1shouldSkipImpl(ID, nullptr)
2.2 we reachesif (!Iter->second || Iter->second(Ptr))
, and sinceIter->second
is a null pointer, we return true and skip the next run of inst combine pass while it shouldn't since the previous run changed the IR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is expected behavior that we avoid run the same pass regardless of whether the last run of this pass modifies IR.
See also the test
llvm-project/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
Lines 96 to 97 in 3a3517c
// Skipped since PassA has just been executed. | |
MPM.addPass(ModuleNoopPass(BitMap, 1, &PassA, false)); |
For InstCombine, we expect that it reaches a fixpoint in the first run. Thus it is safe to avoid the second run. See also the discussion in https://discourse.llvm.org/t/rfc-pipeline-avoid-running-transform-passes-that-have-just-been-run/82467/8. If not, InstCombine should report something like Instruction Combining on XXX did not reach a fixpoint...
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks!
This patch adds a new analysis pass to track a set of passes and their parameters to see if we can avoid running transform passes that have just been run. The current implementation only skips redundant InstCombine runs. I will add support for other passes in follow-up patches.
RFC link: https://discourse.llvm.org/t/rfc-pipeline-avoid-running-transform-passes-that-have-just-been-run/82467
Compile time improvement: http://llvm-compile-time-tracker.com/compare.php?from=76007138f4ffd4e0f510d12b5e8cad529c21f24d&to=64134cf07ea7eb39c60320087c0c5afdc16c3a2b&stat=instructions%3Au