Skip to content

Commit

Permalink
[InstCombine] Fix transforms of two select patterns (#65845)
Browse files Browse the repository at this point in the history
This patch fixes transforms of `select (~a | c), a, b` and `select (c &
b), a, b` as discussed in [D158983](https://reviews.llvm.org/D158983).
Alive2: https://alive2.llvm.org/ce/z/ft6TDw
  • Loading branch information
dtcxzyw committed Sep 17, 2023
1 parent a054d89 commit 1679b20
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 51 deletions.
31 changes: 16 additions & 15 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3099,28 +3099,29 @@ 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))
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));
}
// 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 (~a | c), a, b -> select a, (select c, true, b), false
if (match(CondVal,
m_OneUse(m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))))) {
Value *OrV = Builder.CreateSelect(C, One, FalseVal);
return SelectInst::Create(TrueVal, OrV, Zero);
}
// select (c & b), a, b -> select b, (select ~c, true, a), false
if (match(CondVal, m_OneUse(m_c_And(m_Value(C), m_Specific(FalseVal)))) &&
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))) &&
CondVal->hasOneUse() && isFreeToInvert(C, C->hasOneUse())) {
if (match(CondVal, m_OneUse(m_c_Or(m_Specific(TrueVal), m_Value(C)))) &&
isFreeToInvert(C, C->hasOneUse())) {
Value *NotC = Builder.CreateNot(C);
Value *AndV = Builder.CreateSelect(NotC, FalseVal, Zero);
return SelectInst::Create(TrueVal, One, AndV);
}
// select (c & ~b), a, b -> select b, true, (select c, a, false)
if (match(CondVal, m_c_And(m_Value(C), m_Not(m_Specific(FalseVal)))) &&
CondVal->hasOneUse()) {
if (match(CondVal,
m_OneUse(m_c_And(m_Value(C), m_Not(m_Specific(FalseVal)))))) {
Value *AndV = Builder.CreateSelect(C, TrueVal, Zero);
return SelectInst::Create(FalseVal, One, AndV);
}
Expand Down
64 changes: 28 additions & 36 deletions llvm/test/Transforms/InstCombine/select-and-or.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -479,9 +477,8 @@ define i1 @and_or2(i1 %a, i1 %b, i1 %c) {

define i1 @and_or1_commuted(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @and_or1_commuted(
; 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
Expand All @@ -492,9 +489,8 @@ define i1 @and_or1_commuted(i1 %a, i1 %b, i1 %c) {

define i1 @and_or2_commuted(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @and_or2_commuted(
; 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
Expand Down Expand Up @@ -536,9 +532,8 @@ define i1 @and_or2_multiuse(i1 %a, i1 %b, i1 %c) {
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:%.*]] = freeze <2 x i1> [[B:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[A:%.*]]
; 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()
Expand All @@ -551,9 +546,8 @@ define <2 x i1> @and_or1_vec(<2 x i1> %a, <2 x i1> %b) {
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:%.*]] = freeze <2 x i1> [[A:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[B:%.*]]
; 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()
Expand All @@ -566,9 +560,8 @@ define <2 x i1> @and_or2_vec(<2 x i1> %a, <2 x i1> %b) {
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:%.*]] = freeze <2 x i1> [[B:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[A:%.*]]
; 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()
Expand All @@ -581,9 +574,8 @@ define <2 x i1> @and_or1_vec_commuted(<2 x i1> %a, <2 x i1> %b) {
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:%.*]] = freeze <2 x i1> [[A:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[B:%.*]]
; 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()
Expand Down Expand Up @@ -621,9 +613,9 @@ define i1 @and_or2_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) {

define i1 @and_or3(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @and_or3(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[COND:%.*]] = and i1 [[C]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]]
; 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
Expand All @@ -634,9 +626,9 @@ define i1 @and_or3(i1 %a, i1 %b, i32 %x, i32 %y) {

define i1 @and_or3_commuted(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @and_or3_commuted(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[COND:%.*]] = and i1 [[C]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]]
; 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
Expand Down Expand Up @@ -673,9 +665,9 @@ define i1 @and_or3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) {

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 eq <2 x i32> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[COND:%.*]] = and <2 x i1> [[C]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A:%.*]], <2 x i1> [[B]]
; 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
Expand All @@ -686,9 +678,9 @@ define <2 x i1> @and_or3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %

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 eq <2 x i32> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[COND:%.*]] = and <2 x i1> [[C]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A:%.*]], <2 x i1> [[B]]
; 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
Expand Down

0 comments on commit 1679b20

Please sign in to comment.