[llvm] [X86] Fold compares of widened vectors into masked compares (PR #228350)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 2 03:49:08 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Part of #<!-- -->226389

Masked compares are only matched from an `and` that has the same mask type as the compare. When the compared vectors have to be widened, e.g. `<2 x float>` to `v4f32`, the compare gives a `v4i1` and the `v2i1` `and` only sees it through an `extract_subvector`. The same shape shows up with legal types too, because DAGCombiner narrows an `and` when only its low elements are used. Either way nothing matched, and we ended up with separate compares and a chain of `kandw` instead of `vcmpltps ... %k1 {%k1}`.

`PreprocessISelDAG` now widens such an `and` to the type of the compare and takes the low elements of the result, so the existing patterns do the rest. It has to happen there rather than in a DAG combine, since `narrowExtractedVectorBinOp` would narrow the `and` right back. An `and` that already has a compare of its own type as an operand is left alone: `isel` can fold that one, and it is what tells us the upper mask bits are zero. 


---

Patch is 21.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/228350.diff


6 Files Affected:

- (modified) llvm/lib/Target/X86/X86ISelDAGToDAG.cpp (+55) 
- (modified) llvm/test/CodeGen/X86/avx512-insert-extract.ll (+2-3) 
- (modified) llvm/test/CodeGen/X86/avx512bw-intrinsics-fast-isel.ll (+4-6) 
- (modified) llvm/test/CodeGen/X86/bitcast-and-setcc-128.ll (+34-46) 
- (modified) llvm/test/CodeGen/X86/icmp-abs-C-vec.ll (+2-4) 
- (added) llvm/test/CodeGen/X86/pr226389.ll (+196) 


``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index c2de8283f15ff8..5692683f1ba340 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -985,6 +985,21 @@ static bool needBWI(MVT VT) {
   return (VT == MVT::v32i16 || VT == MVT::v32f16 || VT == MVT::v64i8);
 }
 
+// Return true if V is a compare that an AND can fold as a masked compare.
+static bool isSingleUseMaskCompare(SDValue V) {
+  return (V.getOpcode() == ISD::SETCC || V.getOpcode() == X86ISD::CMPM) &&
+         V.hasOneUse();
+}
+
+// Return the single-use wider compare that V is the low subvector of, if any.
+static SDValue getLowSubvectorMaskCompare(SDValue V) {
+  if (V.getOpcode() != ISD::EXTRACT_SUBVECTOR || !V.hasOneUse() ||
+      !isNullConstant(V.getOperand(1)))
+    return SDValue();
+  SDValue Src = V.getOperand(0);
+  return isSingleUseMaskCompare(Src) ? Src : SDValue();
+}
+
 void X86DAGToDAGISel::PreprocessISelDAG() {
   bool MadeChange = false;
   for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
@@ -1398,6 +1413,46 @@ void X86DAGToDAGISel::PreprocessISelDAG() {
       MadeChange = true;
       continue;
     }
+    case ISD::AND: {
+      // Masked compares only match an AND of the compare's type; widen the AND.
+      MVT VT = N->getSimpleValueType(0);
+      if (!VT.isVectorOf(MVT::i1))
+        break;
+
+      // Isel already folds this AND, or relies on its upper bits being zero.
+      SDValue N0 = N->getOperand(0);
+      SDValue N1 = N->getOperand(1);
+      if (isSingleUseMaskCompare(N0) || isSingleUseMaskCompare(N1) ||
+          isMaskZeroExtended(N))
+        break;
+
+      SDValue Cmp = getLowSubvectorMaskCompare(N1);
+      if (!Cmp)
+        Cmp = getLowSubvectorMaskCompare(N0);
+      if (!Cmp)
+        break;
+
+      SDLoc dl(N);
+      MVT WideVT = Cmp.getSimpleValueType();
+      SDValue ZeroIdx = CurDAG->getIntPtrConstant(0, dl);
+      auto Widen = [&](SDValue V) {
+        if (V.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
+            isNullConstant(V.getOperand(1)) &&
+            V.getOperand(0).getValueType() == WideVT)
+          return V.getOperand(0);
+        return CurDAG->getNode(ISD::INSERT_SUBVECTOR, dl, WideVT,
+                               CurDAG->getUNDEF(WideVT), V, ZeroIdx);
+      };
+      SDValue Wide0 = Widen(N0);
+      SDValue Wide1 = Widen(N1);
+      SDValue Res = CurDAG->getNode(ISD::AND, dl, WideVT, Wide0, Wide1);
+      Res = CurDAG->getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, Res, ZeroIdx);
+      --I;
+      CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Res);
+      ++I;
+      MadeChange = true;
+      continue;
+    }
     }
 
     if (OptLevel != CodeGenOptLevel::None &&
diff --git a/llvm/test/CodeGen/X86/avx512-insert-extract.ll b/llvm/test/CodeGen/X86/avx512-insert-extract.ll
index 4efc4678f1d002..b890a74cc2416e 100644
--- a/llvm/test/CodeGen/X86/avx512-insert-extract.ll
+++ b/llvm/test/CodeGen/X86/avx512-insert-extract.ll
@@ -2071,11 +2071,10 @@ define void @test_concat_v2i1(ptr %arg, ptr %arg1, ptr %arg2) nounwind {
 ; SKX-LABEL: test_concat_v2i1:
 ; SKX:       ## %bb.0:
 ; SKX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
-; SKX-NEXT:    vcvtph2ps %xmm0, %ymm0
-; SKX-NEXT:    vcmpltps {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %ymm0, %k0
 ; SKX-NEXT:    vxorps %xmm1, %xmm1, %xmm1
+; SKX-NEXT:    vcvtph2ps %xmm0, %ymm0
 ; SKX-NEXT:    vcmpltps %ymm0, %ymm1, %k1
-; SKX-NEXT:    kandw %k1, %k0, %k1
+; SKX-NEXT:    vcmpltps {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %ymm0, %k1 {%k1}
 ; SKX-NEXT:    vmovq {{.*#+}} xmm0 = mem[0],zero
 ; SKX-NEXT:    vmovdqu16 %xmm0, %xmm0 {%k1} {z}
 ; SKX-NEXT:    vmovd %xmm0, (%rdx)
diff --git a/llvm/test/CodeGen/X86/avx512bw-intrinsics-fast-isel.ll b/llvm/test/CodeGen/X86/avx512bw-intrinsics-fast-isel.ll
index ada2c8d53aa53a..4a5eb84d171701 100644
--- a/llvm/test/CodeGen/X86/avx512bw-intrinsics-fast-isel.ll
+++ b/llvm/test/CodeGen/X86/avx512bw-intrinsics-fast-isel.ll
@@ -15,13 +15,11 @@ define i64 @test_mm512_kunpackd(<8 x i64> %__A, <8 x i64> %__B, <8 x i64> %__C,
 ; X86-NEXT:    andl $-64, %esp
 ; X86-NEXT:    subl $64, %esp
 ; X86-NEXT:    vmovdqa64 136(%ebp), %zmm3
-; X86-NEXT:    vpcmpneqb %zmm0, %zmm1, %k0
-; X86-NEXT:    vpcmpneqb 8(%ebp), %zmm2, %k1
-; X86-NEXT:    vpcmpneqb 72(%ebp), %zmm3, %k2
-; X86-NEXT:    kandd %k0, %k2, %k0
+; X86-NEXT:    vpcmpneqb 72(%ebp), %zmm3, %k1
+; X86-NEXT:    vpcmpneqb %zmm0, %zmm1, %k0 {%k1}
 ; X86-NEXT:    kmovd %k0, %eax
-; X86-NEXT:    kshiftrq $32, %k2, %k0
-; X86-NEXT:    kandd %k1, %k0, %k0
+; X86-NEXT:    kshiftrq $32, %k1, %k1
+; X86-NEXT:    vpcmpneqb 8(%ebp), %zmm2, %k0 {%k1}
 ; X86-NEXT:    kmovd %k0, %edx
 ; X86-NEXT:    movl %ebp, %esp
 ; X86-NEXT:    popl %ebp
diff --git a/llvm/test/CodeGen/X86/bitcast-and-setcc-128.ll b/llvm/test/CodeGen/X86/bitcast-and-setcc-128.ll
index de030f1b78d3dc..055fb7bafbe81e 100644
--- a/llvm/test/CodeGen/X86/bitcast-and-setcc-128.ll
+++ b/llvm/test/CodeGen/X86/bitcast-and-setcc-128.ll
@@ -214,11 +214,10 @@ define i2 @v2i8(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
 ; AVX512F:       # %bb.0:
 ; AVX512F-NEXT:    vpcmpgtb %xmm1, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0
-; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm0
-; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm1
+; AVX512F-NEXT:    vpmovsxbd %xmm1, %zmm1
+; AVX512F-NEXT:    vptestmd %zmm1, %zmm1, %k1
+; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    vzeroupper
@@ -226,9 +225,8 @@ define i2 @v2i8(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
 ;
 ; AVX512BW-LABEL: v2i8:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
@@ -265,11 +263,10 @@ define i2 @v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c, <2 x i16> %d) {
 ; AVX512F:       # %bb.0:
 ; AVX512F-NEXT:    vpcmpgtw %xmm1, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpmovsxwd %xmm0, %ymm0
-; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k0
-; AVX512F-NEXT:    vpcmpgtw %xmm3, %xmm2, %xmm0
-; AVX512F-NEXT:    vpmovsxwd %xmm0, %ymm0
-; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtw %xmm3, %xmm2, %xmm1
+; AVX512F-NEXT:    vpmovsxwd %xmm1, %ymm1
+; AVX512F-NEXT:    vptestmd %ymm1, %ymm1, %k1
+; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    vzeroupper
@@ -277,9 +274,8 @@ define i2 @v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c, <2 x i16> %d) {
 ;
 ; AVX512BW-LABEL: v2i16:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtw %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtw %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtw %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtw %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
@@ -313,18 +309,16 @@ define i2 @v2i32(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c, <2 x i32> %d) {
 ;
 ; AVX512F-LABEL: v2i32:
 ; AVX512F:       # %bb.0:
-; AVX512F-NEXT:    vpcmpgtd %xmm1, %xmm0, %k0
-; AVX512F-NEXT:    vpcmpgtd %xmm3, %xmm2, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtd %xmm1, %xmm0, %k1
+; AVX512F-NEXT:    vpcmpgtd %xmm3, %xmm2, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    retq
 ;
 ; AVX512BW-LABEL: v2i32:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtd %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtd %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtd %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtd %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
@@ -462,11 +456,10 @@ define i4 @v4i8(<4 x i8> %a, <4 x i8> %b, <4 x i8> %c, <4 x i8> %d) {
 ; AVX512F:       # %bb.0:
 ; AVX512F-NEXT:    vpcmpgtb %xmm1, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0
-; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm0
-; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm1
+; AVX512F-NEXT:    vpmovsxbd %xmm1, %zmm1
+; AVX512F-NEXT:    vptestmd %zmm1, %zmm1, %k1
+; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    vzeroupper
@@ -474,9 +467,8 @@ define i4 @v4i8(<4 x i8> %a, <4 x i8> %b, <4 x i8> %c, <4 x i8> %d) {
 ;
 ; AVX512BW-LABEL: v4i8:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
@@ -512,11 +504,10 @@ define i4 @v4i16(<4 x i16> %a, <4 x i16> %b, <4 x i16> %c, <4 x i16> %d) {
 ; AVX512F:       # %bb.0:
 ; AVX512F-NEXT:    vpcmpgtw %xmm1, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpmovsxwd %xmm0, %ymm0
-; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k0
-; AVX512F-NEXT:    vpcmpgtw %xmm3, %xmm2, %xmm0
-; AVX512F-NEXT:    vpmovsxwd %xmm0, %ymm0
-; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtw %xmm3, %xmm2, %xmm1
+; AVX512F-NEXT:    vpmovsxwd %xmm1, %ymm1
+; AVX512F-NEXT:    vptestmd %ymm1, %ymm1, %k1
+; AVX512F-NEXT:    vptestmd %ymm0, %ymm0, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    vzeroupper
@@ -524,9 +515,8 @@ define i4 @v4i16(<4 x i16> %a, <4 x i16> %b, <4 x i16> %c, <4 x i16> %d) {
 ;
 ; AVX512BW-LABEL: v4i16:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtw %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtw %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtw %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtw %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
@@ -560,11 +550,10 @@ define i8 @v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c, <8 x i8> %d) {
 ; AVX512F:       # %bb.0:
 ; AVX512F-NEXT:    vpcmpgtb %xmm1, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0
-; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm0
-; AVX512F-NEXT:    vpmovsxbd %xmm0, %zmm0
-; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k1
-; AVX512F-NEXT:    kandw %k1, %k0, %k0
+; AVX512F-NEXT:    vpcmpgtb %xmm3, %xmm2, %xmm1
+; AVX512F-NEXT:    vpmovsxbd %xmm1, %zmm1
+; AVX512F-NEXT:    vptestmd %zmm1, %zmm1, %k1
+; AVX512F-NEXT:    vptestmd %zmm0, %zmm0, %k0 {%k1}
 ; AVX512F-NEXT:    kmovw %k0, %eax
 ; AVX512F-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512F-NEXT:    vzeroupper
@@ -572,9 +561,8 @@ define i8 @v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c, <8 x i8> %d) {
 ;
 ; AVX512BW-LABEL: v8i8:
 ; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k0
-; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k1
-; AVX512BW-NEXT:    kandw %k1, %k0, %k0
+; AVX512BW-NEXT:    vpcmpgtb %xmm1, %xmm0, %k1
+; AVX512BW-NEXT:    vpcmpgtb %xmm3, %xmm2, %k0 {%k1}
 ; AVX512BW-NEXT:    kmovd %k0, %eax
 ; AVX512BW-NEXT:    # kill: def $al killed $al killed $eax
 ; AVX512BW-NEXT:    retq
diff --git a/llvm/test/CodeGen/X86/icmp-abs-C-vec.ll b/llvm/test/CodeGen/X86/icmp-abs-C-vec.ll
index 23dcf334124c05..90d086c045fa67 100644
--- a/llvm/test/CodeGen/X86/icmp-abs-C-vec.ll
+++ b/llvm/test/CodeGen/X86/icmp-abs-C-vec.ll
@@ -1015,12 +1015,11 @@ define <4 x i1> @ne_and_to_abs_vec4x8(<4 x i8> %x) {
 ; AVX512-NEXT:    vpcmpeqb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1
 ; AVX512-NEXT:    vpternlogq {{.*#+}} xmm1 = ~xmm1
 ; AVX512-NEXT:    vpmovsxbd %xmm1, %zmm1
-; AVX512-NEXT:    vptestmd %zmm1, %zmm1, %k0
 ; AVX512-NEXT:    vpcmpeqb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0
 ; AVX512-NEXT:    vpternlogq {{.*#+}} xmm0 = ~xmm0
 ; AVX512-NEXT:    vpmovsxbd %xmm0, %zmm0
 ; AVX512-NEXT:    vptestmd %zmm0, %zmm0, %k1
-; AVX512-NEXT:    kandw %k1, %k0, %k1
+; AVX512-NEXT:    vptestmd %zmm1, %zmm1, %k1 {%k1}
 ; AVX512-NEXT:    vpcmpeqd %xmm0, %xmm0, %xmm0
 ; AVX512-NEXT:    vmovdqa32 %xmm0, %xmm0 {%k1} {z}
 ; AVX512-NEXT:    vzeroupper
@@ -1070,12 +1069,11 @@ define <4 x i16> @ne_and_to_abs_vec4x16_sext(<4 x i16> %x) {
 ; AVX512-NEXT:    vpcmpeqw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1
 ; AVX512-NEXT:    vpternlogq {{.*#+}} xmm1 = ~xmm1
 ; AVX512-NEXT:    vpmovsxwd %xmm1, %ymm1
-; AVX512-NEXT:    vptestmd %ymm1, %ymm1, %k0
 ; AVX512-NEXT:    vpcmpeqw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0
 ; AVX512-NEXT:    vpternlogq {{.*#+}} xmm0 = ~xmm0
 ; AVX512-NEXT:    vpmovsxwd %xmm0, %ymm0
 ; AVX512-NEXT:    vptestmd %ymm0, %ymm0, %k1
-; AVX512-NEXT:    kandw %k1, %k0, %k1
+; AVX512-NEXT:    vptestmd %ymm1, %ymm1, %k1 {%k1}
 ; AVX512-NEXT:    vpcmpeqd %ymm0, %ymm0, %ymm0
 ; AVX512-NEXT:    vmovdqa32 %ymm0, %ymm0 {%k1} {z}
 ; AVX512-NEXT:    vpmovdw %ymm0, %xmm0
diff --git a/llvm/test/CodeGen/X86/pr226389.ll b/llvm/test/CodeGen/X86/pr226389.ll
new file mode 100644
index 00000000000000..b25c7113dde0c3
--- /dev/null
+++ b/llvm/test/CodeGen/X86/pr226389.ll
@@ -0,0 +1,196 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f,+avx512vl,+avx512bw,+avx512dq | FileCheck %s
+
+; A compare of vectors that get widened should still be folded into the AND of
+; its result as a masked compare.
+
+define i8 @cmp_v2f32(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d, <2 x float> %e, <2 x float> %f) nounwind {
+; CHECK-LABEL: cmp_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm1, %k1
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm2, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm3, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm4, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm5, %k0 {%k1}
+; CHECK-NEXT:    kshiftlb $6, %k0, %k0
+; CHECK-NEXT:    kshiftrb $6, %k0, %k0
+; CHECK-NEXT:    kmovb %k0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    kmovd %k0, %eax
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %retval = alloca <2 x i1>, align 1
+  %cmp0 = fcmp ogt <2 x float> %a, %b
+  %cmp1 = fcmp ogt <2 x float> %a, %c
+  %and0 = and <2 x i1> %cmp0, %cmp1
+  %cmp2 = fcmp ogt <2 x float> %a, %d
+  %and1 = and <2 x i1> %and0, %cmp2
+  %cmp3 = fcmp ogt <2 x float> %a, %e
+  %and2 = and <2 x i1> %and1, %cmp3
+  %cmp4 = fcmp ogt <2 x float> %a, %f
+  %and3 = and <2 x i1> %and2, %cmp4
+  store <2 x i1> %and3, ptr %retval, align 1
+  %res = load i8, ptr %retval, align 1
+  ret i8 %res
+}
+
+define i8 @cmp_v2i32(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c, <2 x i32> %d, <2 x i32> %e, <2 x i32> %f) nounwind {
+; CHECK-LABEL: cmp_v2i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vpcmpgtd %xmm1, %xmm0, %k1
+; CHECK-NEXT:    vpcmpgtd %xmm2, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtd %xmm3, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtd %xmm4, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtd %xmm5, %xmm0, %k0 {%k1}
+; CHECK-NEXT:    kshiftlb $6, %k0, %k0
+; CHECK-NEXT:    kshiftrb $6, %k0, %k0
+; CHECK-NEXT:    kmovb %k0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    kmovd %k0, %eax
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %retval = alloca <2 x i1>, align 1
+  %cmp0 = icmp sgt <2 x i32> %a, %b
+  %cmp1 = icmp sgt <2 x i32> %a, %c
+  %and0 = and <2 x i1> %cmp0, %cmp1
+  %cmp2 = icmp sgt <2 x i32> %a, %d
+  %and1 = and <2 x i1> %and0, %cmp2
+  %cmp3 = icmp sgt <2 x i32> %a, %e
+  %and2 = and <2 x i1> %and1, %cmp3
+  %cmp4 = icmp sgt <2 x i32> %a, %f
+  %and3 = and <2 x i1> %and2, %cmp4
+  store <2 x i1> %and3, ptr %retval, align 1
+  %res = load i8, ptr %retval, align 1
+  ret i8 %res
+}
+
+define i8 @cmp_v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c, <2 x i16> %d, <2 x i16> %e, <2 x i16> %f) nounwind {
+; CHECK-LABEL: cmp_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vpcmpgtw %xmm1, %xmm0, %k1
+; CHECK-NEXT:    vpcmpgtw %xmm2, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm3, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm4, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm5, %xmm0, %k0 {%k1}
+; CHECK-NEXT:    kshiftlb $6, %k0, %k0
+; CHECK-NEXT:    kshiftrb $6, %k0, %k0
+; CHECK-NEXT:    kmovb %k0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    kmovd %k0, %eax
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %retval = alloca <2 x i1>, align 1
+  %cmp0 = icmp sgt <2 x i16> %a, %b
+  %cmp1 = icmp sgt <2 x i16> %a, %c
+  %and0 = and <2 x i1> %cmp0, %cmp1
+  %cmp2 = icmp sgt <2 x i16> %a, %d
+  %and1 = and <2 x i1> %and0, %cmp2
+  %cmp3 = icmp sgt <2 x i16> %a, %e
+  %and2 = and <2 x i1> %and1, %cmp3
+  %cmp4 = icmp sgt <2 x i16> %a, %f
+  %and3 = and <2 x i1> %and2, %cmp4
+  store <2 x i1> %and3, ptr %retval, align 1
+  %res = load i8, ptr %retval, align 1
+  ret i8 %res
+}
+
+define i8 @cmp_v4i16(<4 x i16> %a, <4 x i16> %b, <4 x i16> %c, <4 x i16> %d, <4 x i16> %e, <4 x i16> %f) nounwind {
+; CHECK-LABEL: cmp_v4i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vpcmpgtw %xmm1, %xmm0, %k1
+; CHECK-NEXT:    vpcmpgtw %xmm2, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm3, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm4, %xmm0, %k1 {%k1}
+; CHECK-NEXT:    vpcmpgtw %xmm5, %xmm0, %k0 {%k1}
+; CHECK-NEXT:    kshiftlb $4, %k0, %k0
+; CHECK-NEXT:    kshiftrb $4, %k0, %k0
+; CHECK-NEXT:    kmovb %k0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    kmovd %k0, %eax
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %retval = alloca <4 x i1>, align 1
+  %cmp0 = icmp sgt <4 x i16> %a, %b
+  %cmp1 = icmp sgt <4 x i16> %a, %c
+  %and0 = and <4 x i1> %cmp0, %cmp1
+  %cmp2 = icmp sgt <4 x i16> %a, %d
+  %and1 = and <4 x i1> %and0, %cmp2
+  %cmp3 = icmp sgt <4 x i16> %a, %e
+  %and2 = and <4 x i1> %and1, %cmp3
+  %cmp4 = icmp sgt <4 x i16> %a, %f
+  %and3 = and <4 x i1> %and2, %cmp4
+  store <4 x i1> %and3, ptr %retval, align 1
+  %res = load i8, ptr %retval, align 1
+  ret i8 %res
+}
+
+define i8 @cmp_v4f32(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d, <4 x float> %e, <4 x float> %f) nounwind {
+; CHECK-LABEL: cmp_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm1, %k1
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm2, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm3, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm4, %k1 {%k1}
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm5, %k0 {%k1}
+; CHECK-NEXT:    kmovb %k0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    kmovd %k0, %eax
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %retval = alloca <4 x i1>, align 1
+  %cmp0 = fcmp ogt <4 x float> %a, %b
+  %cmp1 = fcmp ogt <4 x float> %a, %c
+  %and0 = and <4 x i1> %cmp0, %cmp1
+  %cmp2 = fcmp ogt <4 x float> %a, %d
+  %and1 = and <4 x i1> %and0, %cmp2
+  %cmp3 = fcmp ogt <4 x float> %a, %e
+  %and2 = and <4 x i1> %and1, %cmp3
+  %cmp4 = fcmp ogt <4 x float> %a, %f
+  %and3 = and <4 x i1> %and2, %cmp4
+  store <4 x i1> %and3, ptr %retval, align 1
+  %res = load i8, ptr %retval, align 1
+  ret i8 %res
+}
+
+; Only the low half of the AND is used.
+define i2 @cmp_v4f32_extract(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d) nounwind {
+; CHECK-LABEL: cmp_v4f32_extract:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm1, %k1
+; CHECK-NEXT:    vcmpltps %xmm0, %xmm2, %k1 {%k1}
+; CHECK-NEXT:    vcmpl...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/228350


More information about the llvm-commits mailing list