diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp --- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp @@ -2692,6 +2692,10 @@ // (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 @@ 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 --- /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 --- /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 }