[llvm] 725400f - [NFCI][SimpleLoopUnswitch] Adjust CostKind query

Sam Parker via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 23:55:11 PDT 2020


Author: Sam Parker
Date: 2020-08-14T07:54:20+01:00
New Revision: 725400f9933fe58273d4500d8d6a77a438c43798

URL: https://github.com/llvm/llvm-project/commit/725400f9933fe58273d4500d8d6a77a438c43798
DIFF: https://github.com/llvm/llvm-project/commit/725400f9933fe58273d4500d8d6a77a438c43798.diff

LOG: [NFCI][SimpleLoopUnswitch] Adjust CostKind query

When getUserCost was transitioned to use an explicit CostKind,
TCK_CodeSize was used even though the original kind was implicitly
SizeAndLatency so restore this behaviour. We now only query for
CodeSize when optimising for minsize.

I expect this to not change anything as, I think all, targets will
currently return the same value for CodeSize and SizeLatency. Indeed
I see no changes in the test suite for Arm, AArch64 and X86.

Differential Revision: https://reviews.llvm.org/D85829

Added: 
    llvm/test/Transforms/SimpleLoopUnswitch/ARM/lit.local.cfg
    llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll

Modified: 
    llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index ab1945a1aff1..6656fa0670f5 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -2692,6 +2692,10 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
   // (convergent, noduplicate, or cross-basic-block tokens).
   // FIXME: We might be able to safely handle some of these in non-duplicated
   // regions.
+  TargetTransformInfo::TargetCostKind CostKind =
+      L.getHeader()->getParent()->hasMinSize()
+      ? TargetTransformInfo::TCK_CodeSize
+      : TargetTransformInfo::TCK_SizeAndLatency;
   int LoopCost = 0;
   for (auto *BB : L.blocks()) {
     int Cost = 0;
@@ -2705,7 +2709,7 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
         if (CB->isConvergent() || CB->cannotDuplicate())
           return false;
 
-      Cost += TTI.getUserCost(&I, TargetTransformInfo::TCK_CodeSize);
+      Cost += TTI.getUserCost(&I, CostKind);
     }
     assert(Cost >= 0 && "Must not have negative costs!");
     LoopCost += Cost;

diff  --git a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/lit.local.cfg b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/lit.local.cfg
new file mode 100644
index 000000000000..236e1d344166
--- /dev/null
+++ b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'ARM' in config.root.targets:
+    config.unsupported = True

