[llvm] [LoongArch] Add custom lowering for CTTZ_ELTS and CTTZ_ELTS_ZERO_POISON (PR #226042)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 00:13:21 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-loongarch

Author: lrzlin

<details>
<summary>Changes</summary>

Use `[X]VMSKLTZ` and `CTZ` for custom lowering `ISD::CTTZ_ELTS` and `ISD::CTTZ_ELTS_ZERO_POISON`, when the number of lanes is larger than or equal to `GRLen`, switch back to the generic way; these two intrinsics could possibly be used in early-exit loop vectorization.

---
Full diff: https://github.com/llvm/llvm-project/pull/226042.diff


4 Files Affected:

- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+41) 
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.h (+1) 
- (added) llvm/test/CodeGen/LoongArch/lasx/cttz-elts.ll (+207) 
- (added) llvm/test/CodeGen/LoongArch/lsx/cttz-elts.ll (+175) 


``````````diff
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 07f6a438bbb1bc..249fe798a60558 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -328,6 +328,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::VSELECT, VT, Legal);
       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
       setOperationAction(ISD::EXTRACT_SUBVECTOR, VT, Legal);
+      setOperationAction({ISD::CTTZ_ELTS, ISD::CTTZ_ELTS_ZERO_POISON}, VT,
+                         Custom);
     }
     for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
@@ -430,6 +432,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::SETCC, VT, Custom);
       setOperationAction(ISD::VSELECT, VT, Legal);
       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
+      setOperationAction({ISD::CTTZ_ELTS, ISD::CTTZ_ELTS_ZERO_POISON}, VT,
+                         Custom);
     }
     for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
@@ -670,6 +674,9 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
   case ISD::ROTL:
   case ISD::ROTR:
     return lowerRotate(Op, DAG);
+  case ISD::CTTZ_ELTS:
+  case ISD::CTTZ_ELTS_ZERO_POISON:
+    return lowerCTTZ_ELTS(Op, DAG);
   case ISD::VECREDUCE_AND:
   case ISD::VECREDUCE_OR:
   case ISD::VECREDUCE_XOR:
@@ -10986,6 +10993,40 @@ bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
   return false;
 }
 
