Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2798,19 +2798,26 @@ (CondVal->hasOneUse() || FalseVal->hasOneUse())) { bool CondLogicAnd = isa(CondVal); bool FalseLogicAnd = isa(FalseVal); - if (CondLogicAnd && FalseLogicAnd) { - // (A ? B : 0) ? 1 : (A ? D : 0) --> A ? (B ? 1 : D) : 0 + auto AndFactorization = [&](Value *Common, Value *InnerCond, + Value *InnerVal, + bool SelFirst = false) -> Instruction * { + Value *InnerSel = Builder.CreateSelect(InnerCond, One, InnerVal); + if (SelFirst) + std::swap(Common, InnerSel); + if (CondLogicAnd || FalseLogicAnd) + return SelectInst::Create(Common, InnerSel, Zero); + else + return BinaryOperator::CreateAnd(Common, InnerSel); + }; + if (!CondLogicAnd || FalseLogicAnd) { if (A == C) - return SelectInst::Create(A, Builder.CreateSelect(B, One, D), Zero); - // (A ? B : 0) ? 1 : (C ? A : 0) --> A ? (B ? 1 : C) : 0 + return AndFactorization(A, B, D); if (A == D) - return SelectInst::Create(A, Builder.CreateSelect(B, One, C), Zero); - // (A ? B : 0) ? 1 : (B ? D : 0) --> B ? (A ? 1 : D) : 0 + return AndFactorization(A, B, C); if (B == C) - return SelectInst::Create(B, Builder.CreateSelect(A, One, D), Zero); - // (A ? B : 0) ? 1 : (C ? B : 0) --> (A ? 1 : C) ? B : 0 + return AndFactorization(B, A, D); if (B == D) - return SelectInst::Create(Builder.CreateSelect(A, One, C), B, Zero); + return AndFactorization(B, A, C, CondLogicAnd && FalseLogicAnd); } } } @@ -2833,19 +2840,27 @@ (CondVal->hasOneUse() || TrueVal->hasOneUse())) { bool CondLogicOr = isa(CondVal); bool TrueLogicOr = isa(TrueVal); - if (CondLogicOr && TrueLogicOr) { - // (A ? 1 : B) ? (A ? 1 : D) : 0 --> A ? 1 : (B ? D : 0) + auto OrFactorization = [&](Value *Common, Value *InnerCond, + Value *InnerVal, + bool SelFirst = false) -> Instruction * { + Value *InnerSel = Builder.CreateSelect(InnerCond, InnerVal, Zero); + if (SelFirst) + std::swap(Common, InnerSel); + if (CondLogicOr || TrueLogicOr) + return SelectInst::Create(Common, One, InnerSel); + else + return BinaryOperator::CreateOr(Common, InnerSel); + }; + + if (!CondLogicOr || TrueLogicOr) { if (A == C) - return SelectInst::Create(A, One, Builder.CreateSelect(B, D, Zero)); - // (A ? 1 : B) ? (C ? 1 : A) : 0 --> A ? 1 : (B ? C : 0) + return OrFactorization(A, B, D); if (A == D) - return SelectInst::Create(A, One, Builder.CreateSelect(B, C, Zero)); - // (A ? 1 : B) ? (B ? 1 : D) : 0 --> B ? 1 : (A ? D : 0) + return OrFactorization(A, B, C); if (B == C) - return SelectInst::Create(B, One, Builder.CreateSelect(A, D, Zero)); - // (A ? 1 : B) ? (C ? 1 : B) : 0 --> (A ? C : 0) ? 1 : B + return OrFactorization(B, A, D); if (B == D) - return SelectInst::Create(Builder.CreateSelect(A, C, Zero), One, B); + return OrFactorization(B, A, C, CondLogicOr && TrueLogicOr); } } } Index: llvm/test/Transforms/InstCombine/select-factorize.ll =================================================================== --- llvm/test/Transforms/InstCombine/select-factorize.ll +++ llvm/test/Transforms/InstCombine/select-factorize.ll @@ -169,8 +169,8 @@ define i1 @and_logic_and_logic_or_1(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_logic_and_logic_or_1( -; CHECK-NEXT: [[BC:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[BC]], i1 false +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[OR]] ; %ac = and i1 %c, %a @@ -181,9 +181,8 @@ define i1 @and_logic_and_logic_or_2(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_logic_and_logic_or_2( -; CHECK-NEXT: [[AC:%.*]] = and i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = select i1 [[B:%.*]], i1 [[C]], i1 false -; CHECK-NEXT: [[OR:%.*]] = select i1 [[AC]], i1 true, i1 [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[OR]] ; %ac = and i1 %c, %a @@ -194,8 +193,8 @@ define i1 @and_logic_and_logic_or_3(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_logic_and_logic_or_3( -; CHECK-NEXT: [[BC:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[BC]], i1 false +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[OR]] ; %ac = and i1 %a, %c @@ -204,6 +203,8 @@ ret i1 %or } +; negative test: and is not last select condition + define i1 @and_logic_and_logic_or_4(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_logic_and_logic_or_4( ; CHECK-NEXT: [[AC:%.*]] = and i1 [[A:%.*]], [[C:%.*]] @@ -219,8 +220,8 @@ define <3 x i1> @and_logic_and_logic_or_vector(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @and_logic_and_logic_or_vector( -; CHECK-NEXT: [[BC:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> [[BC]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> [[TMP1]], <3 x i1> zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = and <3 x i1> %c, %a @@ -243,8 +244,8 @@ define <3 x i1> @and_logic_and_logic_or_vector_poison2(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @and_logic_and_logic_or_vector_poison2( -; CHECK-NEXT: [[BC:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> [[BC]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> [[TMP1]], <3 x i1> zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = and <3 x i1> %c, %a @@ -253,6 +254,8 @@ ret <3 x i1> %or } +; negative test: not one use for both op + define i1 @and_logic_and_logic_or_not_one_use(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_logic_and_logic_or_not_one_use( ; CHECK-NEXT: [[AC:%.*]] = and i1 [[A:%.*]], [[C:%.*]] @@ -272,9 +275,8 @@ define i1 @and_and_logic_or_1(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_and_logic_or_1( -; CHECK-NEXT: [[AC:%.*]] = and i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = and i1 [[C]], [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[AC]], i1 true, i1 [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = and i1 [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = and i1 %c, %a @@ -285,9 +287,8 @@ define i1 @and_and_logic_or_2(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_and_logic_or_2( -; CHECK-NEXT: [[AC:%.*]] = and i1 [[A:%.*]], [[C:%.*]] -; CHECK-NEXT: [[BC:%.*]] = and i1 [[C]], [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[BC]], i1 true, i1 [[AC]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]] +; CHECK-NEXT: [[OR:%.*]] = and i1 [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = and i1 %a, %c @@ -298,9 +299,8 @@ define <3 x i1> @and_and_logic_or_vector(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @and_and_logic_or_vector( -; CHECK-NEXT: [[AC:%.*]] = and <3 x i1> [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = and <3 x i1> [[C]], [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[AC]], <3 x i1> , <3 x i1> [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = and <3 x i1> [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = and <3 x i1> %c, %a @@ -311,9 +311,8 @@ define <3 x i1> @and_and_logic_or_vector_poison(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @and_and_logic_or_vector_poison( -; CHECK-NEXT: [[AC:%.*]] = and <3 x i1> [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = and <3 x i1> [[C]], [[B:%.*]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[AC]], <3 x i1> , <3 x i1> [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> , <3 x i1> [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = and <3 x i1> [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = and <3 x i1> %c, %a @@ -322,6 +321,8 @@ ret <3 x i1> %or } +; negative test : extra use for both cond/falseval + define i1 @and_and_logic_or_not_one_use(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @and_and_logic_or_not_one_use( ; CHECK-NEXT: [[AC:%.*]] = and i1 [[A:%.*]], [[C:%.*]] @@ -505,8 +506,8 @@ define i1 @or_logic_or_logic_and_1(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_logic_or_logic_and_1( -; CHECK-NEXT: [[BC:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false -; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[TMP1]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = or i1 %c, %a @@ -517,9 +518,8 @@ define i1 @or_logic_or_logic_and_2(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_logic_or_logic_and_2( -; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[C]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[AC]], i1 [[BC]], i1 false +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[TMP1]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = or i1 %c, %a @@ -528,6 +528,8 @@ ret i1 %or } +; negative test: or is not last select condition + define i1 @or_logic_or_logic_and_3(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_logic_or_logic_and_3( ; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] @@ -541,6 +543,8 @@ ret i1 %or } +; negative test: or is not last select condition + define i1 @or_logic_or_logic_and_4(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_logic_or_logic_and_4( ; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] @@ -556,8 +560,8 @@ define <3 x i1> @or_logic_or_logic_and_vector(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @or_logic_or_logic_and_vector( -; CHECK-NEXT: [[BC:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> zeroinitializer -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> , <3 x i1> [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> , <3 x i1> [[TMP1]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = or <3 x i1> %c, %a @@ -580,8 +584,8 @@ define <3 x i1> @or_logic_or_logic_and_vector_poison2(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @or_logic_or_logic_and_vector_poison2( -; CHECK-NEXT: [[BC:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> , <3 x i1> [[BC]] +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[C:%.*]], <3 x i1> , <3 x i1> [[TMP1]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = or <3 x i1> %c, %a @@ -590,6 +594,8 @@ ret <3 x i1> %or } +; negative test: not one use for both op + define i1 @or_logic_or_logic_and_not_one_use(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_logic_or_logic_and_not_one_use( ; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] @@ -609,9 +615,8 @@ define i1 @or_or_logic_and_1(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_or_logic_and_1( -; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = or i1 [[B:%.*]], [[C]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[AC]], i1 [[BC]], i1 false +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false +; CHECK-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = or i1 %c, %a @@ -622,9 +627,8 @@ define i1 @or_or_logic_and_2(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_or_logic_and_2( -; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = or i1 [[B:%.*]], [[C]] -; CHECK-NEXT: [[OR:%.*]] = select i1 [[BC]], i1 [[AC]], i1 false +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false +; CHECK-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret i1 [[OR]] ; %ac = or i1 %c, %a @@ -635,9 +639,8 @@ define <3 x i1> @or_or_logic_and_vector(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @or_or_logic_and_vector( -; CHECK-NEXT: [[AC:%.*]] = or <3 x i1> [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = or <3 x i1> [[B:%.*]], [[C]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[AC]], <3 x i1> [[BC]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[OR:%.*]] = or <3 x i1> [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = or <3 x i1> %c, %a @@ -648,9 +651,8 @@ define <3 x i1> @or_or_logic_and_vector_poison(<3 x i1> %c, <3 x i1> %a, <3 x i1> %b) { ; CHECK-LABEL: @or_or_logic_and_vector_poison( -; CHECK-NEXT: [[AC:%.*]] = or <3 x i1> [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[BC:%.*]] = or <3 x i1> [[B:%.*]], [[C]] -; CHECK-NEXT: [[OR:%.*]] = select <3 x i1> [[AC]], <3 x i1> [[BC]], <3 x i1> +; CHECK-NEXT: [[TMP1:%.*]] = select <3 x i1> [[A:%.*]], <3 x i1> [[B:%.*]], <3 x i1> zeroinitializer +; CHECK-NEXT: [[OR:%.*]] = or <3 x i1> [[TMP1]], [[C:%.*]] ; CHECK-NEXT: ret <3 x i1> [[OR]] ; %ac = or <3 x i1> %c, %a @@ -659,6 +661,8 @@ ret <3 x i1> %or } +; negative test : extra use for both cond/trueval + define i1 @or_or_logic_and_not_one_use(i1 %c, i1 %a, i1 %b) { ; CHECK-LABEL: @or_or_logic_and_not_one_use( ; CHECK-NEXT: [[AC:%.*]] = or i1 [[C:%.*]], [[A:%.*]]