[llvm] [DAG] computeKnownFPClass - add ISD::EXTRACT_VECTOR_ELT handling (PR #190307)

Xinlong Chen via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 19 01:20:32 PDT 2026


https://github.com/Xinlong-Chen updated https://github.com/llvm/llvm-project/pull/190307

>From 2ee1c2d50803c337ca109ebd467e1522c4d2c42a Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Fri, 3 Apr 2026 11:49:18 +0800
Subject: [PATCH 1/4] [DAG] computeKnownFPClass - add ISD::EXTRACT_VECTOR_ELT
 handling

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 20 +++++++
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 55 +++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 6eb8853550a19..a572ce62ab56d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6076,6 +6076,26 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     }
     break;
   }
+  case ISD::EXTRACT_VECTOR_ELT: {
+    SDValue Src = Op.getOperand(0);
+    auto *CIdx = dyn_cast<ConstantSDNode>(Op.getOperand(1));
+    EVT SrcVT = Src.getValueType();
+    if (SrcVT.isFixedLengthVector() && CIdx) {
+      if (CIdx->getAPIntValue().ult(SrcVT.getVectorNumElements())) {
+        APInt DemandedSrcElts = APInt::getOneBitSet(
+            SrcVT.getVectorNumElements(), CIdx->getZExtValue());
+        Known = computeKnownFPClass(Src, DemandedSrcElts, InterestedClasses,
+                                    Depth + 1);
+      } else {
+        // Out of bounds index is poison.
+        Known.KnownFPClasses = fcNone;
+        Known.SignBit = false;
+      }
+    } else {
+      Known = computeKnownFPClass(Src, InterestedClasses, Depth + 1);
+    }
+    break;
+  }
   case ISD::BITCAST: {
     // FIXME: It should not be necessary to check for an elementwise bitcast.
     // If a bitcast is not elementwise between vector / scalar types,
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 0292df415a655..90cacfe3b1a91 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -21,3 +21,58 @@ define i8 @iszero_constant_v4f32() nounwind {
   %r = bitcast <8 x i1> %f to i8
   ret i8 %r
 }
+
+define i1 @extract_nonconst_idx_const_vec_isnan(i32 %idx) nounwind {
+; CHECK-LABEL: extract_nonconst_idx_const_vec_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %elt = extractelement <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, i32 %idx
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
+  ret i1 %res
+}
+
+define i1 @extract_oob_idx_const_vec_isnan() nounwind {
+; CHECK-LABEL: extract_oob_idx_const_vec_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 768
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %elt = extractelement <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, i32 6
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
+  ret i1 %res
+}
+
+define i1 @extract_fabs_vec_isneg(<4 x float> %a0) nounwind {
+; CHECK-LABEL: extract_fabs_vec_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a0)
+  %elt = extractelement <4 x float> %abs, i32 2
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  ret i1 %res
+}
+
+define i1 @extract_fabs_unknown_idx_isneg(<4 x float> %a0, i32 %idx) nounwind {
+; CHECK-LABEL: extract_fabs_unknown_idx_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a0)
+  %elt = extractelement <4 x float> %abs, i32 %idx
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  ret i1 %res
+}
+
+define i1 @extract_scalable_fabs_isneg(<vscale x 4 x float> %a0) nounwind {
+; CHECK-LABEL: extract_scalable_fabs_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %abs = call <vscale x 4 x float> @llvm.fabs.nxv4f32(<vscale x 4 x float> %a0)
+  %elt = extractelement <vscale x 4 x float> %abs, i32 0
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  ret i1 %res
+}

