[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
diff --git a/include/llvm/Transforms/Scalar/GuardWidening.h b/include/llvm/Transforms/Scalar/GuardWidening.h
index 3adea05..06dc9ac 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 @@
 
 struct GuardWideningPass : public PassInfoMixin<GuardWideningPass> {
   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 d3220c8..23ebbcf 100644
--- a/lib/Passes/PassRegistry.def
+++ b/lib/Passes/PassRegistry.def
@@ -294,4 +294,5 @@
 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/lib/Transforms/Scalar/GuardWidening.cpp b/lib/Transforms/Scalar/GuardWidening.cpp
index ec1f914..e14f44b 100644
--- a/lib/Transforms/Scalar/GuardWidening.cpp
+++ b/lib/Transforms/Scalar/GuardWidening.cpp
@@ -817,6 +817,31 @@
   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/test/Transforms/GuardWidening/basic-loop.ll b/test/Transforms/GuardWidening/basic-loop.ll
new file mode 100644
index 0000000..8129a78
--- /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
+}
+