diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -724,7 +724,8 @@ LPM1.addPass(LoopRotatePass(Level != OptimizationLevel::Oz)); // TODO: Investigate promotion cap for O1. LPM1.addPass(LICMPass(PTO.LicmMssaOptCap, PTO.LicmMssaNoAccForPromotionCap)); - LPM1.addPass(SimpleLoopUnswitchPass(/* NonTrivial */ true)); + LPM1.addPass( + SimpleLoopUnswitchPass(/* NonTrivial */ Level == OptimizationLevel::O3)); LPM2.addPass(LoopIdiomRecognizePass()); LPM2.addPass(IndVarSimplifyPass()); 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 @@ -2906,6 +2906,10 @@ if (!NonTrivial && !EnableNonTrivialUnswitch) return false; + // Skip non-trivial unswitching for optsize functions. + if (L.getHeader()->getParent()->hasOptSize()) + return false; + // For non-trivial unswitching, because it often creates new loops, we rely on // the pass manager to iterate on the loops rather than trying to immediately // reach a fixed point. There is no substantial advantage to iterating diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll --- a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll @@ -111,33 +111,19 @@ 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-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-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-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 ; @@ -235,39 +221,25 @@ 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: br label [[LOOP_BEGIN:%.*]] +; CHECK: loop_begin: ; CHECK-NEXT: call void @x() -; CHECK-NEXT: br label [[LOOP_A_US:%.*]] -; CHECK: loop_a.us: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[LOOP_A:%.*]], label [[LOOP_B:%.*]] +; CHECK: loop_a: ; 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-NEXT: br label [[LOOP_LATCH:%.*]] ; 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-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-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 ; @@ -387,45 +359,31 @@ 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-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-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-NEXT: br i1 [[V3]], label [[LOOP_BEGIN]], label [[LOOP_EXIT:%.*]] ; CHECK: loop_exit: ; CHECK-NEXT: ret void ; @@ -666,31 +624,22 @@ 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-NEXT: br i1 [[COND:%.*]], label [[LOOP_A:%.*]], label [[LOOP_B_EXIT:%.*]] +; CHECK: loop_a: +; CHECK-NEXT: call void @a() +; CHECK-NEXT: br label [[LOOP_LATCH:%.*]] ; 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_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 ; diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/pipeline.ll b/llvm/test/Transforms/SimpleLoopUnswitch/pipeline.ll --- a/llvm/test/Transforms/SimpleLoopUnswitch/pipeline.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/pipeline.ll @@ -1,12 +1,15 @@ -; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefix=O1 -; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefix=O2 +; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefixes=TRIVIAL,CHECK +; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefixes=TRIVIAL,CHECK +; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefixes=NONTRIVIAL,CHECK +; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefixes=TRIVIAL,CHECK +; RUN: opt < %s -S -passes="default" | FileCheck %s -check-prefixes=TRIVIAL,CHECK declare i32 @a() declare i32 @b() declare i32 @c() -; O1-NOT: loop_begin.us: -; O2: loop_begin.us: +; TRIVIAL-NOT: loop_begin.us: +; NONTRIVIAL: loop_begin.us: define i32 @test1(i1* %ptr, i1 %cond1, i1 %cond2) { entry: @@ -37,3 +40,34 @@ loop_exit: ret i32 0 } + +; CHECK-NOT: loop2_begin.us: +define i32 @test2(i1* %ptr, i1 %cond1, i1 %cond2) optsize { +entry: + br label %loop2_begin + +loop2_begin: + br i1 %cond1, label %loop2_a, label %loop2_b + +loop2_a: + call i32 @a() + br label %latch2 + +loop2_b: + br i1 %cond2, label %loop2_b_a, label %loop2_b_b + +loop2_b_a: + call i32 @b() + br label %latch2 + +loop2_b_b: + call i32 @c() + br label %latch2 + +latch2: + %v = load i1, i1* %ptr + br i1 %v, label %loop2_begin, label %loop2_exit + +loop2_exit: + ret i32 0 +}