}
/// OR combines for which the commuted variant will be tried as well.
-static SDValue visitORCommutative(
- SelectionDAG &DAG, SDValue N0, SDValue N1, SDNode *N) {
+static SDValue visitORCommutative(SelectionDAG &DAG, SDValue N0, SDValue N1,
+ SDNode *N) {
EVT VT = N0.getValueType();
if (N0.getOpcode() == ISD::AND) {
+ SDValue N00 = N0.getOperand(0);
+ SDValue N01 = N0.getOperand(1);
+
// fold (or (and X, (xor Y, -1)), Y) -> (or X, Y)
// TODO: Set AllowUndefs = true.
- if (getBitwiseNotOperand(N0.getOperand(1), N0.getOperand(0),
+ if (getBitwiseNotOperand(N01, N00,
/* AllowUndefs */ false) == N1)
- return DAG.getNode(ISD::OR, SDLoc(N), VT, N0.getOperand(0), N1);
+ return DAG.getNode(ISD::OR, SDLoc(N), VT, N00, N1);
// fold (or (and (xor Y, -1), X), Y) -> (or X, Y)
- if (getBitwiseNotOperand(N0.getOperand(0), N0.getOperand(1),
+ if (getBitwiseNotOperand(N00, N01,
/* AllowUndefs */ false) == N1)
- return DAG.getNode(ISD::OR, SDLoc(N), VT, N0.getOperand(1), N1);
+ return DAG.getNode(ISD::OR, SDLoc(N), VT, N01, N1);
+
+ // (or (and X, C1), (and (or X, Y), C2)) -> (or (and X, C1|C2), (and Y, C2))
+ if (N1.getOpcode() == ISD::AND) {
+ SDValue N10 = N1.getOperand(0);
+ if (N10.getOpcode() == ISD::OR) {
+ SDValue N11 = N1.getOperand(1);
+ SDValue N100 = N10.getOperand(0);
+ SDValue N101 = N10.getOperand(1);
+ if (((N00 == N100) || (N00 == N101)) && N0->hasOneUse() &&
+ N1->hasOneUse()) {
+ SDLoc DL(N);
+ if (SDValue C12 =
+ DAG.FoldConstantArithmetic(ISD::OR, DL, VT, {N01, N11})) {
+ SDValue Y = (N00 == N100 ? N101 : N100);
+ return DAG.getNode(ISD::OR, DL, VT,
+ DAG.getNode(ISD::AND, DL, VT, N00, C12),
+ DAG.getNode(ISD::AND, DL, VT, Y, N11));
+ }
+ }
+ }
+ }
}
if (SDValue R = foldLogicOfShifts(N, N0, N1, DAG))
ret <4 x i32> %2
}
-; FIXME: fold (or (and X, C1), (and (or X, Y), C2)) -> (or (and X, C1|C2), (and Y, C2))
+; fold (or (and X, C1), (and (or X, Y), C2)) -> (or (and X, C1|C2), (and Y, C2))
define i32 @or_and_and_i32(i32 %x, i32 %y) {
; CHECK-LABEL: or_and_and_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
-; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
-; CHECK-NEXT: orl %edi, %esi
-; CHECK-NEXT: andl $8, %edi
+; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: andl $-11, %esi
-; CHECK-NEXT: leal (%rsi,%rdi), %eax
+; CHECK-NEXT: andl $-3, %eax
+; CHECK-NEXT: orl %esi, %eax
; CHECK-NEXT: retq
%xy = or i32 %x, %y
%mx = and i32 %x, 8
define i64 @or_and_and_commute_i64(i64 %x, i64 %y) {
; CHECK-LABEL: or_and_and_commute_i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: movq %rsi, %rax
-; CHECK-NEXT: orq %rdi, %rax
-; CHECK-NEXT: andl $8, %edi
+; CHECK-NEXT: movq %rdi, %rax
+; CHECK-NEXT: orq %rsi, %rax
; CHECK-NEXT: andq $-3, %rax
-; CHECK-NEXT: orq %rdi, %rax
; CHECK-NEXT: retq
%xy = or i64 %x, %y
%mx = and i64 %x, 8
define <4 x i32> @or_and_and_v4i32(<4 x i32> %x, <4 x i32> %y) {
; CHECK-LABEL: or_and_and_v4i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: orps %xmm0, %xmm1
-; CHECK-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
; CHECK-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; CHECK-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
; CHECK-NEXT: orps %xmm1, %xmm0
; CHECK-NEXT: retq
%xy = or <4 x i32> %x, %y