https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/65845
>From 91af70acd72c8e889f542ba6dfff6401b89b2dc5 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Sat, 9 Sep 2023 16:47:24 +0800 Subject: [PATCH] [InstCombine] Fix transforms of select (~a | c), a, b and select (c & b), a, b --- .../InstCombine/InstCombineSelect.cpp | 17 +- .../Transforms/InstCombine/select-and-or.ll | 214 +++++++++++++----- 2 files changed, 166 insertions(+), 65 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 33d370690e71a8c..7913644d376f80b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3086,17 +3086,18 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) { m_c_LogicalOr(m_Deferred(A), m_Deferred(B))))) return BinaryOperator::CreateXor(A, B); - // select (~a | c), a, b -> and a, (or c, freeze(b)) + // select (~a | c), a, b -> select a, (select c, true, b), false if (match(CondVal, m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))) && CondVal->hasOneUse()) { - FalseVal = Builder.CreateFreeze(FalseVal); - return BinaryOperator::CreateAnd(TrueVal, Builder.CreateOr(C, FalseVal)); + Value *OrV = Builder.CreateSelect(C, One, FalseVal); + return SelectInst::Create(TrueVal, OrV, Zero); } - // select (~c & b), a, b -> and b, (or freeze(a), c) - if (match(CondVal, m_c_And(m_Not(m_Value(C)), m_Specific(FalseVal))) && - CondVal->hasOneUse()) { - TrueVal = Builder.CreateFreeze(TrueVal); - return BinaryOperator::CreateAnd(FalseVal, Builder.CreateOr(C, TrueVal)); + // select (c & b), a, b -> select b, (select ~c, true, a), false + if (match(CondVal, m_c_And(m_Value(C), m_Specific(FalseVal))) && + CondVal->hasOneUse() && isFreeToInvert(C, C->hasOneUse())) { + Value *NotC = Builder.CreateNot(C); + Value *OrV = Builder.CreateSelect(NotC, One, TrueVal); + return SelectInst::Create(FalseVal, OrV, Zero); } // select (a | c), a, b -> select a, true, (select ~c, b, false) if (match(CondVal, m_c_Or(m_Specific(TrueVal), m_Value(C))) && diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll index fb78f0affcb8f14..7edcd767b86ecba 100644 --- a/llvm/test/Transforms/InstCombine/select-and-or.ll +++ b/llvm/test/Transforms/InstCombine/select-and-or.ll @@ -453,9 +453,8 @@ define i1 @demorgan_select_infloop2(i1 %L) { define i1 @and_or1(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @and_or1( -; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[R]] ; %nota = xor i1 %a, true @@ -466,9 +465,8 @@ define i1 @and_or1(i1 %a, i1 %b, i1 %c) { define i1 @and_or2(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @and_or2( -; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[A:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[R]] ; %notc = xor i1 %c, true @@ -477,32 +475,32 @@ define i1 @and_or2(i1 %a, i1 %b, i1 %c) { ret i1 %r } -define i1 @and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { -; CHECK-LABEL: @and_or1_bundef( -; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[B:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]] +define i1 @and_or1_commuted(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or1_commuted( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[R]] ; %nota = xor i1 %a, true - %cond = or i1 %nota, %c + %cond = or i1 %c, %nota %r = select i1 %cond, i1 %a, i1 %b ret i1 %r } -define i1 @and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { -; CHECK-LABEL: @and_or2_aundef( -; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[A:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] +define i1 @and_or2_commuted(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or2_commuted( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false ; CHECK-NEXT: ret i1 [[R]] ; %notc = xor i1 %c, true - %cond = and i1 %notc, %b + %cond = and i1 %b, %notc %r = select i1 %cond, i1 %a, i1 %b ret i1 %r } -define i1 @no_and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { -; CHECK-LABEL: @no_and_or1_bundef( +define i1 @and_or1_multiuse(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or1_multiuse( ; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true ; CHECK-NEXT: [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]] ; CHECK-NEXT: call void @use(i1 [[COND]]) @@ -516,8 +514,8 @@ define i1 @no_and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { ret i1 %r } -define i1 @no_and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { -; CHECK-LABEL: @no_and_or2_aundef( +define i1 @and_or2_multiuse(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or2_multiuse( ; CHECK-NEXT: [[NOTC:%.*]] = xor i1 [[C:%.*]], true ; CHECK-NEXT: [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]] ; CHECK-NEXT: call void @use(i1 [[COND]]) @@ -531,38 +529,64 @@ define i1 @no_and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { ret i1 %r } -define i1 @and_or1_op1not(i1 %a, i1 %b) { -; CHECK-LABEL: @and_or1_op1not( -; CHECK-NEXT: [[C:%.*]] = call i1 @gen_i1() -; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[C]], [[TMP1]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]] -; CHECK-NEXT: ret i1 [[R]] +define <2 x i1> @and_or1_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_or1_vec( +; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] ; - %c = call i1 @gen_i1() - %nota = xor i1 %a, true - %cond = or i1 %c, %nota - %r = select i1 %cond, i1 %a, i1 %b - ret i1 %r + %c = call <2 x i1> @gen_v2i1() + %nota = xor <2 x i1> %a, <i1 true, i1 true> + %cond = or <2 x i1> %nota, %c + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r } -define i1 @and_or2_op1not(i1 %a, i1 %c) { -; CHECK-LABEL: @and_or2_op1not( -; CHECK-NEXT: [[B:%.*]] = call i1 @gen_i1() -; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[A:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[B]], [[TMP2]] -; CHECK-NEXT: ret i1 [[R]] +define <2 x i1> @and_or2_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_or2_vec( +; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] ; - %b = call i1 @gen_i1() - %notc = xor i1 %c, true - %cond = and i1 %b, %notc - %r = select i1 %cond, i1 %a, i1 %b - ret i1 %r + %c = call <2 x i1> @gen_v2i1() + %notc = xor <2 x i1> %c, <i1 true, i1 true> + %cond = and <2 x i1> %notc, %b + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r } -define i1 @neg_and_or1(i1 %a, i1 %b, i1 %c, i1 %d) { -; CHECK-LABEL: @neg_and_or1( +define <2 x i1> @and_or1_vec_commuted(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_or1_vec_commuted( +; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %c = call <2 x i1> @gen_v2i1() + %nota = xor <2 x i1> %a, <i1 true, i1 true> + %cond = or <2 x i1> %c, %nota + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r +} + +define <2 x i1> @and_or2_vec_commuted(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_or2_vec_commuted( +; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %c = call <2 x i1> @gen_v2i1() + %notc = xor <2 x i1> %c, <i1 true, i1 true> + %cond = and <2 x i1> %b, %notc + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r +} + +define i1 @and_or1_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @and_or1_wrong_operand( ; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true ; CHECK-NEXT: [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]] ; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[D:%.*]], i1 [[B:%.*]] @@ -574,8 +598,8 @@ define i1 @neg_and_or1(i1 %a, i1 %b, i1 %c, i1 %d) { ret i1 %r } -define i1 @neg_and_or2(i1 %a, i1 %b, i1 %c, i1 %d) { -; CHECK-LABEL: @neg_and_or2( +define i1 @and_or2_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @and_or2_wrong_operand( ; CHECK-NEXT: [[NOTC:%.*]] = xor i1 [[C:%.*]], true ; CHECK-NEXT: [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[D:%.*]] @@ -587,21 +611,97 @@ define i1 @neg_and_or2(i1 %a, i1 %b, i1 %c, i1 %d) { ret i1 %r } -define <2 x i1> @and_or1_op1not_vec(<2 x i1> %a, <2 x i1> %b) { -; CHECK-LABEL: @and_or1_op1not_vec( -; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() -; CHECK-NEXT: [[TMP1:%.*]] = freeze <2 x i1> [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]] -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[A:%.*]] +define i1 @and_or3(i1 %a, i1 %b, i32 %x, i32 %y) { +; CHECK-LABEL: @and_or3( +; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 true, i1 [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false +; CHECK-NEXT: ret i1 [[R]] +; + %c = icmp eq i32 %x, %y + %cond = and i1 %b, %c + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or3_commuted(i1 %a, i1 %b, i32 %x, i32 %y) { +; CHECK-LABEL: @and_or3_commuted( +; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 true, i1 [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false +; CHECK-NEXT: ret i1 [[R]] +; + %c = icmp eq i32 %x, %y + %cond = and i1 %c, %b + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or3_not_free_to_invert(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or3_not_free_to_invert( +; CHECK-NEXT: [[COND:%.*]] = and i1 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]] +; CHECK-NEXT: ret i1 [[R]] +; + %cond = and i1 %b, %c + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) { +; CHECK-LABEL: @and_or3_multiuse( +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[COND:%.*]] = and i1 [[C]], [[B:%.*]] +; CHECK-NEXT: call void @use(i1 [[COND]]) +; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]] +; CHECK-NEXT: ret i1 [[R]] +; + %c = icmp eq i32 %x, %y + %cond = and i1 %b, %c + call void @use(i1 %cond) + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define <2 x i1> @and_or3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @and_or3_vec( +; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; - %c = call <2 x i1> @gen_v2i1() - %nota = xor <2 x i1> %a, <i1 true, i1 true> - %cond = or <2 x i1> %c, %nota + %c = icmp eq <2 x i32> %x, %y + %cond = and <2 x i1> %b, %c %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b ret <2 x i1> %r } +define <2 x i1> @and_or3_vec_commuted(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @and_or3_vec_commuted( +; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %c = icmp eq <2 x i32> %x, %y + %cond = and <2 x i1> %c, %b + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r +} + +define i1 @and_or3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) { +; CHECK-LABEL: @and_or3_wrong_operand( +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[COND:%.*]] = and i1 [[C]], [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[D:%.*]] +; CHECK-NEXT: ret i1 [[R]] +; + %c = icmp eq i32 %x, %y + %cond = and i1 %b, %c + %r = select i1 %cond, i1 %a, i1 %d + ret i1 %r +} + define i1 @or_and1(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @or_and1( ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits