Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -161,6 +161,11 @@ static cl::opt ShouldLowerDbgDeclare("instcombine-lower-dbg-declare", cl::Hidden, cl::init(true)); +static cl::opt + CanonicalizeBranchPredicates("instcombine-canonicalize-branch-predicates", + cl::Hidden, cl::init(true), + cl::desc("Canonicalize branch predicates")); + Optional InstCombiner::targetInstCombineIntrinsic(IntrinsicInst &II) { // Handle target specific intrinsics @@ -2814,7 +2819,8 @@ // Change br (not X), label True, label False to: br X, label False, True Value *X = nullptr; - if (match(&BI, m_Br(m_Not(m_Value(X)), m_BasicBlock(), m_BasicBlock())) && + if (CanonicalizeBranchPredicates && + match(&BI, m_Br(m_Not(m_Value(X)), m_BasicBlock(), m_BasicBlock())) && !isa(X)) { // Swap Destinations and condition... BI.swapSuccessors(); @@ -2830,7 +2836,8 @@ // Canonicalize, for example, fcmp_one -> fcmp_oeq. CmpInst::Predicate Pred; - if (match(&BI, m_Br(m_OneUse(m_FCmp(Pred, m_Value(), m_Value())), + if (CanonicalizeBranchPredicates && + match(&BI, m_Br(m_OneUse(m_FCmp(Pred, m_Value(), m_Value())), m_BasicBlock(), m_BasicBlock())) && !isCanonicalPredicate(Pred)) { // Swap destinations and condition. Index: llvm/test/Transforms/InstCombine/branch.ll =================================================================== --- llvm/test/Transforms/InstCombine/branch.ll +++ llvm/test/Transforms/InstCombine/branch.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -instcombine -S < %s | FileCheck %s -; RUN: opt -passes=instcombine -S < %s | FileCheck %s +; RUN: opt -instcombine -instcombine-canonicalize-branch-predicates=0 -S < %s | FileCheck %s +; RUN: opt -passes=instcombine -instcombine-canonicalize-branch-predicates=0 -S < %s | FileCheck %s ; Check that we fold the condition of branches of the ; form: br dest1, dest2, where dest1 == dest2. @@ -82,7 +82,8 @@ ; CHECK: if.false.1: ; CHECK-NEXT: br label [[MERGE_1]] ; CHECK: merge.1: -; CHECK-NEXT: br i1 [[COND]], label [[IF_FALSE_2:%.*]], label [[IF_TRUE_2:%.*]] +; CHECK: [[TMP0:%.*]] = xor i1 [[COND]], true +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]] ; CHECK: if.true.2: ; CHECK-NEXT: br label [[MERGE_2:%.*]] ; CHECK: if.false.2: Index: llvm/test/Transforms/InstCombine/canonicalize_branch.ll =================================================================== --- llvm/test/Transforms/InstCombine/canonicalize_branch.ll +++ llvm/test/Transforms/InstCombine/canonicalize_branch.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -instcombine -S | FileCheck %s +; RUN: opt < %s -instcombine -instcombine-canonicalize-branch-predicates=0 -S | FileCheck %s ; Test an already canonical branch to make sure we don't flip those. define i32 @eq(i32 %X, i32 %Y) { @@ -224,8 +224,8 @@ define i32 @f_oge(float %X, float %Y) { ; CHECK-LABEL: @f_oge( -; CHECK-NEXT: [[C:%.*]] = fcmp ult float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !13 +; CHECK-NEXT: [[C:%.*]] = fcmp oge float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !13 ; CHECK: T: ; CHECK-NEXT: ret i32 12 ; CHECK: F: @@ -258,8 +258,8 @@ define i32 @f_ole(float %X, float %Y) { ; CHECK-LABEL: @f_ole( -; CHECK-NEXT: [[C:%.*]] = fcmp ugt float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !15 +; CHECK-NEXT: [[C:%.*]] = fcmp ole float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !15 ; CHECK: T: ; CHECK-NEXT: ret i32 12 ; CHECK: F: @@ -275,8 +275,8 @@ define i32 @f_one(float %X, float %Y) { ; CHECK-LABEL: @f_one( -; CHECK-NEXT: [[C:%.*]] = fcmp ueq float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !16 +; CHECK-NEXT: [[C:%.*]] = fcmp one float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !16 ; CHECK: T: ; CHECK-NEXT: ret i32 12 ; CHECK: F: @@ -484,10 +484,10 @@ ; CHECK: !10 = {{.*}} i32 10, i32 99} ; CHECK: !11 = {{.*}} i32 11, i32 99} ; CHECK: !12 = {{.*}} i32 12, i32 99} -; CHECK: !13 = {{.*}} i32 99, i32 13} +; CHECK: !13 = {{.*}} i32 13, i32 99} ; CHECK: !14 = {{.*}} i32 14, i32 99} -; CHECK: !15 = {{.*}} i32 99, i32 15} -; CHECK: !16 = {{.*}} i32 99, i32 16} +; CHECK: !15 = {{.*}} i32 15, i32 99} +; CHECK: !16 = {{.*}} i32 16, i32 99} ; CHECK: !17 = {{.*}} i32 17, i32 99} ; CHECK: !18 = {{.*}} i32 18, i32 99} ; CHECK: !19 = {{.*}} i32 19, i32 99} Index: llvm/test/Transforms/InstCombine/select.ll =================================================================== --- llvm/test/Transforms/InstCombine/select.ll +++ llvm/test/Transforms/InstCombine/select.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -instcombine -S | FileCheck %s +; RUN: opt < %s -instcombine -instcombine-canonicalize-branch-predicates=0 -S | FileCheck %s ; PR1822 @@ -1700,7 +1700,8 @@ define i32 @select_dominating_inverted(i1 %cond, i32 %x, i32 %y) { ; CHECK-LABEL: @select_dominating_inverted( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: br i1 [[INVERTED]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: if.false: @@ -1775,7 +1776,8 @@ define i32 @select_dominating_cond_inverted_multiple_preds(i1 %cond, i1 %cond2, i1 %cond3, i32 %x, i32 %y) { ; CHECK-LABEL: @select_dominating_cond_inverted_multiple_preds( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: br i1 [[INVERTED]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: br i1 [[COND2:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_TRUE_2:%.*]] ; CHECK: if.true.1: @@ -1823,7 +1825,8 @@ define i32 @select_dominating_cond_inverted_multiple_duplicating_preds(i1 %cond, i32 %cond2, i1 %cond3, i32 %x, i32 %y) { ; CHECK-LABEL: @select_dominating_cond_inverted_multiple_duplicating_preds( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: br i1 [[INVERTED]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: switch i32 [[COND2:%.*]], label [[SWITCH_CASE_1:%.*]] [ ; CHECK-NEXT: i32 1, label [[MERGE:%.*]] @@ -2321,7 +2324,8 @@ define i32 @test_select_into_phi_not_idom_inverted(i1 %cond, i32 %A, i32 %B) { ; CHECK-LABEL: @test_select_into_phi_not_idom_inverted( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: br i1 [[INVERTED]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: if.false: @@ -2354,7 +2358,8 @@ define i32 @test_select_into_phi_not_idom_inverted_2(i1 %cond, i32 %A, i32 %B) { ; CHECK-LABEL: @test_select_into_phi_not_idom_inverted_2( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: br i1 [[INVERTED]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: if.false: Index: llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll =================================================================== --- llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll +++ llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -instcombine -instcombine-infinite-loop-threshold=2 -S | FileCheck %s +; RUN: opt < %s -instcombine -instcombine-infinite-loop-threshold=4 -instcombine-canonicalize-branch-predicates=0 -S | FileCheck %s ; These xor-of-icmps could be replaced with and-of-icmps, but %cond0 has extra ; uses, so we don't consider it, even though some cases are freely invertible. @@ -54,12 +54,12 @@ ret i1 %res } -; Branch is also freely invertible +; Branch is not freely invertible because it changes CFG. define i1 @v3_branch(i32 %X, i32* %dst0, i32* %dst1) { ; CHECK-LABEL: @v3_branch( ; CHECK-NEXT: begin: -; CHECK-NEXT: [[COND0:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: br i1 [[COND0]], label [[BB1:%.*]], label [[BB0:%.*]] +; CHECK-NEXT: [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767 +; CHECK-NEXT: br i1 [[COND0]], label %bb0, label %bb1 ; CHECK: bb0: ; CHECK-NEXT: store i32 0, i32* [[DST0:%.*]], align 4 ; CHECK-NEXT: br label [[END:%.*]] Index: llvm/test/Transforms/InstCombine/xor.ll =================================================================== --- llvm/test/Transforms/InstCombine/xor.ll +++ llvm/test/Transforms/InstCombine/xor.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -instcombine -S | FileCheck %s +; RUN: opt < %s -instcombine -instcombine-canonicalize-branch-predicates=0 -S | FileCheck %s @G1 = global i32 0 @G2 = global i32 0 @@ -79,7 +79,8 @@ define i8 @test8(i1 %c) { ; CHECK-LABEL: @test8( -; CHECK-NEXT: br i1 [[C:%.*]], label [[FALSE:%.*]], label [[TRUE:%.*]] +; CHECK-NEXT: [[D:%.*]] = xor i1 %c, true +; CHECK-NEXT: br i1 [[D]], label %True, label %False ; CHECK: True: ; CHECK-NEXT: ret i8 1 ; CHECK: False: