diff options
author | Philip Reames <listmail@philipreames.com> | 2019-04-18 19:17:14 +0000 |
---|---|---|
committer | Philip Reames <listmail@philipreames.com> | 2019-04-18 19:17:14 +0000 |
commit | 137995d8daf39e435eceb0dc77a97dff089ded18 (patch) | |
tree | 422b53148761a5aba33ae37382bd6ca90b0b6214 | |
parent | 139e216e6610091b7ee3c30bc11114f5d73cbd3e (diff) | |
download | llvm-137995d8daf39e435eceb0dc77a97dff089ded18.zip llvm-137995d8daf39e435eceb0dc77a97dff089ded18.tar.gz llvm-137995d8daf39e435eceb0dc77a97dff089ded18.tar.bz2 |
[GuardWidening] Wire up a NPM version of the LoopGuardWidening pass
llvm-svn: 358704
-rw-r--r-- | llvm/include/llvm/Transforms/Scalar/GuardWidening.h | 4 | ||||
-rw-r--r-- | llvm/lib/Passes/PassRegistry.def | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/GuardWidening.cpp | 25 | ||||
-rw-r--r-- | llvm/test/Transforms/GuardWidening/basic-loop.ll | 138 |
4 files changed, 168 insertions, 0 deletions
diff --git a/llvm/include/llvm/Transforms/Scalar/GuardWidening.h b/llvm/include/llvm/Transforms/Scalar/GuardWidening.h index 3adea05..06dc9ac 100644 --- a/llvm/include/llvm/Transforms/Scalar/GuardWidening.h +++ b/llvm/include/llvm/Transforms/Scalar/GuardWidening.h @@ -16,7 +16,9 @@ #ifndef LLVM_TRANSFORMS_SCALAR_GUARD_WIDENING_H #define LLVM_TRANSFORMS_SCALAR_GUARD_WIDENING_H +#include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" namespace llvm { @@ -24,6 +26,8 @@ class Function; struct GuardWideningPass : public PassInfoMixin<GuardWideningPass> { PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, LPMUpdater &U); }; } diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index d3220c8..23ebbcf 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -294,4 +294,5 @@ LOOP_PASS("unswitch", SimpleLoopUnswitchPass()) LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs())) LOOP_PASS("print<ivusers>", IVUsersPrinterPass(dbgs())) LOOP_PASS("loop-predication", LoopPredicationPass()) +LOOP_PASS("guard-widening", GuardWideningPass()) #undef LOOP_PASS diff --git a/llvm/lib/Transforms/Scalar/GuardWidening.cpp b/llvm/lib/Transforms/Scalar/GuardWidening.cpp index ec1f914..e14f44b 100644 --- a/llvm/lib/Transforms/Scalar/GuardWidening.cpp +++ b/llvm/lib/Transforms/Scalar/GuardWidening.cpp @@ -817,6 +817,31 @@ PreservedAnalyses GuardWideningPass::run(Function &F, return PA; } +PreservedAnalyses GuardWideningPass::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + + const auto &FAM = + AM.getResult<FunctionAnalysisManagerLoopProxy>(L, AR).getManager(); + Function &F = *L.getHeader()->getParent(); + BranchProbabilityInfo *BPI = nullptr; + if (WidenFrequentBranches) + BPI = FAM.getCachedResult<BranchProbabilityAnalysis>(F); + + BasicBlock *RootBB = L.getLoopPredecessor(); + if (!RootBB) + RootBB = L.getHeader(); + auto BlockFilter = [&](BasicBlock *BB) { + return BB == RootBB || L.contains(BB); + }; + if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, BPI, + AR.DT.getNode(RootBB), + BlockFilter).run()) + return PreservedAnalyses::all(); + + return getLoopPassPreservedAnalyses(); +} + namespace { struct GuardWideningLegacyPass : public FunctionPass { static char ID; diff --git a/llvm/test/Transforms/GuardWidening/basic-loop.ll b/llvm/test/Transforms/GuardWidening/basic-loop.ll new file mode 100644 index 0000000..8129a78 --- /dev/null +++ b/llvm/test/Transforms/GuardWidening/basic-loop.ll @@ -0,0 +1,138 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -loop-guard-widening < %s | FileCheck %s +; RUN: opt -S -passes="loop(guard-widening)" < %s | FileCheck %s + +declare void @llvm.experimental.guard(i1,...) + +@G = external global i32 + +; Show that we can widen into early checks within a loop, and in the process +; expose optimization oppurtunities. +define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) { +; CHECK-LABEL: @widen_within_loop( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: store i32 0, i32* @G +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: store i32 1, i32* @G +; CHECK-NEXT: store i32 2, i32* @G +; CHECK-NEXT: store i32 3, i32* @G +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + store i32 0, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] + store i32 1, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] + store i32 2, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] + store i32 3, i32* @G + br label %loop +} + +define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) { +; CHECK-LABEL: @widen_into_preheader( +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 0, i32* @G +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: store i32 1, i32* @G +; CHECK-NEXT: store i32 2, i32* @G +; CHECK-NEXT: store i32 3, i32* @G +; CHECK-NEXT: br label [[LOOP]] +; +entry: + store i32 0, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] + br label %loop + +loop: + store i32 1, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ] + store i32 2, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] + store i32 3, i32* @G + br label %loop +} + +define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) { +; CHECK-LABEL: @dont_widen_over_common_exit( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: store i32 0, i32* @G +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: store i32 1, i32* @G +; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] +; CHECK: backedge: +; CHECK-NEXT: store i32 2, i32* @G +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ] +; CHECK-NEXT: store i32 3, i32* @G +; CHECK-NEXT: br label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + store i32 0, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] + store i32 1, i32* @G + br i1 %cond_1, label %backedge, label %exit + +backedge: + store i32 2, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] + store i32 3, i32* @G + br label %loop + +exit: + ret void +} + +define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) { +; CHECK-LABEL: @widen_over_common_exit_to_ph( +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 0, i32* @G +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: store i32 1, i32* @G +; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]] +; CHECK: backedge: +; CHECK-NEXT: store i32 2, i32* @G +; CHECK-NEXT: store i32 3, i32* @G +; CHECK-NEXT: br label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + store i32 0, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ] + br label %loop + +loop: + store i32 1, i32* @G + br i1 %cond_1, label %backedge, label %exit + +backedge: + store i32 2, i32* @G + call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ] + store i32 3, i32* @G + br label %loop + +exit: + ret void +} + |