From dd4e3b41996bf0645d69d77c977e599d49c624ce Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Thu, 18 Apr 2019 19:17:14 +0000 Subject: [PATCH] [GuardWidening] Wire up a NPM version of the LoopGuardWidening pass git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358704 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/Transforms/Scalar/GuardWidening.h | 4 + lib/Passes/PassRegistry.def | 1 + lib/Transforms/Scalar/GuardWidening.cpp | 25 ++++ test/Transforms/GuardWidening/basic-loop.ll | 138 ++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 test/Transforms/GuardWidening/basic-loop.ll diff --git a/include/llvm/Transforms/Scalar/GuardWidening.h b/include/llvm/Transforms/Scalar/GuardWidening.h index 3adea0529c6..06dc9ac97be 100644 --- a/include/llvm/Transforms/Scalar/GuardWidening.h +++ b/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 { PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, LPMUpdater &U); }; } diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index d3220c8f2e6..23ebbcfa675 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -294,4 +294,5 @@ LOOP_PASS("unswitch", SimpleLoopUnswitchPass()) LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs())) LOOP_PASS("print", IVUsersPrinterPass(dbgs())) LOOP_PASS("loop-predication", LoopPredicationPass()) +LOOP_PASS("guard-widening", GuardWideningPass()) #undef LOOP_PASS diff --git a/lib/Transforms/Scalar/GuardWidening.cpp b/lib/Transforms/Scalar/GuardWidening.cpp index ec1f9144a15..e14f44bb706 100644 --- a/lib/Transforms/Scalar/GuardWidening.cpp +++ b/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(L, AR).getManager(); + Function &F = *L.getHeader()->getParent(); + BranchProbabilityInfo *BPI = nullptr; + if (WidenFrequentBranches) + BPI = FAM.getCachedResult(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/test/Transforms/GuardWidening/basic-loop.ll b/test/Transforms/GuardWidening/basic-loop.ll new file mode 100644 index 00000000000..8129a789f33 --- /dev/null +++ b/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 +} + -- 2.50.1