>From 9ec20c68f4c5a49bde1a3844da7eccf651585e43 Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Wed, 8 Apr 2026 22:02:00 +0800
Subject: [PATCH 2/4] add test for isnan

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  8 +++++
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 32 +++++++++----------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 383e45c5ea3a8..210c1bb274214 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -16056,6 +16056,14 @@ SDValue DAGCombiner::visitIS_FPCLASS(SDNode *N) {
 
   KnownFPClass Known = DAG.computeKnownFPClass(Src, Mask);
 
+  // All possible classes ruled out: result is always false.
+  if ((Mask & Known.KnownFPClasses) == fcNone)
+    return DAG.getBoolConstant(false, DL, VT, Src.getValueType());
+
+  // All possible classes are within the mask: result is always true.
+  if ((~Mask & Known.KnownFPClasses) == fcNone)
+    return DAG.getBoolConstant(true, DL, VT, Src.getValueType());
+
   // Clear test bits we know must be false from the source value.
   // fp_class (nnan x), qnan|snan|other -> fp_class (nnan x), other
   // fp_class (ninf x), ninf|pinf|other -> fp_class (ninf x), other
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 73b896b7427bc..eff60da042018 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -22,36 +22,35 @@ define i8 @iszero_constant_v4f32() nounwind {
   ret i8 %r
 }
 
-define i1 @extract_nonconst_idx_const_vec_isnan(i32 %idx) nounwind {
-; CHECK-LABEL: extract_nonconst_idx_const_vec_isnan:
+define i1 @extract_idx0_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=0, isnan -> true
+; CHECK-LABEL: extract_idx0_const_vec_isnan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    li a0, 1
 ; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, i32 %idx
+  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 0
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
 
-define i1 @extract_oob_idx_const_vec_isnan() nounwind {
-; CHECK-LABEL: extract_oob_idx_const_vec_isnan:
+define i1 @extract_idx1_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=1, isnan -> false
+; CHECK-LABEL: extract_idx1_const_vec_isnan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 768
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, i32 6
+  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 1
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
 
-define i1 @extract_fabs_vec_isneg(<4 x float> %a0) nounwind {
-; CHECK-LABEL: extract_fabs_vec_isneg:
+define i1 @extract_oob_idx_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=6 (OOB), isnan -> poison
+; CHECK-LABEL: extract_oob_idx_const_vec_isnan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 768
+; CHECK-NEXT:    snez a0, a0
 ; CHECK-NEXT:    ret
-  %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a0)
-  %elt = extractelement <4 x float> %abs, i32 2
-  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 6
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
 
@@ -106,4 +105,3 @@ define <vscale x 2 x i1> @splat_constant_f64_isinf_false() {
   %res = call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f64(<vscale x 2 x double> splat (double 1.0), i32 516) ; 516 = inf
   ret <vscale x 2 x i1> %res
 }
-

>From 36b432cdcacfb297de8b4c1280029d9f06fc9998 Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Sun, 12 Apr 2026 22:55:08 +0800
Subject: [PATCH 3/4] fix poison and add negative tests

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  4 +--
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 36 ++++++++++++++++---
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 0ba257673acd2..db37e73859cad 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8398,12 +8398,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
     if (N1.isUndef() || N2.isUndef())
       return getUNDEF(VT);
 
-    // EXTRACT_VECTOR_ELT of out-of-bounds element is an UNDEF for fixed length
+    // EXTRACT_VECTOR_ELT of out-of-bounds element is an POISON for fixed length
     // vectors. For scalable vectors we will provide appropriate support for
     // dealing with arbitrary indices.
     if (N2C && N1.getValueType().isFixedLengthVector() &&
         N2C->getAPIntValue().uge(N1.getValueType().getVectorNumElements()))
-      return getUNDEF(VT);
+      return getPOISON(VT);
 
     // EXTRACT_VECTOR_ELT of CONCAT_VECTORS is often formed while lowering is
     // expanding copies of large vectors from registers. This only works for
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 799d6ebf03d6c..a95b09d164fd7 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -42,12 +42,20 @@ define i1 @extract_idx1_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf,
   ret i1 %res
 }
 
-define i1 @extract_oob_idx_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=6 (OOB), isnan -> poison
+define i1 @extract_const_vec_unknown_idx_isnan(i32 %idx) nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, unknown idx, isnan -> cannot fold
+; CHECK-LABEL: extract_const_vec_unknown_idx_isnan:
+; CHECK:       # %bb.0:
+; CHECK:    fclass.s
+; CHECK:    ret
+  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 %idx
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
+  ret i1 %res
+}
+
+define i1 @extract_oob_idx_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=6 (OOB) -> poison, folds away
 ; CHECK-LABEL: extract_oob_idx_const_vec_isnan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 768
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 6
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
@@ -76,6 +84,26 @@ define i1 @extract_scalable_fabs_isneg(<vscale x 4 x float> %a0) nounwind {
   ret i1 %res
 }
 
+define i1 @extract_const_vec_unknown_idx_isneg(i32 %idx) nounwind {  ; vec = <-1, 2, -3, 4>, unknown idx, isneg -> cannot fold
+; CHECK-LABEL: extract_const_vec_unknown_idx_isneg:
+; CHECK:       # %bb.0:
+; CHECK:    fclass.s
+; CHECK:    ret
+  %elt = extractelement <4 x float> <float -1.0, float 2.0, float -3.0, float 4.0>, i32 %idx
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  ret i1 %res
+}
+
+define i1 @extract_const_vec_known_neg_idx_isneg() nounwind {  ; vec = <-1, 2, -3, 4>, idx=0, isneg -> true
+; CHECK-LABEL: extract_const_vec_known_neg_idx_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 1
+; CHECK-NEXT:    ret
+  %elt = extractelement <4 x float> <float -1.0, float 2.0, float -3.0, float 4.0>, i32 0
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
+  ret i1 %res
+}
+
 define <vscale x 4 x i1> @splat_constant_is_pos_normal() {
 ; CHECK-LABEL: splat_constant_is_pos_normal:
 ; CHECK:       # %bb.0:

>From 440ce14334c630b03c24a3e92bcc4fa6794fabce Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Sun, 19 Apr 2026 15:15:40 +0800
Subject: [PATCH 4/4] delete useless code in this pr

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |   8 -
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |   4 +-
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 154 +++++++++++++-----
 3 files changed, 119 insertions(+), 47 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 1c0b470d8250c..a184e0b590092 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -16060,14 +16060,6 @@ SDValue DAGCombiner::visitIS_FPCLASS(SDNode *N) {
 
   KnownFPClass Known = DAG.computeKnownFPClass(Src, Mask);
 
-  // All possible classes ruled out: result is always false.
-  if ((Mask & Known.KnownFPClasses) == fcNone)
-    return DAG.getBoolConstant(false, DL, VT, Src.getValueType());
-
-  // All possible classes are within the mask: result is always true.
-  if ((~Mask & Known.KnownFPClasses) == fcNone)
-    return DAG.getBoolConstant(true, DL, VT, Src.getValueType());
-
   // Clear test bits we know must be false from the source value.
   // fp_class (nnan x), qnan|snan|other -> fp_class (nnan x), other
   // fp_class (ninf x), ninf|pinf|other -> fp_class (ninf x), other
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index db37e73859cad..0ba257673acd2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8398,12 +8398,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
     if (N1.isUndef() || N2.isUndef())
       return getUNDEF(VT);
 
-    // EXTRACT_VECTOR_ELT of out-of-bounds element is an POISON for fixed length
+    // EXTRACT_VECTOR_ELT of out-of-bounds element is an UNDEF for fixed length
     // vectors. For scalable vectors we will provide appropriate support for
     // dealing with arbitrary indices.
     if (N2C && N1.getValueType().isFixedLengthVector() &&
         N2C->getAPIntValue().uge(N1.getValueType().getVectorNumElements()))
-      return getPOISON(VT);
+      return getUNDEF(VT);
 
     // EXTRACT_VECTOR_ELT of CONCAT_VECTORS is often formed while lowering is
     // expanding copies of large vectors from registers. This only works for
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index a95b09d164fd7..9f46d98fa26bb 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -22,42 +22,142 @@ define i8 @iszero_constant_v4f32() nounwind {
   ret i8 %r
 }
 
-define i1 @extract_idx0_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=0, isnan -> true
-; CHECK-LABEL: extract_idx0_const_vec_isnan:
+define i1 @extract_bitcast_sign_set_not_pos(<4 x i32> %bits, ptr %p) nounwind {  ; elts 0,2 sign set, idx=0, ispos -> false
+; CHECK-LABEL: extract_bitcast_sign_set_not_pos:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 1
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vid.v v9
+; CHECK-NEXT:    vsll.vi v9, v9, 31
+; CHECK-NEXT:    lui a1, 524288
+; CHECK-NEXT:    vrsub.vx v9, v9, a1
+; CHECK-NEXT:    vor.vv v8, v8, v9
+; CHECK-NEXT:    vse32.v v8, (a0)
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 0
-  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
+  %masked = or <4 x i32> %bits, <i32 u0x80000000, i32 0, i32 u0x80000000, i32 0>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 0
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 960)  ; 0x3C0 = any positive
   ret i1 %res
 }
 
-define i1 @extract_idx1_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=1, isnan -> false
-; CHECK-LABEL: extract_idx1_const_vec_isnan:
+define i1 @extract_bitcast_unknown_sign_ispos(<4 x i32> %bits, ptr %p) nounwind {  ; elts 0,2 sign set, idx=1 unknown sign, ispos -> cannot fold
+; CHECK-LABEL: extract_bitcast_unknown_sign_ispos:
 ; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vid.v v9
+; CHECK-NEXT:    vsll.vi v9, v9, 31
+; CHECK-NEXT:    lui a1, 524288
+; CHECK-NEXT:    vrsub.vx v9, v9, a1
+; CHECK-NEXT:    vor.vv v8, v8, v9
+; CHECK-NEXT:    vslidedown.vi v9, v8, 1
+; CHECK-NEXT:    vfmv.f.s fa5, v9
+; CHECK-NEXT:    fclass.s a1, fa5
+; CHECK-NEXT:    andi a1, a1, 240
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    vse32.v v8, (a0)
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    ret
+  %masked = or <4 x i32> %bits, <i32 u0x80000000, i32 0, i32 u0x80000000, i32 0>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 1
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 960)  ; 0x3C0 = any positive
+  ret i1 %res
+}
+
+define i1 @extract_bitcast_not_nan(<4 x i32> %bits, ptr %p) nounwind {  ; elts 0,2 exp bit cleared (not NaN), idx=0, isnan -> false
+; CHECK-LABEL: extract_bitcast_not_nan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a1, 786432
+; CHECK-NEXT:    addi a1, a1, -1
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vmv.v.x v9, a1
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vand.vv v8, v8, v9
+; CHECK-NEXT:    vse32.v v8, (a0)
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 1
+  %masked = and <4 x i32> %bits, <i32 u0xBFFFFFFF, i32 -1, i32 u0xBFFFFFFF, i32 -1>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 0
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
 
-define i1 @extract_const_vec_unknown_idx_isnan(i32 %idx) nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, unknown idx, isnan -> cannot fold
-; CHECK-LABEL: extract_const_vec_unknown_idx_isnan:
+define i1 @extract_bitcast_maybe_nan(<4 x i32> %bits, ptr %p) nounwind {  ; elts 0,2 exp bit cleared, idx=1 unchanged, isnan -> cannot fold
+; CHECK-LABEL: extract_bitcast_maybe_nan:
 ; CHECK:       # %bb.0:
-; CHECK:    fclass.s
-; CHECK:    ret
-  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 %idx
+; CHECK-NEXT:    lui a1, 786432
+; CHECK-NEXT:    addi a1, a1, -1
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vmv.v.x v9, a1
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vand.vv v8, v8, v9
+; CHECK-NEXT:    vslidedown.vi v9, v8, 1
+; CHECK-NEXT:    vfmv.f.s fa5, v9
+; CHECK-NEXT:    fclass.s a1, fa5
+; CHECK-NEXT:    andi a1, a1, 768
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    vse32.v v8, (a0)
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    ret
+  %masked = and <4 x i32> %bits, <i32 u0xBFFFFFFF, i32 -1, i32 u0xBFFFFFFF, i32 -1>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 1
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
 
-define i1 @extract_oob_idx_const_vec_isnan() nounwind {  ; vec = <QNaN, 2.0, +Inf, -Inf>, idx=6 (OOB) -> poison, folds away
-; CHECK-LABEL: extract_oob_idx_const_vec_isnan:
+define i1 @extract_bitcast_unknown_idx_not_pos(<4 x i32> %bits, ptr %p, i32 %idx) nounwind {  ; mixed sign, unknown idx, ispos -> cannot fold
+; CHECK-LABEL: extract_bitcast_unknown_idx_not_pos:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vid.v v9
+; CHECK-NEXT:    lui a2, 524288
+; CHECK-NEXT:    slli a1, a1, 32
+; CHECK-NEXT:    vsll.vi v9, v9, 31
+; CHECK-NEXT:    vrsub.vx v9, v9, a2
+; CHECK-NEXT:    vor.vv v8, v8, v9
+; CHECK-NEXT:    srli a1, a1, 32
+; CHECK-NEXT:    vslidedown.vx v9, v8, a1
+; CHECK-NEXT:    vfmv.f.s fa5, v9
+; CHECK-NEXT:    fclass.s a1, fa5
+; CHECK-NEXT:    andi a1, a1, 240
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    vse32.v v8, (a0)
+; CHECK-NEXT:    mv a0, a1
 ; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float 0x7FF8000000000000, float 2.0, float 0x7FF0000000000000, float 0xFFF0000000000000>, i32 6
+  %masked = or <4 x i32> %bits, <i32 u0x80000000, i32 0, i32 u0x80000000, i32 0>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 %idx
+  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 960)  ; 0x3C0 = any positive
+  ret i1 %res
+}
+
+define i1 @extract_bitcast_oob_idx(<4 x i32> %bits, ptr %p) nounwind {  ; idx=6 (OOB) -> undef, isnan -> cannot fold
+; CHECK-LABEL: extract_bitcast_oob_idx:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vid.v v9
+; CHECK-NEXT:    lui a1, 524288
+; CHECK-NEXT:    vsll.vi v9, v9, 31
+; CHECK-NEXT:    vrsub.vx v9, v9, a1
+; CHECK-NEXT:    fclass.s a1, fa5
+; CHECK-NEXT:    andi a1, a1, 768
+; CHECK-NEXT:    vor.vv v8, v8, v9
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    vse32.v v8, (a0)
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    ret
+  %masked = or <4 x i32> %bits, <i32 u0x80000000, i32 0, i32 u0x80000000, i32 0>
+  %fvec = bitcast <4 x i32> %masked to <4 x float>
+  store <4 x float> %fvec, ptr %p
+  %elt = extractelement <4 x float> %fvec, i32 6
   %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 3)  ; 0x3 = nan
   ret i1 %res
 }
@@ -84,26 +184,6 @@ define i1 @extract_scalable_fabs_isneg(<vscale x 4 x float> %a0) nounwind {
   ret i1 %res
 }
 
-define i1 @extract_const_vec_unknown_idx_isneg(i32 %idx) nounwind {  ; vec = <-1, 2, -3, 4>, unknown idx, isneg -> cannot fold
-; CHECK-LABEL: extract_const_vec_unknown_idx_isneg:
-; CHECK:       # %bb.0:
-; CHECK:    fclass.s
-; CHECK:    ret
-  %elt = extractelement <4 x float> <float -1.0, float 2.0, float -3.0, float 4.0>, i32 %idx
-  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
-  ret i1 %res
-}
-
-define i1 @extract_const_vec_known_neg_idx_isneg() nounwind {  ; vec = <-1, 2, -3, 4>, idx=0, isneg -> true
-; CHECK-LABEL: extract_const_vec_known_neg_idx_isneg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 1
-; CHECK-NEXT:    ret
-  %elt = extractelement <4 x float> <float -1.0, float 2.0, float -3.0, float 4.0>, i32 0
-  %res = call i1 @llvm.is.fpclass.f32(float %elt, i32 60)  ; 0x3C = negative
-  ret i1 %res
-}
-
 define <vscale x 4 x i1> @splat_constant_is_pos_normal() {
 ; CHECK-LABEL: splat_constant_is_pos_normal:
 ; CHECK:       # %bb.0:



More information about the llvm-commits mailing list