diff --git a/llvm/test/Transforms/LoopPredication/invalidate-analyses.ll b/llvm/test/Transforms/LoopPredication/invalidate-analyses.ll new file mode 100644 index 00000000000000..9c1812a9ae9d6f --- /dev/null +++ b/llvm/test/Transforms/LoopPredication/invalidate-analyses.ll @@ -0,0 +1,166 @@ +; RUN: opt -S -passes='require,loop-mssa(loop-predication)' -debug-pass-manager < %s 2>&1 | FileCheck %s + +; FIXME: We should invalidate PreservedCFGCheckerAnalysis after LoopPredicationPass! +; NOTE: PreservedCFGCheckerAnalysis is an arbitrary analysis that just happens +; to be calculated before this pass and isn't preserved by it. If after +; your change this analysis is preserved by the pass, please update this +; test some other analysis that isn't preserved. + +; CHECK: Running analysis: PreservedCFGCheckerAnalysis on drop_a_wc_and_leave_early +; CHECK: Running pass: LoopPredicationPass on Loop at depth 1 containing: %loop
,%guarded,%guarded2 +; CHECK-NEXT: Running analysis: PreservedCFGCheckerAnalysis on drop_a_wc_and_leave +; CHECK: Running pass: LoopPredicationPass on Loop at depth 1 containing: %loop
,%guarded,%guarded2 +; CHECK-NEXT: Running pass: VerifierPass + + +; This test makes the pass drop its attempts to optimize the exit condition in +; `%loop` BB by using unanalyzable `%cond_0` as an exit condition. +define i64 @drop_a_wc_and_leave_early(i64 %length, i64 %n, i1 %cond_0, i1 %cond_1) { +; Make sure the pass has only replaced `%wc2` with `true` in the definition of `%wb_cond`. +; CHECK-LABEL: define i64 @drop_a_wc_and_leave_early(i64 %length, i64 %n, i1 %cond_0, i1 %cond_1) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %wc1 = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: %wc2 = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: %exiplicit_guard_cond = and i1 %cond_0, %wc1 +; CHECK-NEXT: br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0 +; CHECK: deopt: +; CHECK-NEXT: %deoptret = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret +; CHECK: loop.preheader: +; CHECK-NEXT: br label %loop +; CHECK: loop: +; CHECK-NEXT: %i = phi i64 [ %i.next, %guarded2 ], [ 0, %loop.preheader ] +; CHECK-NEXT: br i1 %cond_0, label %guarded, label %deopt2, !prof !0 +; CHECK: deopt2: +; CHECK-NEXT: %deoptret2 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret2 +; CHECK: guarded: +; CHECK-NEXT: %wb_cond = and i1 %cond_1, true +; CHECK-NEXT: br i1 %wb_cond, label %guarded2, label %deopt3, !prof !0 +; CHECK: deopt3: +; CHECK-NEXT: %deoptret3 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret3 +; CHECK: guarded2: +; CHECK-NEXT: %i.next = add nuw i64 %i, 1 +; CHECK-NEXT: %continue = icmp ult i64 %i.next, %n +; CHECK-NEXT: br i1 %continue, label %loop, label %exit +; CHECK: exit: +; CHECK-NEXT: ret i64 0 +; CHECK-NEXT: } + +entry: + %wc1 = call i1 @llvm.experimental.widenable.condition() + %wc2 = call i1 @llvm.experimental.widenable.condition() + %exiplicit_guard_cond = and i1 %cond_0, %wc1 + br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0 + +deopt: + %deoptret = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret + +loop.preheader: + br label %loop + +loop: + %i = phi i64 [ %i.next, %guarded2 ], [ 0, %loop.preheader ] + br i1 %cond_0, label %guarded, label %deopt2, !prof !0 + +deopt2: + %deoptret2 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret2 + +guarded: + %wb_cond = and i1 %cond_1, %wc2 + br i1 %wb_cond, label %guarded2, label %deopt3, !prof !0 + +deopt3: + %deoptret3 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret3 + +guarded2: + %i.next = add nuw i64 %i, 1 + %continue = icmp ult i64 %i.next, %n + br i1 %continue, label %loop, label %exit + +exit: + ret i64 0 +} + +; This test makes the pass drop its attempts to optimize the exit condition in +; `%loop` BB by using trivial `false` as an exit condition. +define i64 @drop_a_wc_and_leave(i64 %n, i1 %cond_0, i1 %cond_1) { +; Make sure the pass has only replaced `%wc2` with `true` in the definition of `%wb_cond`. +; CHECK-LABEL: define i64 @drop_a_wc_and_leave(i64 %n, i1 %cond_0, i1 %cond_1) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %wc1 = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: %wc2 = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: %exiplicit_guard_cond = and i1 %cond_0, %wc1 +; CHECK-NEXT: br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0 +; CHECK: deopt: +; CHECK-NEXT: %deoptret = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret +; CHECK: loop.preheader: +; CHECK-NEXT: br label %loop +; CHECK: loop: +; CHECK-NEXT: %i = phi i64 [ %i.next, %guarded2 ], [ 0, %loop.preheader ] +; CHECK-NEXT: br i1 false, label %guarded, label %deopt2, !prof !0 +; CHECK: deopt2: +; CHECK-NEXT: %deoptret2 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret2 +; CHECK: guarded: +; CHECK-NEXT: %wb_cond = and i1 %cond_1, true +; CHECK-NEXT: br i1 %wb_cond, label %guarded2, label %deopt3, !prof !0 +; CHECK: deopt3: +; CHECK-NEXT: %deoptret3 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] +; CHECK-NEXT: ret i64 %deoptret3 +; CHECK: guarded2: +; CHECK-NEXT: %i.next = add nuw i64 %i, 1 +; CHECK-NEXT: %continue = icmp ult i64 %i.next, %n +; CHECK-NEXT: br i1 %continue, label %loop, label %exit +; CHECK: exit: +; CHECK-NEXT: ret i64 0 +; CHECK-NEXT: } + +entry: + %wc1 = call i1 @llvm.experimental.widenable.condition() + %wc2 = call i1 @llvm.experimental.widenable.condition() + %exiplicit_guard_cond = and i1 %cond_0, %wc1 + br i1 %exiplicit_guard_cond, label %loop.preheader, label %deopt, !prof !0 + +deopt: + %deoptret = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret + +loop.preheader: + br label %loop + +loop: + %i = phi i64 [ %i.next, %guarded2 ], [ 0, %loop.preheader ] + br i1 false, label %guarded, label %deopt2, !prof !0 + +deopt2: + %deoptret2 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret2 + +guarded: + %wb_cond = and i1 %cond_1, %wc2 + br i1 %wb_cond, label %guarded2, label %deopt3, !prof !0 + +deopt3: + %deoptret3 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ] + ret i64 %deoptret3 + +guarded2: + %i.next = add nuw i64 %i, 1 + %continue = icmp ult i64 %i.next, %n + br i1 %continue, label %loop, label %exit + +exit: + ret i64 0 +} + + +declare i1 @llvm.experimental.widenable.condition() +declare i64 @llvm.experimental.deoptimize.i64(...) + +!0 = !{!"branch_weights", i64 1048576, i64 1}