[InstSimplify] (x | y) & (x | !y) --> x
https://alive2.llvm.org/ce/z/QagQMn This fold is handled by instcombine via SimplifyUsingDistributiveLaws(), but we are missing the sibliing fold for 'logical and' (implemented with 'select'). Retrofitting the code in instcombine looks much harder than just adding a small adjustment here, and this is potentially more efficient and beneficial to other passes.
This commit is contained in:
@@ -2042,11 +2042,19 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
||||
if (match(Op1, m_c_Or(m_Specific(Op0), m_Value())))
|
||||
return Op0;
|
||||
|
||||
// (X | Y) & (X | ~Y) --> X (commuted 8 ways)
|
||||
Value *X, *Y;
|
||||
if (match(Op0, m_c_Or(m_Value(X), m_Not(m_Value(Y)))) &&
|
||||
match(Op1, m_c_Or(m_Deferred(X), m_Deferred(Y))))
|
||||
return X;
|
||||
if (match(Op1, m_c_Or(m_Value(X), m_Not(m_Value(Y)))) &&
|
||||
match(Op0, m_c_Or(m_Deferred(X), m_Deferred(Y))))
|
||||
return X;
|
||||
|
||||
if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::And))
|
||||
return V;
|
||||
|
||||
// A mask that only clears known zeros of a shifted value is a no-op.
|
||||
Value *X;
|
||||
const APInt *Mask;
|
||||
const APInt *ShAmt;
|
||||
if (match(Op1, m_APInt(Mask))) {
|
||||
@@ -2143,7 +2151,7 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
||||
// if Mask = ((1 << effective_width_of(X)) - 1) << A
|
||||
// SimplifyDemandedBits in InstCombine can optimize the general case.
|
||||
// This pattern aims to help other passes for a common case.
|
||||
Value *Y, *XShifted;
|
||||
Value *XShifted;
|
||||
if (match(Op1, m_APInt(Mask)) &&
|
||||
match(Op0, m_c_Or(m_CombineAnd(m_NUWShl(m_Value(X), m_APInt(ShAmt)),
|
||||
m_Value(XShifted)),
|
||||
|
||||
@@ -9,13 +9,11 @@ define i32 @poison(i32 %x) {
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
; (X | Y) & (X | ~Y) --> X (commuted 8 ways)
|
||||
|
||||
define i8 @or_or_not_commute0(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute0(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[X:%.*]], [[Y]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %x, %y
|
||||
@@ -26,11 +24,7 @@ define i8 @or_or_not_commute0(i8 %x, i8 %y) {
|
||||
|
||||
define <2 x i5> @or_or_not_commute1(<2 x i5> %x, <2 x i5> %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute1(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor <2 x i5> [[Y:%.*]], <i5 -1, i5 -1>
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or <2 x i5> [[X:%.*]], [[Y]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or <2 x i5> [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and <2 x i5> [[XORYNOT]], [[XORY]]
|
||||
; CHECK-NEXT: ret <2 x i5> [[AND]]
|
||||
; CHECK-NEXT: ret <2 x i5> [[X:%.*]]
|
||||
;
|
||||
%ynot = xor <2 x i5> %y, <i5 -1, i5 -1>
|
||||
%xory = or <2 x i5> %x, %y
|
||||
@@ -41,11 +35,7 @@ define <2 x i5> @or_or_not_commute1(<2 x i5> %x, <2 x i5> %y) {
|
||||
|
||||
define <2 x i8> @or_or_not_commute2(<2 x i8> %x, <2 x i8> %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute2(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor <2 x i8> [[Y:%.*]], <i8 poison, i8 -1>
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or <2 x i8> [[X:%.*]], [[Y]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or <2 x i8> [[YNOT]], [[X]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[XORY]], [[XORYNOT]]
|
||||
; CHECK-NEXT: ret <2 x i8> [[AND]]
|
||||
; CHECK-NEXT: ret <2 x i8> [[X:%.*]]
|
||||
;
|
||||
%ynot = xor <2 x i8> %y, <i8 poison, i8 -1>
|
||||
%xory = or <2 x i8> %x, %y
|
||||
@@ -56,11 +46,7 @@ define <2 x i8> @or_or_not_commute2(<2 x i8> %x, <2 x i8> %y) {
|
||||
|
||||
define i8 @or_or_not_commute3(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute3(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[X:%.*]], [[Y]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %x, %y
|
||||
@@ -70,11 +56,7 @@ define i8 @or_or_not_commute3(i8 %x, i8 %y) {
|
||||
}
|
||||
define i8 @or_or_not_commute4(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute4(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %y, %x
|
||||
@@ -85,11 +67,7 @@ define i8 @or_or_not_commute4(i8 %x, i8 %y) {
|
||||
|
||||
define i8 @or_or_not_commute5(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute5(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %y, %x
|
||||
@@ -100,11 +78,7 @@ define i8 @or_or_not_commute5(i8 %x, i8 %y) {
|
||||
|
||||
define i8 @or_or_not_commute6(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute6(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %y, %x
|
||||
@@ -115,11 +89,7 @@ define i8 @or_or_not_commute6(i8 %x, i8 %y) {
|
||||
|
||||
define i8 @or_or_not_commute7(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_or_not_commute7(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
; CHECK-NEXT: ret i8 [[X:%.*]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xory = or i8 %y, %x
|
||||
@@ -127,3 +97,37 @@ define i8 @or_or_not_commute7(i8 %x, i8 %y) {
|
||||
%and = and i8 %xorynot, %xory
|
||||
ret i8 %and
|
||||
}
|
||||
|
||||
; negative test - wrong logic op
|
||||
|
||||
define i8 @or_xor_not(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @or_xor_not(
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XXORY:%.*]] = xor i8 [[Y]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORYNOT]], [[XXORY]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
;
|
||||
%ynot = xor i8 %y, -1
|
||||
%xxory = xor i8 %y, %x
|
||||
%xorynot = or i8 %x, %ynot
|
||||
%and = and i8 %xorynot, %xxory
|
||||
ret i8 %and
|
||||
}
|
||||
|
||||
; negative test - must have common operands
|
||||
|
||||
define i8 @or_or_not_no_common_op(i8 %x, i8 %y, i8 %z) {
|
||||
; CHECK-LABEL: @or_or_not_no_common_op(
|
||||
; CHECK-NEXT: [[XORZ:%.*]] = or i8 [[Z:%.*]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
|
||||
; CHECK-NEXT: [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XORYNOT]], [[XORZ]]
|
||||
; CHECK-NEXT: ret i8 [[AND]]
|
||||
;
|
||||
%xorz = or i8 %z, %x
|
||||
%ynot = xor i8 %y, -1
|
||||
%xorynot = or i8 %x, %ynot
|
||||
%and = and i8 %xorynot, %xorz
|
||||
ret i8 %and
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user