Skip to content

Commit 5c759ed

Browse files
committed
[InstCombine] reduce another or-xor bitwise logic pattern
~(A & ?) | (A ^ B) --> ~((A & ?) & B) https://alive2.llvm.org/ce/z/mxex6V This is similar to 9d218b6 where we peeked through another logic op to find a common operand.
1 parent fbfac8e commit 5c759ed

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,19 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
30123012
(match(Op0, m_Not(m_Specific(A))) || match(Op0, m_Not(m_Specific(B)))))
30133013
return BinaryOperator::CreateNot(Builder.CreateAnd(A, B));
30143014

3015+
// Same as above, but peek through an 'and' to the common operand:
3016+
// ~(A & ?) | (A ^ B) --> ~((A & ?) & B)
3017+
// ~(B & ?) | (A ^ B) --> ~((B & ?) & A)
3018+
Instruction *And;
3019+
if ((Op0->hasOneUse() || Op1->hasOneUse()) &&
3020+
match(Op0, m_Not(m_CombineAnd(m_Instruction(And),
3021+
m_c_And(m_Specific(A), m_Value())))))
3022+
return BinaryOperator::CreateNot(Builder.CreateAnd(And, B));
3023+
if ((Op0->hasOneUse() || Op1->hasOneUse()) &&
3024+
match(Op0, m_Not(m_CombineAnd(m_Instruction(And),
3025+
m_c_And(m_Specific(B), m_Value())))))
3026+
return BinaryOperator::CreateNot(Builder.CreateAnd(And, A));
3027+
30153028
// (~A | C) | (A ^ B) --> ~(A & B) | C
30163029
// (~B | C) | (A ^ B) --> ~(A & B) | C
30173030
if (Op0->hasOneUse() && Op1->hasOneUse() &&

llvm/test/Transforms/InstCombine/or-xor.ll

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -960,9 +960,8 @@ define i8 @or_not_xor_common_op_use2(i8 %x, i8 %y, i8 %z) {
960960
define i4 @or_nand_xor_common_op_commute0(i4 %x, i4 %y, i4 %z) {
961961
; CHECK-LABEL: @or_nand_xor_common_op_commute0(
962962
; CHECK-NEXT: [[AND:%.*]] = and i4 [[X:%.*]], [[Z:%.*]]
963-
; CHECK-NEXT: [[NAND:%.*]] = xor i4 [[AND]], -1
964-
; CHECK-NEXT: [[XOR:%.*]] = xor i4 [[X]], [[Y:%.*]]
965-
; CHECK-NEXT: [[R:%.*]] = or i4 [[XOR]], [[NAND]]
963+
; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[AND]], [[Y:%.*]]
964+
; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], -1
966965
; CHECK-NEXT: ret i4 [[R]]
967966
;
968967
%and = and i4 %x, %z
@@ -975,9 +974,8 @@ define i4 @or_nand_xor_common_op_commute0(i4 %x, i4 %y, i4 %z) {
975974
define <2 x i4> @or_nand_xor_common_op_commute1(<2 x i4> %x, <2 x i4> %y, <2 x i4> %z) {
976975
; CHECK-LABEL: @or_nand_xor_common_op_commute1(
977976
; CHECK-NEXT: [[AND:%.*]] = and <2 x i4> [[Z:%.*]], [[X:%.*]]
978-
; CHECK-NEXT: [[NAND:%.*]] = xor <2 x i4> [[AND]], <i4 poison, i4 -1>
979-
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i4> [[X]], [[Y:%.*]]
980-
; CHECK-NEXT: [[R:%.*]] = or <2 x i4> [[XOR]], [[NAND]]
977+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i4> [[AND]], [[Y:%.*]]
978+
; CHECK-NEXT: [[R:%.*]] = xor <2 x i4> [[TMP1]], <i4 -1, i4 -1>
981979
; CHECK-NEXT: ret <2 x i4> [[R]]
982980
;
983981
%and = and <2 x i4> %z, %x
@@ -991,9 +989,8 @@ define i8 @or_nand_xor_common_op_commute2(i8 %x, i8 %y, i8 %z) {
991989
; CHECK-LABEL: @or_nand_xor_common_op_commute2(
992990
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], [[Z:%.*]]
993991
; CHECK-NEXT: call void @use(i8 [[AND]])
994-
; CHECK-NEXT: [[NAND:%.*]] = xor i8 [[AND]], -1
995-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y:%.*]], [[X]]
996-
; CHECK-NEXT: [[R:%.*]] = or i8 [[XOR]], [[NAND]]
992+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[AND]], [[Y:%.*]]
993+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP1]], -1
997994
; CHECK-NEXT: ret i8 [[R]]
998995
;
999996
%and = and i8 %x, %z
@@ -1009,8 +1006,8 @@ define i8 @or_nand_xor_common_op_commute3(i8 %x, i8 %y, i8 %z) {
10091006
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], [[X:%.*]]
10101007
; CHECK-NEXT: [[NAND:%.*]] = xor i8 [[AND]], -1
10111008
; CHECK-NEXT: call void @use(i8 [[NAND]])
1012-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y:%.*]], [[X]]
1013-
; CHECK-NEXT: [[R:%.*]] = or i8 [[XOR]], [[NAND]]
1009+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[AND]], [[Y:%.*]]
1010+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP1]], -1
10141011
; CHECK-NEXT: ret i8 [[R]]
10151012
;
10161013
%and = and i8 %z, %x
@@ -1024,10 +1021,10 @@ define i8 @or_nand_xor_common_op_commute3(i8 %x, i8 %y, i8 %z) {
10241021
define i8 @or_nand_xor_common_op_commute3_use2(i8 %x, i8 %y, i8 %z) {
10251022
; CHECK-LABEL: @or_nand_xor_common_op_commute3_use2(
10261023
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], [[X:%.*]]
1027-
; CHECK-NEXT: [[NAND:%.*]] = xor i8 [[AND]], -1
10281024
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y:%.*]], [[X]]
10291025
; CHECK-NEXT: call void @use(i8 [[XOR]])
1030-
; CHECK-NEXT: [[R:%.*]] = or i8 [[XOR]], [[NAND]]
1026+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[AND]], [[Y]]
1027+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP1]], -1
10311028
; CHECK-NEXT: ret i8 [[R]]
10321029
;
10331030
%and = and i8 %z, %x
@@ -1038,6 +1035,8 @@ define i8 @or_nand_xor_common_op_commute3_use2(i8 %x, i8 %y, i8 %z) {
10381035
ret i8 %r
10391036
}
10401037

1038+
; negative test - too many extra uses
1039+
10411040
define i8 @or_nand_xor_common_op_commute3_use3(i8 %x, i8 %y, i8 %z) {
10421041
; CHECK-LABEL: @or_nand_xor_common_op_commute3_use3(
10431042
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], [[X:%.*]]

0 commit comments

Comments
 (0)