[llvm] [LoongArch] Lower ANY_EXTEND to ZERO_EXTEND under LASX to avoid scalarization (PR #201099)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 6 01:24:40 PDT 2026


https://github.com/lrzlin updated https://github.com/llvm/llvm-project/pull/201099

>From b1f22d2e1a8408dc923dadc3e5aa682e82bf1609 Mon Sep 17 00:00:00 2001
From: Lin Runze <linrunze at loongson.cn>
Date: Mon, 6 Jul 2026 14:48:08 +0800
Subject: [PATCH 1/2] [LoongArch][NFC] Pre-commit tests for lower ANY_EXTEND to
 ZERO_EXTEND under LASX

---
 .../LoongArch/lasx/vec-shuffle-any-ext.ll     | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll

diff --git a/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll b/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll
new file mode 100644
index 0000000000000..e6680ee951b26
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll
@@ -0,0 +1,112 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA64
+
+define void @shuffle_any_ext_8i16_to_8i32(ptr %ptr, ptr %dst) nounwind {
+; CHECK-LABEL: shuffle_any_ext_8i16_to_8i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vld $vr0, $a0, 0
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 4
+; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 0
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 5
+; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 1
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 6
+; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 2
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 7
+; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 3
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 0
+; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 0
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 1
+; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 1
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 2
+; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 2
+; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 3
+; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 3
+; CHECK-NEXT:    xvpermi.q $xr2, $xr1, 2
+; CHECK-NEXT:    xvst $xr2, $a1, 0
+; CHECK-NEXT:    ret
+  %x = load <8 x i16>, ptr %ptr
+  %y = shufflevector <8 x i16> %x, <8 x i16> poison, <16 x i32> <i32 0, i32 15, i32 1, i32 15, i32 2, i32 13, i32 3, i32 12, i32 4, i32 11, i32 5, i32 10, i32 6, i32 9, i32 7, i32 8>
+  %r = bitcast <16 x i16> %y to <8 x i32>
+  store <8 x i32> %r, ptr %dst
+  ret void
+}
+
+define void @shuffle_any_ext_16i8_to_16i16(ptr %ptr, ptr %dst) nounwind {
+; CHECK-LABEL: shuffle_any_ext_16i8_to_16i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vld $vr0, $a0, 0
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 8
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 0
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 9
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 1
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 10
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 2
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 11
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 3
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 12
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 4
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 13
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 5
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 14
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 6
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 15
+; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 7
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 0
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 0
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 1
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 1
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 2
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 2
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 3
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 3
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 4
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 4
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 5
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 5
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 6
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 6
+; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 7
+; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 7
+; CHECK-NEXT:    xvpermi.q $xr2, $xr1, 2
+; CHECK-NEXT:    xvst $xr2, $a1, 0
+; CHECK-NEXT:    ret
+  %x = load <16 x i8>, ptr %ptr
+  %y = shufflevector <16 x i8> %x, <16 x i8> poison, <32 x i32> <i32 0, i32 31, i32 1, i32 31, i32 2, i32 29, i32 3, i32 28, i32 4, i32 27, i32 5, i32 26, i32 6, i32 25, i32 7, i32 24, i32 8, i32 23, i32 9, i32 22, i32 10, i32 21, i32 11, i32 20, i32 12, i32 19, i32 13, i32 18, i32 14, i32 17, i32 15, i32 16>
+  %r = bitcast <32 x i8> %y to <16 x i16>
+  store <16 x i16> %r, ptr %dst
+  ret void
+}
+
+define void @shuffle_any_ext_4i32_to_4i64(ptr %ptr, ptr %dst) nounwind {
+; LA32-LABEL: shuffle_any_ext_4i32_to_4i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a0, 0
+; LA32-NEXT:    vextrins.w $vr1, $vr0, 2
+; LA32-NEXT:    vextrins.w $vr1, $vr0, 35
+; LA32-NEXT:    # kill: def $vr0 killed $vr0 def $xr0
+; LA32-NEXT:    vextrins.w $vr0, $vr0, 33
+; LA32-NEXT:    xvpermi.q $xr0, $xr1, 2
+; LA32-NEXT:    xvst $xr0, $a1, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: shuffle_any_ext_4i32_to_4i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a0, 0
+; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 2
+; LA64-NEXT:    vinsgr2vr.d $vr1, $a0, 0
+; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 3
+; LA64-NEXT:    vinsgr2vr.d $vr1, $a0, 1
+; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 0
+; LA64-NEXT:    vinsgr2vr.d $vr2, $a0, 0
+; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 1
+; LA64-NEXT:    vinsgr2vr.d $vr2, $a0, 1
+; LA64-NEXT:    xvpermi.q $xr2, $xr1, 2
+; LA64-NEXT:    xvst $xr2, $a1, 0
+; LA64-NEXT:    ret
+  %x = load <4 x i32>, ptr %ptr
+  %y = shufflevector <4 x i32> %x, <4 x i32> poison, <8 x i32> <i32 0, i32 7, i32 1, i32 6, i32 2, i32 5, i32 3, i32 4>
+  %r = bitcast <8 x i32> %y to <4 x i64>
+  store <4 x i64> %r, ptr %dst
+  ret void
+}

>From 9ddb7a8a94719efbe95b22be925277c115c76474 Mon Sep 17 00:00:00 2001
From: Lin Runze <linrunze at loongson.cn>
Date: Tue, 26 May 2026 17:59:30 +0800
Subject: [PATCH 2/2] [LoongArch] Lower ANY_EXTEND to ZERO_EXTEND under LASX to
 avoid scalarization

---
 .../LoongArch/LoongArchISelLowering.cpp       | 15 ++++
 .../Target/LoongArch/LoongArchISelLowering.h  |  1 +
 .../LoongArch/lasx/vec-shuffle-any-ext.ll     | 90 +++----------------
 3 files changed, 29 insertions(+), 77 deletions(-)

diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 9dc6d23711ec1..f781246db2b5b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -489,6 +489,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
       setOperationAction(ISD::SIGN_EXTEND, VT, Legal);
       setOperationAction(ISD::ZERO_EXTEND, VT, Legal);
+      setOperationAction(ISD::ANY_EXTEND, VT, Custom);
     }
     for (MVT VT :
          {MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
@@ -674,6 +675,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
     return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
   case ISD::DYNAMIC_STACKALLOC:
     return lowerDYNAMIC_STACKALLOC(Op, DAG);
+  case ISD::ANY_EXTEND:
+    return lowerANY_EXTEND(Op, DAG);
   }
   return SDValue();
 }
