// Try to match two logic ops to a VPTERNLOG.
// FIXME: Handle inverted inputs?
// FIXME: Handle more complex patterns that use an operand more than once?
-// FIXME: Support X86ISD::ANDNP
bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
MVT NVT = N->getSimpleValueType(0);
SDValue N1 = N->getOperand(1);
auto isLogicOp = [](unsigned Opc) {
- return Opc == ISD::AND || Opc == ISD::OR || Opc == ISD::XOR;
+ return Opc == ISD::AND || Opc == ISD::OR || Opc == ISD::XOR ||
+ Opc == X86ISD::ANDNP;
};
SDValue A, B, C;
case ISD::AND:
switch (Opc2) {
default: llvm_unreachable("Unexpected opcode!");
- case ISD::AND: Imm = 0x80; break;
- case ISD::OR: Imm = 0xe0; break;
- case ISD::XOR: Imm = 0x60; break;
+ case ISD::AND: Imm = 0x80; break;
+ case ISD::OR: Imm = 0xe0; break;
+ case ISD::XOR: Imm = 0x60; break;
+ case X86ISD::ANDNP: Imm = 0x20; break;
}
break;
case ISD::OR:
switch (Opc2) {
default: llvm_unreachable("Unexpected opcode!");
- case ISD::AND: Imm = 0xf8; break;
- case ISD::OR: Imm = 0xfe; break;
- case ISD::XOR: Imm = 0xf6; break;
+ case ISD::AND: Imm = 0xf8; break;
+ case ISD::OR: Imm = 0xfe; break;
+ case ISD::XOR: Imm = 0xf6; break;
+ case X86ISD::ANDNP: Imm = 0xf2; break;
}
break;
case ISD::XOR:
switch (Opc2) {
default: llvm_unreachable("Unexpected opcode!");
- case ISD::AND: Imm = 0x78; break;
- case ISD::OR: Imm = 0x1e; break;
- case ISD::XOR: Imm = 0x96; break;
+ case ISD::AND: Imm = 0x78; break;
+ case ISD::OR: Imm = 0x1e; break;
+ case ISD::XOR: Imm = 0x96; break;
+ case X86ISD::ANDNP: Imm = 0xd2; break;
}
break;
}
ret <16 x float> %4
}
+define <16 x i32> @ternlog_and_andn(<16 x i32> %x, <16 x i32> %y, <16 x i32> %z) {
+; ALL-LABEL: ternlog_and_andn:
+; ALL: ## %bb.0:
+; ALL-NEXT: vpternlogd $8, %zmm1, %zmm2, %zmm0
+; ALL-NEXT: retq
+ %a = xor <16 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <16 x i32> %y, %a
+ %c = and <16 x i32> %b, %z
+ ret <16 x i32> %c
+}
+
+define <16 x i32> @ternlog_or_andn(<16 x i32> %x, <16 x i32> %y, <16 x i32> %z) {
+; ALL-LABEL: ternlog_or_andn:
+; ALL: ## %bb.0:
+; ALL-NEXT: vpternlogd $206, %zmm1, %zmm2, %zmm0
+; ALL-NEXT: retq
+ %a = xor <16 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <16 x i32> %y, %a
+ %c = or <16 x i32> %b, %z
+ ret <16 x i32> %c
+}
+
+define <16 x i32> @ternlog_xor_andn(<16 x i32> %x, <16 x i32> %y, <16 x i32> %z) {
+; ALL-LABEL: ternlog_xor_andn:
+; ALL: ## %bb.0:
+; ALL-NEXT: vpternlogd $198, %zmm1, %zmm2, %zmm0
+; ALL-NEXT: retq
+ %a = xor <16 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <16 x i32> %y, %a
+ %c = xor <16 x i32> %b, %z
+ ret <16 x i32> %c
+}
%4 = select <4 x i1> %extract.i, <4 x float> %2, <4 x float> zeroinitializer
ret <4 x float> %4
}
+
+define <4 x i32> @ternlog_and_andn(<4 x i32> %x, <4 x i32> %y, <4 x i32> %z) {
+; CHECK-LABEL: ternlog_and_andn:
+; CHECK: ## %bb.0:
+; CHECK-NEXT: vpternlogd $8, %xmm1, %xmm2, %xmm0
+; CHECK-NEXT: retq
+ %a = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <4 x i32> %y, %a
+ %c = and <4 x i32> %b, %z
+ ret <4 x i32> %c
+}
+
+define <4 x i32> @ternlog_or_andn(<4 x i32> %x, <4 x i32> %y, <4 x i32> %z) {
+; CHECK-LABEL: ternlog_or_andn:
+; CHECK: ## %bb.0:
+; CHECK-NEXT: vpternlogd $206, %xmm1, %xmm2, %xmm0
+; CHECK-NEXT: retq
+ %a = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <4 x i32> %y, %a
+ %c = or <4 x i32> %b, %z
+ ret <4 x i32> %c
+}
+
+define <4 x i32> @ternlog_xor_andn(<4 x i32> %x, <4 x i32> %y, <4 x i32> %z) {
+; CHECK-LABEL: ternlog_xor_andn:
+; CHECK: ## %bb.0:
+; CHECK-NEXT: vpternlogd $198, %xmm1, %xmm2, %xmm0
+; CHECK-NEXT: retq
+ %a = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
+ %b = and <4 x i32> %y, %a
+ %c = xor <4 x i32> %b, %z
+ ret <4 x i32> %c
+}