+SDValue LoongArchTargetLowering::lowerCTTZ_ELTS(SDValue Op,
+                                                SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+  MVT GRLenVT = Subtarget.getGRLenVT();
+  SDValue Src = Op.getOperand(0);
+  EVT SrcVT = Src.getValueType();
+  unsigned NumElts = SrcVT.getVectorNumElements();
+  unsigned SrcBits = SrcVT.getSizeInBits();
+
+  // Only masks occupying exactly one LSX or LASX register are handled; anything
+  // else is left to the generic expansion.
+  if (SrcBits != 128 && SrcBits != 256)
+    return SDValue();
+
+  // [X]VMSKLTZ collect each lane's sign bit into lowest bits of a VPR, copy
+  // them into GPR and count trailing zeros.
+  SDValue Bits = DAG.getNode(SrcBits == 256 ? LoongArchISD::XVMSKLTZ
+                                            : LoongArchISD::VMSKLTZ,
+                             DL, GRLenVT, Src);
+
+  // CTTZ_ELTS must produce the vector length when no lane is set.
+  if (Op.getOpcode() == ISD::CTTZ_ELTS) {
+    // When GRLen is 32, it's possible that NumElts is 32 too.
+    if (NumElts >= GRLenVT.getSizeInBits())
+      return SDValue();
+    Bits = DAG.getNode(ISD::OR, DL, GRLenVT, Bits,
+                       DAG.getConstant(1ULL << NumElts, DL, GRLenVT));
+  }
+
+  return DAG.getZExtOrTrunc(
+      DAG.getNode(ISD::CTTZ_ZERO_POISON, DL, GRLenVT, Bits), DL,
+      Op.getValueType());
+}
+
 EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
                                                 LLVMContext &Context,
                                                 EVT VT) const {
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 7c3ae7d6aac14a..8371efff305e43 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -255,6 +255,7 @@ class LoongArchTargetLowering : public TargetLowering {
   SDValue lowerFP16_TO_FP(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerFP_TO_BF16(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerBF16_TO_FP(SDValue Op, SelectionDAG &DAG) const;
+  SDValue lowerCTTZ_ELTS(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerVECREDUCE_ADD(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerVECREDUCE(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerConstantFP(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/test/CodeGen/LoongArch/lasx/cttz-elts.ll b/llvm/test/CodeGen/LoongArch/lasx/cttz-elts.ll
new file mode 100644
index 00000000000000..988786df71c089
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/cttz-elts.ll
@@ -0,0 +1,207 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx --verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,LA64
+
+declare i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v8i1(<8 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v16i1(<16 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v32i1(<32 x i1>, i1)
+
+define void @first_set_lane_v4i64(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v4i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a0, 0
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    xvseq.d $xr0, $xr0, $xr1
+; LA32-NEXT:    xvpickev.w $xr0, $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA32-NEXT:    vmskltz.w $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ori $a0, $a0, 16
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v4i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a0, 0
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvseq.d $xr0, $xr0, $xr1
+; LA64-NEXT:    xvpickev.w $xr0, $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA64-NEXT:    vmskltz.w $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ori $a0, $a0, 16
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <4 x i64>, ptr %src
+  %b = load <4 x i64>, ptr %dst
+  %cmp = icmp eq <4 x i64> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v4i64_poison(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v4i64_poison:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a0, 0
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    xvseq.d $xr0, $xr0, $xr1
+; LA32-NEXT:    xvpickev.w $xr0, $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA32-NEXT:    vmskltz.w $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v4i64_poison:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a0, 0
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvseq.d $xr0, $xr0, $xr1
+; LA64-NEXT:    xvpickev.w $xr0, $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA64-NEXT:    vmskltz.w $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <4 x i64>, ptr %src
+  %b = load <4 x i64>, ptr %dst
+  %cmp = icmp eq <4 x i64> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> %cmp, i1 true)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v8i32(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v8i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a0, 0
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    xvseq.w $xr0, $xr0, $xr1
+; LA32-NEXT:    xvpickev.h $xr0, $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA32-NEXT:    vmskltz.h $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ori $a0, $a0, 256
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v8i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a0, 0
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvseq.w $xr0, $xr0, $xr1
+; LA64-NEXT:    xvpickev.h $xr0, $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA64-NEXT:    vmskltz.h $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ori $a0, $a0, 256
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <8 x i32>, ptr %src
+  %b = load <8 x i32>, ptr %dst
+  %cmp = icmp eq <8 x i32> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v8i1(<8 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v16i16(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v16i16:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a0, 0
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    xvseq.h $xr0, $xr0, $xr1
+; LA32-NEXT:    xvpickev.b $xr0, $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA32-NEXT:    vmskltz.b $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    lu12i.w $a2, 16
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v16i16:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a0, 0
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvseq.h $xr0, $xr0, $xr1
+; LA64-NEXT:    xvpickev.b $xr0, $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr0, $xr0, 216
+; LA64-NEXT:    vmskltz.b $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    lu12i.w $a2, 16
+; LA64-NEXT:    or $a0, $a0, $a2
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <16 x i16>, ptr %src
+  %b = load <16 x i16>, ptr %dst
+  %cmp = icmp eq <16 x i16> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v16i1(<16 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v32i8(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v32i8:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a0, 0
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    pcalau12i $a0, %pc_hi20(.LCPI4_0)
+; LA32-NEXT:    xvld $xr2, $a0, %pc_lo12(.LCPI4_0)
+; LA32-NEXT:    xvseq.b $xr0, $xr0, $xr1
+; LA32-NEXT:    xvand.v $xr0, $xr0, $xr2
+; LA32-NEXT:    xvpermi.q $xr1, $xr0, 1
+; LA32-NEXT:    vmax.bu $vr0, $vr0, $vr1
+; LA32-NEXT:    vbsrl.v $vr1, $vr0, 8
+; LA32-NEXT:    vmax.bu $vr0, $vr1, $vr0
+; LA32-NEXT:    vbsrl.v $vr1, $vr0, 4
+; LA32-NEXT:    vmax.bu $vr0, $vr1, $vr0
+; LA32-NEXT:    vbsrl.v $vr1, $vr0, 2
+; LA32-NEXT:    vmax.bu $vr0, $vr1, $vr0
+; LA32-NEXT:    vbsrl.v $vr1, $vr0, 1
+; LA32-NEXT:    vmax.bu $vr0, $vr1, $vr0
+; LA32-NEXT:    vpickve2gr.bu $a0, $vr0, 0
+; LA32-NEXT:    ori $a2, $zero, 32
+; LA32-NEXT:    sub.w $a0, $a2, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v32i8:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a0, 0
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvseq.b $xr0, $xr0, $xr1
+; LA64-NEXT:    xvmskltz.b $xr0, $xr0
+; LA64-NEXT:    xvpickve2gr.wu $a0, $xr0, 0
+; LA64-NEXT:    xvpickve2gr.wu $a2, $xr0, 4
+; LA64-NEXT:    bstrins.d $a0, $a2, 31, 16
+; LA64-NEXT:    ori $a2, $zero, 0
+; LA64-NEXT:    lu32i.d $a2, 1
+; LA64-NEXT:    or $a0, $a0, $a2
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <32 x i8>, ptr %src
+  %b = load <32 x i8>, ptr %dst
+  %cmp = icmp eq <32 x i8> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v32i1(<32 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/cttz-elts.ll b/llvm/test/CodeGen/LoongArch/lsx/cttz-elts.ll
new file mode 100644
index 00000000000000..b7a5e151e57657
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/cttz-elts.ll
@@ -0,0 +1,175 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx --verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,LA64
+
+declare i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v8i1(<8 x i1>, i1)
+declare i64 @llvm.experimental.cttz.elts.i64.v16i1(<16 x i1>, i1)
+
+define void @first_set_lane_v2i64(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v2i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vld $vr1, $a1, 0
+; LA32-NEXT:    vseq.d $vr0, $vr0, $vr1
+; LA32-NEXT:    vmskltz.d $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ori $a0, $a0, 4
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v2i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vld $vr1, $a1, 0
+; LA64-NEXT:    vseq.d $vr0, $vr0, $vr1
+; LA64-NEXT:    vmskltz.d $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ori $a0, $a0, 4
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <2 x i64>, ptr %src
+  %b = load <2 x i64>, ptr %dst
+  %cmp = icmp eq <2 x i64> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v2i64_poison(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v2i64_poison:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vld $vr1, $a1, 0
+; LA32-NEXT:    vseq.d $vr0, $vr0, $vr1
+; LA32-NEXT:    vmskltz.d $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v2i64_poison:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vld $vr1, $a1, 0
+; LA64-NEXT:    vseq.d $vr0, $vr0, $vr1
+; LA64-NEXT:    vmskltz.d $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <2 x i64>, ptr %src
+  %b = load <2 x i64>, ptr %dst
+  %cmp = icmp eq <2 x i64> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> %cmp, i1 true)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v4i32(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vld $vr1, $a1, 0
+; LA32-NEXT:    vseq.w $vr0, $vr0, $vr1
+; LA32-NEXT:    vmskltz.w $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ori $a0, $a0, 16
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vld $vr1, $a1, 0
+; LA64-NEXT:    vseq.w $vr0, $vr0, $vr1
+; LA64-NEXT:    vmskltz.w $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ori $a0, $a0, 16
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <4 x i32>, ptr %src
+  %b = load <4 x i32>, ptr %dst
+  %cmp = icmp eq <4 x i32> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v8i16(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v8i16:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vld $vr1, $a1, 0
+; LA32-NEXT:    vseq.h $vr0, $vr0, $vr1
+; LA32-NEXT:    vmskltz.h $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    ori $a0, $a0, 256
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v8i16:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vld $vr1, $a1, 0
+; LA64-NEXT:    vseq.h $vr0, $vr0, $vr1
+; LA64-NEXT:    vmskltz.h $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    ori $a0, $a0, 256
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <8 x i16>, ptr %src
+  %b = load <8 x i16>, ptr %dst
+  %cmp = icmp eq <8 x i16> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v8i1(<8 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+
+define void @first_set_lane_v16i8(ptr %src, ptr %dst) {
+; LA32-LABEL: first_set_lane_v16i8:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vld $vr1, $a1, 0
+; LA32-NEXT:    vseq.b $vr0, $vr0, $vr1
+; LA32-NEXT:    vmskltz.b $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA32-NEXT:    lu12i.w $a2, 16
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    ctz.w $a0, $a0
+; LA32-NEXT:    st.w $zero, $a1, 4
+; LA32-NEXT:    st.w $a0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: first_set_lane_v16i8:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vld $vr1, $a1, 0
+; LA64-NEXT:    vseq.b $vr0, $vr0, $vr1
+; LA64-NEXT:    vmskltz.b $vr0, $vr0
+; LA64-NEXT:    vpickve2gr.hu $a0, $vr0, 0
+; LA64-NEXT:    lu12i.w $a2, 16
+; LA64-NEXT:    or $a0, $a0, $a2
+; LA64-NEXT:    ctz.d $a0, $a0
+; LA64-NEXT:    st.d $a0, $a1, 0
+; LA64-NEXT:    ret
+  %a = load <16 x i8>, ptr %src
+  %b = load <16 x i8>, ptr %dst
+  %cmp = icmp eq <16 x i8> %a, %b
+  %r = call i64 @llvm.experimental.cttz.elts.i64.v16i1(<16 x i1> %cmp, i1 false)
+  store i64 %r, ptr %dst
+  ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}

``````````

</details>


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


More information about the llvm-commits mailing list