diff  --git a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll
new file mode 100644
index 000000000000..87f52c01e955
--- /dev/null
+++ b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll
@@ -0,0 +1,723 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -mtriple=thumbv8m.main -simple-loop-unswitch -enable-nontrivial-unswitch -unswitch-threshold=5 -S -o - %s | FileCheck %s
+
+declare void @a()
+declare void @b()
+declare void @x()
+
+define void @test_no_unswitch(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_no_unswitch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LOOP_A:%.*]], label [[LOOP_B:%.*]]
+; CHECK:       loop_a:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT:%.*]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+loop_begin:
+  call void @x()
+  call void @x()
+  call void @x()
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_unswitch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_minsize(i1* %ptr, i1 %cond) #0 {
+; CHECK-LABEL: @test_unswitch_minsize(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_non_dup_code(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_unswitch_non_dup_code(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  call void @a()
+  call void @a()
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  call void @b()
+  call void @b()
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_non_dup_code_minsize(i1* %ptr, i1 %cond) #0 {
+; CHECK-LABEL: @test_unswitch_non_dup_code_minsize(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  call void @a()
+  call void @a()
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  call void @b()
+  call void @b()
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_non_dup_code_in_cfg(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_unswitch_non_dup_code_in_cfg(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    [[V1_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V1_US]], label [[LOOP_A_A_US:%.*]], label [[LOOP_A_B_US:%.*]]
+; CHECK:       loop_a_b.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_a_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V3_US:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V3_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    [[V2:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V2]], label [[LOOP_B_A:%.*]], label [[LOOP_B_B:%.*]]
+; CHECK:       loop_b_a:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_b_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V3:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V3]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  %v1 = load i1, i1* %ptr
+  br i1 %v1, label %loop_a_a, label %loop_a_b
+
+loop_a_a:
+  call void @a()
+  br label %loop_latch
+
+loop_a_b:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  %v2 = load i1, i1* %ptr
+  br i1 %v2, label %loop_b_a, label %loop_b_b
+
+loop_b_a:
+  call void @b()
+  br label %loop_latch
+
+loop_b_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v3 = load i1, i1* %ptr
+  br i1 %v3, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_non_dup_code_in_cfg_minsize(i1* %ptr, i1 %cond) #0 {
+; CHECK-LABEL: @test_unswitch_non_dup_code_in_cfg_minsize(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    [[V1_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V1_US]], label [[LOOP_A_A_US:%.*]], label [[LOOP_A_B_US:%.*]]
+; CHECK:       loop_a_b.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_a_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V3_US:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V3_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    [[V2:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V2]], label [[LOOP_B_A:%.*]], label [[LOOP_B_B:%.*]]
+; CHECK:       loop_b_a:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_b_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V3:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V3]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  %v1 = load i1, i1* %ptr
+  br i1 %v1, label %loop_a_a, label %loop_a_b
+
+loop_a_a:
+  call void @a()
+  br label %loop_latch
+
+loop_a_b:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  %v2 = load i1, i1* %ptr
+  br i1 %v2, label %loop_b_a, label %loop_b_b
+
+loop_b_a:
+  call void @b()
+  br label %loop_latch
+
+loop_b_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v3 = load i1, i1* %ptr
+  br i1 %v3, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_no_unswitch_non_dup_code(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_no_unswitch_non_dup_code(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LOOP_A:%.*]], label [[LOOP_B:%.*]]
+; CHECK:       loop_a:
+; CHECK-NEXT:    [[V1:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V1]], label [[LOOP_A_A:%.*]], label [[LOOP_A_B:%.*]]
+; CHECK:       loop_a_a:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_a_b:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    [[V2:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V2]], label [[LOOP_B_A:%.*]], label [[LOOP_B_B:%.*]]
+; CHECK:       loop_b_a:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_b_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT:%.*]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  %v1 = load i1, i1* %ptr
+  br i1 %v1, label %loop_a_a, label %loop_a_b
+
+loop_a_a:
+  call void @a()
+  br label %loop_latch
+
+loop_a_b:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  %v2 = load i1, i1* %ptr
+  br i1 %v2, label %loop_b_a, label %loop_b_b
+
+loop_b_a:
+  call void @b()
+  br label %loop_latch
+
+loop_b_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  call void @x()
+  call void @x()
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_large_exit(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_unswitch_large_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B:%.*]]
+; CHECK:       loop_b:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop_latch:
+; CHECK-NEXT:    [[V:%.*]] = load i1, i1* [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[V]], label [[LOOP_BEGIN]], label [[LOOP_EXIT_SPLIT:%.*]]
+; CHECK:       loop_exit.split:
+; CHECK-NEXT:    br label [[LOOP_EXIT]]
+; CHECK:       loop_exit:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b:
+  call void @b()
+  br label %loop_latch
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  call void @x()
+  call void @x()
+  call void @x()
+  call void @x()
+  ret void
+}
+
+define void @test_unswitch_dedicated_exiting(i1* %ptr, i1 %cond) {
+; CHECK-LABEL: @test_unswitch_dedicated_exiting(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B_EXIT:%.*]]
+; CHECK:       loop_b_exit:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    ret void
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b_exit
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b_exit:
+  call void @b()
+  call void @b()
+  call void @b()
+  call void @b()
+  ret void
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+define void @test_unswitch_dedicated_exiting_minsize(i1* %ptr, i1 %cond) #0 {
+; CHECK-LABEL: @test_unswitch_dedicated_exiting_minsize(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
+; CHECK:       entry.split.us:
+; CHECK-NEXT:    br label [[LOOP_BEGIN_US:%.*]]
+; CHECK:       loop_begin.us:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_A_US:%.*]]
+; CHECK:       loop_a.us:
+; CHECK-NEXT:    call void @a()
+; CHECK-NEXT:    br label [[LOOP_LATCH_US:%.*]]
+; CHECK:       loop_latch.us:
+; CHECK-NEXT:    [[V_US:%.*]] = load i1, i1* [[PTR:%.*]], align 1
+; CHECK-NEXT:    br i1 [[V_US]], label [[LOOP_BEGIN_US]], label [[LOOP_EXIT_SPLIT_US:%.*]]
+; CHECK:       loop_exit.split.us:
+; CHECK-NEXT:    br label [[LOOP_EXIT:%.*]]
+; CHECK:       entry.split:
+; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
+; CHECK:       loop_begin:
+; CHECK-NEXT:    call void @x()
+; CHECK-NEXT:    br label [[LOOP_B_EXIT:%.*]]
+; CHECK:       loop_b_exit:
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    call void @b()
+; CHECK-NEXT:    ret void
+; CHECK:       loop_exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop_begin
+
+loop_begin:
+  call void @x()
+  br i1 %cond, label %loop_a, label %loop_b_exit
+
+loop_a:
+  call void @a()
+  br label %loop_latch
+
+loop_b_exit:
+  call void @b()
+  call void @b()
+  call void @b()
+  call void @b()
+  ret void
+
+loop_latch:
+  %v = load i1, i1* %ptr
+  br i1 %v, label %loop_begin, label %loop_exit
+
+loop_exit:
+  ret void
+}
+
+attributes #0 = { minsize optsize }


        


More information about the llvm-commits mailing list