@@ -1023,6 +1026,18 @@ SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
   return SDValue();
 }
 
+// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
+SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
+                                                 SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+  if (!Subtarget.hasExtLASX())
+    return SDValue();
+
+  // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
+  // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
+  return DAG.getNode(ISD::ZERO_EXTEND, DL, Op.getValueType(), Op.getOperand(0));
+}
+
 // Lower vecreduce_add using vhaddw instructions.
 // For Example:
 //  call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 8d9ec6020478b..7c717f9735219 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -261,6 +261,7 @@ class LoongArchTargetLowering : public TargetLowering {
   SDValue lowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerSIGN_EXTEND_VECTOR_INREG(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
+  SDValue lowerANY_EXTEND(SDValue Op, SelectionDAG &DAG) const;
 
   bool isFPImmLegal(const APFloat &Imm, EVT VT,
                     bool ForCodeSize) const override;
diff --git a/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll b/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll
index e6680ee951b26..8c4837f10ca05 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/vec-shuffle-any-ext.ll
@@ -6,24 +6,8 @@ define void @shuffle_any_ext_8i16_to_8i32(ptr %ptr, ptr %dst) nounwind {
 ; CHECK-LABEL: shuffle_any_ext_8i16_to_8i32:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vld $vr0, $a0, 0
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 4
-; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 0
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 5
-; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 1
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 6
-; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 2
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 7
-; CHECK-NEXT:    vinsgr2vr.w $vr1, $a0, 3
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 0
-; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 0
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 1
-; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 1
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 2
-; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 2
-; CHECK-NEXT:    vpickve2gr.h $a0, $vr0, 3
-; CHECK-NEXT:    vinsgr2vr.w $vr2, $a0, 3
-; CHECK-NEXT:    xvpermi.q $xr2, $xr1, 2
-; CHECK-NEXT:    xvst $xr2, $a1, 0
+; CHECK-NEXT:    vext2xv.wu.hu $xr0, $xr0
+; CHECK-NEXT:    xvst $xr0, $a1, 0
 ; CHECK-NEXT:    ret
   %x = load <8 x i16>, ptr %ptr
   %y = shufflevector <8 x i16> %x, <8 x i16> poison, <16 x i32> <i32 0, i32 15, i32 1, i32 15, i32 2, i32 13, i32 3, i32 12, i32 4, i32 11, i32 5, i32 10, i32 6, i32 9, i32 7, i32 8>
@@ -36,40 +20,8 @@ define void @shuffle_any_ext_16i8_to_16i16(ptr %ptr, ptr %dst) nounwind {
 ; CHECK-LABEL: shuffle_any_ext_16i8_to_16i16:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vld $vr0, $a0, 0
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 8
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 0
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 9
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 1
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 10
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 2
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 11
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 3
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 12
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 4
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 13
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 5
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 14
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 6
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 15
-; CHECK-NEXT:    vinsgr2vr.h $vr1, $a0, 7
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 0
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 0
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 1
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 1
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 2
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 2
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 3
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 3
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 4
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 4
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 5
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 5
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 6
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 6
-; CHECK-NEXT:    vpickve2gr.b $a0, $vr0, 7
-; CHECK-NEXT:    vinsgr2vr.h $vr2, $a0, 7
-; CHECK-NEXT:    xvpermi.q $xr2, $xr1, 2
-; CHECK-NEXT:    xvst $xr2, $a1, 0
+; CHECK-NEXT:    vext2xv.hu.bu $xr0, $xr0
+; CHECK-NEXT:    xvst $xr0, $a1, 0
 ; CHECK-NEXT:    ret
   %x = load <16 x i8>, ptr %ptr
   %y = shufflevector <16 x i8> %x, <16 x i8> poison, <32 x i32> <i32 0, i32 31, i32 1, i32 31, i32 2, i32 29, i32 3, i32 28, i32 4, i32 27, i32 5, i32 26, i32 6, i32 25, i32 7, i32 24, i32 8, i32 23, i32 9, i32 22, i32 10, i32 21, i32 11, i32 20, i32 12, i32 19, i32 13, i32 18, i32 14, i32 17, i32 15, i32 16>
@@ -79,34 +31,18 @@ define void @shuffle_any_ext_16i8_to_16i16(ptr %ptr, ptr %dst) nounwind {
 }
 
 define void @shuffle_any_ext_4i32_to_4i64(ptr %ptr, ptr %dst) nounwind {
-; LA32-LABEL: shuffle_any_ext_4i32_to_4i64:
-; LA32:       # %bb.0:
-; LA32-NEXT:    vld $vr0, $a0, 0
-; LA32-NEXT:    vextrins.w $vr1, $vr0, 2
-; LA32-NEXT:    vextrins.w $vr1, $vr0, 35
-; LA32-NEXT:    # kill: def $vr0 killed $vr0 def $xr0
-; LA32-NEXT:    vextrins.w $vr0, $vr0, 33
-; LA32-NEXT:    xvpermi.q $xr0, $xr1, 2
-; LA32-NEXT:    xvst $xr0, $a1, 0
-; LA32-NEXT:    ret
-;
-; LA64-LABEL: shuffle_any_ext_4i32_to_4i64:
-; LA64:       # %bb.0:
-; LA64-NEXT:    vld $vr0, $a0, 0
-; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 2
-; LA64-NEXT:    vinsgr2vr.d $vr1, $a0, 0
-; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 3
-; LA64-NEXT:    vinsgr2vr.d $vr1, $a0, 1
-; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 0
-; LA64-NEXT:    vinsgr2vr.d $vr2, $a0, 0
-; LA64-NEXT:    vpickve2gr.w $a0, $vr0, 1
-; LA64-NEXT:    vinsgr2vr.d $vr2, $a0, 1
-; LA64-NEXT:    xvpermi.q $xr2, $xr1, 2
-; LA64-NEXT:    xvst $xr2, $a1, 0
-; LA64-NEXT:    ret
+; CHECK-LABEL: shuffle_any_ext_4i32_to_4i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vld $vr0, $a0, 0
+; CHECK-NEXT:    vext2xv.du.wu $xr0, $xr0
+; CHECK-NEXT:    xvst $xr0, $a1, 0
+; CHECK-NEXT:    ret
   %x = load <4 x i32>, ptr %ptr
   %y = shufflevector <4 x i32> %x, <4 x i32> poison, <8 x i32> <i32 0, i32 7, i32 1, i32 6, i32 2, i32 5, i32 3, i32 4>
   %r = bitcast <8 x i32> %y to <4 x i64>
   store <4 x i64> %r, ptr %dst
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; LA32: {{.*}}
+; LA64: {{.*}}



More information about the llvm-commits mailing list