[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