https://github.com/E00N777 updated 
https://github.com/llvm/llvm-project/pull/209389

>From 034bcfaf43d559d2dfd8405a56c4e1c7e3424325 Mon Sep 17 00:00:00 2001
From: E00N777 <[email protected]>
Date: Tue, 14 Jul 2026 11:18:07 +0800
Subject: [PATCH 1/2] [CIR][AArch64] Lower Vector saturating shift and narrow
 intrinsics

---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  |  83 ++++-
 clang/test/CodeGen/AArch64/neon-intrinsics.c  | 331 -----------------
 clang/test/CodeGen/AArch64/neon/intrinsics.c  | 344 ++++++++++++++++++
 3 files changed, 415 insertions(+), 343 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 9a50acece4d2c..0076031dae84e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -330,6 +330,30 @@ static cir::VectorType 
deriveNeonBinaryArgType(CIRGenBuilderTy &builder,
   return vTy;
 }
 
+/// Vectorize value, usually for argument of a neon SISD intrinsic call.
+static void vecExtendIntValue(CIRGenFunction &cgf, cir::VectorType argVTy,
+                              mlir::Value &arg, mlir::Location loc) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  cir::IntType eltTy = mlir::dyn_cast<cir::IntType>(argVTy.getElementType());
+  assert(mlir::isa<cir::IntType>(arg.getType()) && eltTy);
+  // Cast the scalar data operand to the vector element type before inserting
+  // it into lane 0.
+  arg = builder.createIntCast(arg, eltTy);
+  mlir::Value zero = builder.getConstInt(loc, cgf.sizeTy, 0);
+  mlir::Value poison = builder.getConstant(loc, cir::PoisonAttr::get(argVTy));
+  arg = cir::VecInsertOp::create(builder, loc, poison, arg, zero);
+}
+
+/// Reduce vector type value to scalar, usually for result of a
+/// neon SISD intrinsic call
+static mlir::Value vecReduceIntValue(CIRGenFunction &cgf, mlir::Value val,
+                                     mlir::Location loc) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  assert(mlir::isa<cir::VectorType>(val.getType()));
+  return cir::VecExtractOp::create(builder, loc, val,
+                                   builder.getConstInt(loc, cgf.sizeTy, 0));
+}
+
 static mlir::Value emitCommonNeonSISDBuiltinExpr(
     CIRGenFunction &cgf, const ARMNeonVectorIntrinsicInfo &info,
     llvm::SmallVectorImpl<mlir::Value> &ops, const CallExpr *expr) {
@@ -458,6 +482,9 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
   case NEON::BI__builtin_neon_vqrshrund_n_s64:
   case NEON::BI__builtin_neon_vqrshrnd_n_s64:
   case NEON::BI__builtin_neon_vqrshrnd_n_u64:
+  case NEON::BI__builtin_neon_vqshrund_n_s64:
+  case NEON::BI__builtin_neon_vqshrnd_n_s64:
+  case NEON::BI__builtin_neon_vqshrnd_n_u64:
   case NEON::BI__builtin_neon_vmaxnmv_f32:
   case NEON::BI__builtin_neon_vmaxnmvq_f32:
   case NEON::BI__builtin_neon_vmaxnmvq_f64:
@@ -470,6 +497,12 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
   case NEON::BI__builtin_neon_vpmaxnms_f32:
   case NEON::BI__builtin_neon_vpmaxnmqd_f64:
   case NEON::BI__builtin_neon_vmulxh_f16:
+  case NEON::BI__builtin_neon_vqshrunh_n_s16:
+  case NEON::BI__builtin_neon_vqshruns_n_s32:
+  case NEON::BI__builtin_neon_vqshrnh_n_s16:
+  case NEON::BI__builtin_neon_vqshrns_n_s32:
+  case NEON::BI__builtin_neon_vqshrnh_n_u16:
+  case NEON::BI__builtin_neon_vqshrns_n_u32:
     break;
   }
 
@@ -483,8 +516,30 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
   auto [funcResTy, argTypes] = deriveNeonSISDIntrinsicOperandTypes(
       cgf, info.TypeModifier, arg0Ty, resultTy, ops);
 
-  return emitNeonCall(cgf.cgm, builder, std::move(argTypes), ops, llvmIntrName,
-                      funcResTy, loc);
+  auto resVecTy = mlir::dyn_cast<cir::VectorType>(funcResTy);
+  auto argIntTy = mlir::dyn_cast<cir::IntType>(arg0Ty);
+  auto resultIntTy = mlir::dyn_cast<cir::IntType>(resultTy);
+
+  if (resVecTy && argIntTy && resultIntTy &&
+      argIntTy.getWidth() == resultIntTy.getWidth() * 2) {
+    cir::VectorType argVecTy = cir::VectorType::get(arg0Ty, 
resVecTy.getSize());
+    assert(!argTypes.empty());
+    argTypes[0] = argVecTy;
+    vecExtendIntValue(cgf, argVecTy, ops[0], loc);
+  }
+
+  mlir::Value result = emitNeonCall(cgf.cgm, builder, std::move(argTypes), ops,
+                                    llvmIntrName, funcResTy, loc);
+
+  if (cgf.cgm.getDataLayout().getTypeSizeInBits(resultTy) <
+      cgf.cgm.getDataLayout().getTypeSizeInBits(funcResTy)) {
+    return vecReduceIntValue(cgf, result, loc);
+  }
+
+  if (result.getType() != resultTy)
+    return builder.createBitcast(loc, result, resultTy);
+
+  return result;
 }
 
 
//===----------------------------------------------------------------------===//
@@ -2951,22 +3006,26 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned 
builtinID, const CallExpr *expr,
     auto halfTy = builder.getFp16Ty();
     return builder.emitIntrinsicCallOp(loc, "aarch64.neon.frecps", halfTy, 
ops);
   }
-  case NEON::BI__builtin_neon_vqshrun_n_v:
-    cgm.errorNYI(expr->getSourceRange(),
-                 std::string("unimplemented AArch64 builtin call: ") +
-                     getContext().BuiltinInfo.getName(builtinID));
-    return mlir::Value{};
+  case NEON::BI__builtin_neon_vqshrun_n_v: {
+    cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
+        ty, /*isExtended=*/true, /*isSigned=*/true);
+    return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
+                        "aarch64.neon.sqshrun", ty, loc);
+  }
   case NEON::BI__builtin_neon_vqrshrun_n_v: {
     cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
         ty, /*isExtended=*/true, /*isSigned=*/true);
     return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
                         "aarch64.neon.sqrshrun", ty, loc);
   }
-  case NEON::BI__builtin_neon_vqshrn_n_v:
-    cgm.errorNYI(expr->getSourceRange(),
-                 std::string("unimplemented AArch64 builtin call: ") +
-                     getContext().BuiltinInfo.getName(builtinID));
-    return mlir::Value{};
+  case NEON::BI__builtin_neon_vqshrn_n_v: {
+    cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
+        ty, /*isExtended=*/true, /*isSigned=*/!usgn);
+    llvm::StringRef intrName =
+        usgn ? "aarch64.neon.uqshrn" : "aarch64.neon.sqshrn";
+    return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty,
+                        loc);
+  }
   case NEON::BI__builtin_neon_vrshrn_n_v:
     cgm.errorNYI(expr->getSourceRange(),
                  std::string("unimplemented AArch64 builtin call: ") +
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c 
b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index 883897a18cbf6..8d78c01892351 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -4186,81 +4186,6 @@ uint32x4_t test_vshrn_high_n_u64(uint32x2_t a, 
uint64x2_t b) {
   return vshrn_high_n_u64(a, b, 19);
 }
 
-// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrun_n_s16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRUN_N1:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3)
-// CHECK-NEXT:    ret <8 x i8> [[VQSHRUN_N1]]
-//
-uint8x8_t test_vqshrun_n_s16(int16x8_t a) {
-  return vqshrun_n_s16(a, 3);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrun_n_s32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRUN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9)
-// CHECK-NEXT:    ret <4 x i16> [[VQSHRUN_N1]]
-//
-uint16x4_t test_vqshrun_n_s32(int32x4_t a) {
-  return vqshrun_n_s32(a, 9);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrun_n_s64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRUN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19)
-// CHECK-NEXT:    ret <2 x i32> [[VQSHRUN_N1]]
-//
-uint32x2_t test_vqshrun_n_s64(int64x2_t a) {
-  return vqshrun_n_s64(a, 19);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrun_high_n_s16(
-// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRUN_N3:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, 
i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK-NEXT:    ret <16 x i8> [[SHUFFLE_I]]
-//
-uint8x16_t test_vqshrun_high_n_s16(uint8x8_t a, int16x8_t b) {
-  return vqshrun_high_n_s16(a, b, 3);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrun_high_n_s32(
-// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRUN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
-// CHECK-NEXT:    ret <8 x i16> [[SHUFFLE_I]]
-//
-uint16x8_t test_vqshrun_high_n_s32(uint16x4_t a, int32x4_t b) {
-  return vqshrun_high_n_s32(a, b, 9);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrun_high_n_s64(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRUN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I]]
-//
-uint32x4_t test_vqshrun_high_n_s64(uint32x2_t a, int64x2_t b) {
-  return vqshrun_high_n_s64(a, b, 19);
-}
-
 // CHECK-LABEL: define dso_local <8 x i8> @test_vrshrn_n_s16(
 // CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -4411,157 +4336,6 @@ uint32x4_t test_vrshrn_high_n_u64(uint32x2_t a, 
uint64x2_t b) {
   return vrshrn_high_n_u64(a, b, 19);
 }
 
-// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrn_n_s16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3)
-// CHECK-NEXT:    ret <8 x i8> [[VQSHRN_N1]]
-//
-int8x8_t test_vqshrn_n_s16(int16x8_t a) {
-  return vqshrn_n_s16(a, 3);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrn_n_s32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
-// CHECK-NEXT:    ret <4 x i16> [[VQSHRN_N1]]
-//
-int16x4_t test_vqshrn_n_s32(int32x4_t a) {
-  return vqshrn_n_s32(a, 9);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrn_n_s64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
-// CHECK-NEXT:    ret <2 x i32> [[VQSHRN_N1]]
-//
-int32x2_t test_vqshrn_n_s64(int64x2_t a) {
-  return vqshrn_n_s64(a, 19);
-}
-
-// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrn_n_u16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3)
-// CHECK-NEXT:    ret <8 x i8> [[VQSHRN_N1]]
-//
-uint8x8_t test_vqshrn_n_u16(uint16x8_t a) {
-  return vqshrn_n_u16(a, 3);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrn_n_u32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
-// CHECK-NEXT:    ret <4 x i16> [[VQSHRN_N1]]
-//
-uint16x4_t test_vqshrn_n_u32(uint32x4_t a) {
-  return vqshrn_n_u32(a, 9);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrn_n_u64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
-// CHECK-NEXT:    ret <2 x i32> [[VQSHRN_N1]]
-//
-uint32x2_t test_vqshrn_n_u64(uint64x2_t a) {
-  return vqshrn_n_u64(a, 19);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrn_high_n_s16(
-// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK-NEXT:    ret <16 x i8> [[SHUFFLE_I]]
-//
-int8x16_t test_vqshrn_high_n_s16(int8x8_t a, int16x8_t b) {
-  return vqshrn_high_n_s16(a, b, 3);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrn_high_n_s32(
-// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
-// CHECK-NEXT:    ret <8 x i16> [[SHUFFLE_I]]
-//
-int16x8_t test_vqshrn_high_n_s32(int16x4_t a, int32x4_t b) {
-  return vqshrn_high_n_s32(a, b, 9);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrn_high_n_s64(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I]]
-//
-int32x4_t test_vqshrn_high_n_s64(int32x2_t a, int64x2_t b) {
-  return vqshrn_high_n_s64(a, b, 19);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrn_high_n_u16(
-// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK-NEXT:    ret <16 x i8> [[SHUFFLE_I]]
-//
-uint8x16_t test_vqshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
-  return vqshrn_high_n_u16(a, b, 3);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrn_high_n_u32(
-// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
-// CHECK-NEXT:    ret <8 x i16> [[SHUFFLE_I]]
-//
-uint16x8_t test_vqshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
-  return vqshrn_high_n_u32(a, b, 9);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrn_high_n_u64(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VQSHRN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
-// CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I]]
-//
-uint32x4_t test_vqshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
-  return vqshrn_high_n_u64(a, b, 19);
-}
-
-
 // CHECK-LABEL: define dso_local <8 x i16> @test_vmovl_high_s8(
 // CHECK-SAME: <16 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -10010,7 +9784,6 @@ float64x1x3_t test_vld1_f64_x3(float64_t const *a) {
   return vld1_f64_x3(a);
 }
 
-
 // CHECK-LABEL: define dso_local %struct.mfloat8x8x3_t @test_vld1_mf8_x3(
 // CHECK-SAME: ptr noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -11603,74 +11376,6 @@ uint64x1_t test_vqshlu_n_s64(int64x1_t a) {
   return vqshlu_n_s64(a, 1);
 }
 
-// CHECK-LABEL: define dso_local i8 @test_vqshrnh_n_s16(
-// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRNH_N_S16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[TMP0]], i32 8)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_S16]], 
i64 0
-// CHECK-NEXT:    ret i8 [[TMP1]]
-//
-int8_t test_vqshrnh_n_s16(int16_t a) {
-  return (int8_t)vqshrnh_n_s16(a, 8);
-}
-
-// CHECK-LABEL: define dso_local i16 @test_vqshrns_n_s32(
-// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRNS_N_S32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[TMP0]], i32 16)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_S32]], 
i64 0
-// CHECK-NEXT:    ret i16 [[TMP1]]
-//
-int16_t test_vqshrns_n_s32(int32_t a) {
-  return (int16_t)vqshrns_n_s32(a, 16);
-}
-
-// CHECK-LABEL: define dso_local i32 @test_vqshrnd_n_s64(
-// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VQSHRND_N_S64:%.*]] = call i32 
@llvm.aarch64.neon.sqshrn.i32(i64 [[A]], i32 32)
-// CHECK-NEXT:    ret i32 [[VQSHRND_N_S64]]
-//
-int32_t test_vqshrnd_n_s64(int64_t a) {
-  return (int32_t)vqshrnd_n_s64(a, 32);
-}
-
-// CHECK-LABEL: define dso_local i8 @test_vqshrnh_n_u16(
-// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRNH_N_U16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[TMP0]], i32 8)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_U16]], 
i64 0
-// CHECK-NEXT:    ret i8 [[TMP1]]
-//
-uint8_t test_vqshrnh_n_u16(uint16_t a) {
-  return (uint8_t)vqshrnh_n_u16(a, 8);
-}
-
-// CHECK-LABEL: define dso_local i16 @test_vqshrns_n_u32(
-// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRNS_N_U32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[TMP0]], i32 16)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_U32]], 
i64 0
-// CHECK-NEXT:    ret i16 [[TMP1]]
-//
-uint16_t test_vqshrns_n_u32(uint32_t a) {
-  return (uint16_t)vqshrns_n_u32(a, 16);
-}
-
-// CHECK-LABEL: define dso_local i32 @test_vqshrnd_n_u64(
-// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VQSHRND_N_U64:%.*]] = call i32 
@llvm.aarch64.neon.uqshrn.i32(i64 [[A]], i32 32)
-// CHECK-NEXT:    ret i32 [[VQSHRND_N_U64]]
-//
-uint32_t test_vqshrnd_n_u64(uint64_t a) {
-  return (uint32_t)vqshrnd_n_u64(a, 32);
-}
-
 // CHECK-LABEL: define dso_local i8 @test_vqrshrnh_n_s16(
 // CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -11719,40 +11424,6 @@ uint16_t test_vqrshrns_n_u32(uint32_t a) {
   return (uint16_t)vqrshrns_n_u32(a, 16);
 }
 
-// CHECK-LABEL: define dso_local i8 @test_vqshrunh_n_s16(
-// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRUNH_N_S16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[TMP0]], i32 8)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRUNH_N_S16]], 
i64 0
-// CHECK-NEXT:    ret i8 [[TMP1]]
-//
-int8_t test_vqshrunh_n_s16(int16_t a) {
-  return (int8_t)vqshrunh_n_s16(a, 8);
-}
-
-// CHECK-LABEL: define dso_local i16 @test_vqshruns_n_s32(
-// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], 
i64 0
-// CHECK-NEXT:    [[VQSHRUNS_N_S32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[TMP0]], i32 16)
-// CHECK-NEXT:    [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRUNS_N_S32]], 
i64 0
-// CHECK-NEXT:    ret i16 [[TMP1]]
-//
-int16_t test_vqshruns_n_s32(int32_t a) {
-  return (int16_t)vqshruns_n_s32(a, 16);
-}
-
-// CHECK-LABEL: define dso_local i32 @test_vqshrund_n_s64(
-// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VQSHRUND_N_S64:%.*]] = call i32 
@llvm.aarch64.neon.sqshrun.i32(i64 [[A]], i32 32)
-// CHECK-NEXT:    ret i32 [[VQSHRUND_N_S64]]
-//
-int32_t test_vqshrund_n_s64(int64_t a) {
-  return (int32_t)vqshrund_n_s64(a, 32);
-}
-
 // CHECK-LABEL: define dso_local i8 @test_vqrshrunh_n_s16(
 // CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -16060,8 +15731,6 @@ float64x1_t test_vrecpe_f64(float64x1_t a) {
   return vrecpe_f64(a);
 }
 
-
-
 // CHECK-LABEL: define dso_local <1 x double> @test_vrecps_f64(
 // CHECK-SAME: <1 x double> noundef [[A:%.*]], <1 x double> noundef [[B:%.*]]) 
#[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c 
b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index 0e15488aede6b..0bef9c0e11cd9 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -7585,3 +7585,347 @@ float64x2_t test_vrndxq_f64(float64x2_t a) {
 // LLVM: ret <2 x double> [[VRNDX1_I]]
   return vrndxq_f64(a);
 }
+
+//===------------------------------------------------------===//
+// 2.1.3.2.6. Vector saturating shift right and narrow
+// 
https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#vector-saturating-shift-right-and-narrow
+//===------------------------------------------------------===//
+
+// ALL-LABEL: @test_vqshrun_n_s16(
+uint8x8_t test_vqshrun_n_s16(int16x8_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRUN_N1:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3)
+  // LLVM: ret <8 x i8> [[VQSHRUN_N1]]
+  return vqshrun_n_s16(a, 3);
+}
+
+// ALL-LABEL: @test_vqshrun_n_s32(
+uint16x4_t test_vqshrun_n_s32(int32x4_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRUN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9)
+  // LLVM: ret <4 x i16> [[VQSHRUN_N1]]
+  return vqshrun_n_s32(a, 9);
+}
+
+// ALL-LABEL: @test_vqshrun_n_s64(
+uint32x2_t test_vqshrun_n_s64(int64x2_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRUN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19)
+  // LLVM: ret <2 x i32> [[VQSHRUN_N1]]
+  return vqshrun_n_s64(a, 19);
+}
+
+// ALL-LABEL: @test_vqshrunh_n_s16(
+int8_t test_vqshrunh_n_s16(int16_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i16 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0
+  // LLVM: [[VQSHRUNH_N_S16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[TMP0]], i32 8)
+  // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRUNH_N_S16]], i64 0
+  // LLVM: ret i8 [[TMP1]]
+  return (int8_t)vqshrunh_n_s16(a, 8);
+}
+
+// ALL-LABEL: @test_vqshruns_n_s32(
+int16_t test_vqshruns_n_s32(int32_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i32 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
+  // LLVM: [[VQSHRUNS_N_S32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[TMP0]], i32 16)
+  // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRUNS_N_S32]], i64 0
+  // LLVM: ret i16 [[TMP1]]
+  return (int16_t)vqshruns_n_s32(a, 16);
+}
+
+// ALL-LABEL: @test_vqshrund_n_s64(
+int32_t test_vqshrund_n_s64(int64_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: i64 {{.*}} [[A:%.*]])
+  // LLVM: [[VQSHRUND_N_S64:%.*]] = call i32 
@llvm.aarch64.neon.sqshrun.i32(i64 [[A]], i32 32)
+  // LLVM: ret i32 [[VQSHRUND_N_S64]]
+  return (int32_t)vqshrund_n_s64(a, 32);
+}
+
+// ALL-LABEL: @test_vqshrun_high_n_s16(
+uint8x16_t test_vqshrun_high_n_s16(uint8x8_t a, int16x8_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRUN_N3:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, 
i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+  // LLVM: ret <16 x i8> [[SHUFFLE_I]]
+  return vqshrun_high_n_s16(a, b, 3);
+}
+
+// ALL-LABEL: @test_vqshrun_high_n_s32(
+uint16x8_t test_vqshrun_high_n_s32(uint16x4_t a, int32x4_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRUN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
+  // LLVM: ret <8 x i16> [[SHUFFLE_I]]
+  return vqshrun_high_n_s32(a, b, 9);
+}
+
+// ALL-LABEL: @test_vqshrun_high_n_s64(
+uint32x4_t test_vqshrun_high_n_s64(uint32x2_t a, int64x2_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun"
+
+  // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRUN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM: ret <4 x i32> [[SHUFFLE_I]]
+  return vqshrun_high_n_s64(a, b, 19);
+}
+
+// ALL-LABEL: @test_vqshrn_n_s16(
+int8x8_t test_vqshrn_n_s16(int16x8_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 
x i16> [[VQSHRN_N]], i32 3)
+  // LLVM: ret <8 x i8> [[VQSHRN_N1]]
+  return vqshrn_n_s16(a, 3);
+}
+
+// ALL-LABEL: @test_vqshrn_n_s32(
+int16x4_t test_vqshrn_n_s32(int32x4_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
+  // LLVM: ret <4 x i16> [[VQSHRN_N1]]
+  return vqshrn_n_s32(a, 9);
+}
+
+// ALL-LABEL: @test_vqshrn_n_s64(
+int32x2_t test_vqshrn_n_s64(int64x2_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
+  // LLVM: ret <2 x i32> [[VQSHRN_N1]]
+  return vqshrn_n_s64(a, 19);
+}
+
+// ALL-LABEL: @test_vqshrn_n_u16(
+uint8x8_t test_vqshrn_n_u16(uint16x8_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 
x i16> [[VQSHRN_N]], i32 3)
+  // LLVM: ret <8 x i8> [[VQSHRN_N1]]
+  return vqshrn_n_u16(a, 3);
+}
+
+// ALL-LABEL: @test_vqshrn_n_u32(
+uint16x4_t test_vqshrn_n_u32(uint32x4_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
+  // LLVM: ret <4 x i16> [[VQSHRN_N1]]
+  return vqshrn_n_u32(a, 9);
+}
+
+// ALL-LABEL: @test_vqshrn_n_u64(
+uint32x2_t test_vqshrn_n_u64(uint64x2_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRN_N1:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
+  // LLVM: ret <2 x i32> [[VQSHRN_N1]]
+  return vqshrn_n_u64(a, 19);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_s16(
+int8x16_t test_vqshrn_high_n_s16(int8x8_t a, int16x8_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 
x i16> [[VQSHRN_N]], i32 3)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+  // LLVM: ret <16 x i8> [[SHUFFLE_I]]
+  return vqshrn_high_n_s16(a, b, 3);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_s32(
+int16x8_t test_vqshrn_high_n_s32(int16x4_t a, int32x4_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
+  // LLVM: ret <8 x i16> [[SHUFFLE_I]]
+  return vqshrn_high_n_s32(a, b, 9);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_s64(
+int32x4_t test_vqshrn_high_n_s64(int32x2_t a, int64x2_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM: ret <4 x i32> [[SHUFFLE_I]]
+  return vqshrn_high_n_s64(a, b, 19);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_u16(
+uint8x16_t test_vqshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 
x i16> [[VQSHRN_N]], i32 3)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> 
[[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+  // LLVM: ret <16 x i8> [[SHUFFLE_I]]
+  return vqshrn_high_n_u16(a, b, 3);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_u32(
+uint16x8_t test_vqshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> 
[[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 
7>
+  // LLVM: ret <8 x i16> [[SHUFFLE_I]]
+  return vqshrn_high_n_u32(a, b, 9);
+}
+
+// ALL-LABEL: @test_vqshrn_high_n_u64(
+uint32x4_t test_vqshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]])
+  // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
+  // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
+  // LLVM: [[VQSHRN_N3:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19)
+  // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> 
[[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM: ret <4 x i32> [[SHUFFLE_I]]
+  return vqshrn_high_n_u64(a, b, 19);
+}
+
+// ALL-LABEL: @test_vqshrnh_n_s16(
+int8_t test_vqshrnh_n_s16(int16_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i16 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0
+  // LLVM: [[VQSHRNH_N_S16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[TMP0]], i32 8)
+  // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_S16]], i64 0
+  // LLVM: ret i8 [[TMP1]]
+  return (int8_t)vqshrnh_n_s16(a, 8);
+}
+
+// ALL-LABEL: @test_vqshrns_n_s32(
+int16_t test_vqshrns_n_s32(int32_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i32 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
+  // LLVM: [[VQSHRNS_N_S32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[TMP0]], i32 16)
+  // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_S32]], i64 0
+  // LLVM: ret i16 [[TMP1]]
+  return (int16_t)vqshrns_n_s32(a, 16);
+}
+
+// ALL-LABEL: @test_vqshrnd_n_s64(
+int32_t test_vqshrnd_n_s64(int64_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn"
+
+  // LLVM-SAME: i64 {{.*}} [[A:%.*]])
+  // LLVM: [[VQSHRND_N_S64:%.*]] = call i32 @llvm.aarch64.neon.sqshrn.i32(i64 
[[A]], i32 32)
+  // LLVM: ret i32 [[VQSHRND_N_S64]]
+  return (int32_t)vqshrnd_n_s64(a, 32);
+}
+
+// ALL-LABEL: @test_vqshrnh_n_u16(
+uint8_t test_vqshrnh_n_u16(uint16_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i16 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0
+  // LLVM: [[VQSHRNH_N_U16:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[TMP0]], i32 8)
+  // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_U16]], i64 0
+  // LLVM: ret i8 [[TMP1]]
+  return (uint8_t)vqshrnh_n_u16(a, 8);
+}
+
+// ALL-LABEL: @test_vqshrns_n_u32(
+uint16_t test_vqshrns_n_u32(uint32_t a) {
+  // CIR: cir.vec.insert
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+  // CIR: cir.vec.extract
+
+  // LLVM-SAME: i32 {{.*}} [[A:%.*]])
+  // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
+  // LLVM: [[VQSHRNS_N_U32:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[TMP0]], i32 16)
+  // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_U32]], i64 0
+  // LLVM: ret i16 [[TMP1]]
+  return (uint16_t)vqshrns_n_u32(a, 16);
+}
+
+// ALL-LABEL: @test_vqshrnd_n_u64(
+uint32_t test_vqshrnd_n_u64(uint64_t a) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn"
+
+  // LLVM-SAME: i64 {{.*}} [[A:%.*]])
+  // LLVM: [[VQSHRND_N_U64:%.*]] = call i32 @llvm.aarch64.neon.uqshrn.i32(i64 
[[A]], i32 32)
+  // LLVM: ret i32 [[VQSHRND_N_U64]]
+  return (uint32_t)vqshrnd_n_u64(a, 32);
+}

>From a4cf6af4a693a5987d0ffb7d989b2b53dfd93400 Mon Sep 17 00:00:00 2001
From: E00N777 <[email protected]>
Date: Fri, 17 Jul 2026 19:51:10 +0800
Subject: [PATCH 2/2] [CIR][AArch64] Refactor vector saturating shift lowering

---
 .../include/clang/Basic/AArch64CodeGenUtils.h | 18 +++--
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  | 79 ++++++++++---------
 2 files changed, 54 insertions(+), 43 deletions(-)

diff --git a/clang/include/clang/Basic/AArch64CodeGenUtils.h 
b/clang/include/clang/Basic/AArch64CodeGenUtils.h
index 7ae1b20295d1e..489dee1f810c4 100644
--- a/clang/include/clang/Basic/AArch64CodeGenUtils.h
+++ b/clang/include/clang/Basic/AArch64CodeGenUtils.h
@@ -608,13 +608,19 @@ const inline ARMNeonVectorIntrinsicInfo 
AArch64SISDIntrinsicMap[] = {
   NEONMAP1(vqshlus_n_s32, aarch64_neon_sqshlu, Add1ArgType),
   NEONMAP1(vqshrnd_n_s64, aarch64_neon_sqshrn, AddRetType),
   NEONMAP1(vqshrnd_n_u64, aarch64_neon_uqshrn, AddRetType),
-  NEONMAP1(vqshrnh_n_s16, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
-  NEONMAP1(vqshrnh_n_u16, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
-  NEONMAP1(vqshrns_n_s32, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
-  NEONMAP1(vqshrns_n_u32, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
+  NEONMAP1(vqshrnh_n_s16, aarch64_neon_sqshrn,
+           VectorRet | Use64BitVectors | WidenArgs),
+  NEONMAP1(vqshrnh_n_u16, aarch64_neon_uqshrn,
+           VectorRet | Use64BitVectors | WidenArgs),
+  NEONMAP1(vqshrns_n_s32, aarch64_neon_sqshrn,
+           VectorRet | Use64BitVectors | WidenArgs),
+  NEONMAP1(vqshrns_n_u32, aarch64_neon_uqshrn,
+           VectorRet | Use64BitVectors | WidenArgs),
   NEONMAP1(vqshrund_n_s64, aarch64_neon_sqshrun, AddRetType),
-  NEONMAP1(vqshrunh_n_s16, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
-  NEONMAP1(vqshruns_n_s32, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
+  NEONMAP1(vqshrunh_n_s16, aarch64_neon_sqshrun,
+           VectorRet | Use64BitVectors | WidenArgs),
+  NEONMAP1(vqshruns_n_s32, aarch64_neon_sqshrun,
+           VectorRet | Use64BitVectors | WidenArgs),
   NEONMAP1(vqsubb_s8, aarch64_neon_sqsub, Vectorize1ArgType | Use64BitVectors),
   NEONMAP1(vqsubb_u8, aarch64_neon_uqsub, Vectorize1ArgType | Use64BitVectors),
   NEONMAP1(vqsubd_s64, aarch64_neon_sqsub, Add1ArgType),
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 0076031dae84e..9d8db0d24cb8a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -275,7 +275,8 @@ static cir::VectorType 
getNeonPairwiseWidenInputType(cir::VectorType resType,
 static std::pair<mlir::Type, llvm::SmallVector<mlir::Type>>
 deriveNeonSISDIntrinsicOperandTypes(CIRGenFunction &cgf, unsigned modifier,
                                     mlir::Type arg0Ty, mlir::Type resultTy,
-                                    llvm::ArrayRef<mlir::Value> ops) {
+                                    llvm::ArrayRef<mlir::Value> ops,
+                                    unsigned iceArguments) {
   int vectorSize = 0;
   if (modifier & Use64BitVectors)
     vectorSize = 64;
@@ -302,17 +303,26 @@ deriveNeonSISDIntrinsicOperandTypes(CIRGenFunction &cgf, 
unsigned modifier,
   else if (vecArgTy && !(modifier & AddRetType))
     funcResTy = wrapAsVector(resultTy);
 
-  // When VectorizeArgTypes is set, wrap every operand that has the same
-  // scalar type as arg0 into a vector. This covers intrinsics with multiple
-  // data operands of the same type (e.g. vsri takes two data operands,
-  // both of which must be wrapped into the same vector type).
+  // LLVMExtendedType<0> preserves the result vector's lane count while
+  // widening its element type. Reconstruct that source type from the Clang
+  // builtin's scalar data type.
+  if (modifier & WidenArgs) {
+    auto resVecTy = mlir::dyn_cast<cir::VectorType>(funcResTy);
+    assert(resVecTy && "widened SISD arguments require a vector result");
+    vecArgTy = cir::VectorType::get(arg0Ty, resVecTy.getSize());
+  }
+
+  // Wrap every non-immediate data operand that has the same scalar type as
+  // arg0. Checking the ICE bitmap is required when a data operand and an
+  // immediate both have i32 type (e.g. vqshrns_n_s32).
   llvm::SmallVector<mlir::Type> argTypes;
   argTypes.reserve(ops.size());
-  for (mlir::Value op : ops) {
-    if ((modifier & VectorizeArgTypes) && vecArgTy && op.getType() == arg0Ty)
+  for (unsigned i = 0, e = ops.size(); i != e; ++i) {
+    bool isImmediate = iceArguments & (1U << i);
+    if (vecArgTy && !isImmediate && ops[i].getType() == arg0Ty)
       argTypes.push_back(vecArgTy);
     else
-      argTypes.push_back(op.getType());
+      argTypes.push_back(ops[i].getType());
   }
 
   return {funcResTy, std::move(argTypes)};
@@ -344,19 +354,11 @@ static void vecExtendIntValue(CIRGenFunction &cgf, 
cir::VectorType argVTy,
   arg = cir::VecInsertOp::create(builder, loc, poison, arg, zero);
 }
 
-/// Reduce vector type value to scalar, usually for result of a
-/// neon SISD intrinsic call
-static mlir::Value vecReduceIntValue(CIRGenFunction &cgf, mlir::Value val,
-                                     mlir::Location loc) {
-  CIRGenBuilderTy &builder = cgf.getBuilder();
-  assert(mlir::isa<cir::VectorType>(val.getType()));
-  return cir::VecExtractOp::create(builder, loc, val,
-                                   builder.getConstInt(loc, cgf.sizeTy, 0));
-}
-
-static mlir::Value emitCommonNeonSISDBuiltinExpr(
-    CIRGenFunction &cgf, const ARMNeonVectorIntrinsicInfo &info,
-    llvm::SmallVectorImpl<mlir::Value> &ops, const CallExpr *expr) {
+static mlir::Value
+emitCommonNeonSISDBuiltinExpr(CIRGenFunction &cgf,
+                              const ARMNeonVectorIntrinsicInfo &info,
+                              llvm::SmallVectorImpl<mlir::Value> &ops,
+                              const CallExpr *expr, unsigned iceArguments) {
   assert(info.LLVMIntrinsic && "Generic code assumes a valid intrinsic");
 
   switch (info.BuiltinID) {
@@ -514,18 +516,20 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
   // TypeModifier flags. `emitNeonCall` takes care of per-operand
   // bitcasts to `argTypes`.
   auto [funcResTy, argTypes] = deriveNeonSISDIntrinsicOperandTypes(
-      cgf, info.TypeModifier, arg0Ty, resultTy, ops);
+      cgf, info.TypeModifier, arg0Ty, resultTy, ops, iceArguments);
+
+  assert(argTypes.size() == ops.size());
+  for (unsigned i = 0, e = ops.size(); i != e; ++i) {
+    if (cgf.cgm.getDataLayout().getTypeSizeInBits(ops[i].getType()) ==
+        cgf.cgm.getDataLayout().getTypeSizeInBits(argTypes[i]))
+      continue;
 
-  auto resVecTy = mlir::dyn_cast<cir::VectorType>(funcResTy);
-  auto argIntTy = mlir::dyn_cast<cir::IntType>(arg0Ty);
-  auto resultIntTy = mlir::dyn_cast<cir::IntType>(resultTy);
+    auto argVecTy = mlir::dyn_cast<cir::VectorType>(argTypes[i]);
+    assert(argVecTy && !mlir::isa<cir::VectorType>(ops[i].getType()) &&
+           "expecting vector LLVM intrinsic type and scalar Clang builtin "
+           "type");
 
-  if (resVecTy && argIntTy && resultIntTy &&
-      argIntTy.getWidth() == resultIntTy.getWidth() * 2) {
-    cir::VectorType argVecTy = cir::VectorType::get(arg0Ty, 
resVecTy.getSize());
-    assert(!argTypes.empty());
-    argTypes[0] = argVecTy;
-    vecExtendIntValue(cgf, argVecTy, ops[0], loc);
+    vecExtendIntValue(cgf, argVecTy, ops[i], loc);
   }
 
   mlir::Value result = emitNeonCall(cgf.cgm, builder, std::move(argTypes), ops,
@@ -533,13 +537,13 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
 
   if (cgf.cgm.getDataLayout().getTypeSizeInBits(resultTy) <
       cgf.cgm.getDataLayout().getTypeSizeInBits(funcResTy)) {
-    return vecReduceIntValue(cgf, result, loc);
-  }
 
-  if (result.getType() != resultTy)
-    return builder.createBitcast(loc, result, resultTy);
+    assert(mlir::isa<cir::VectorType>(result.getType()));
+    return cir::VecExtractOp::create(builder, loc, result,
+                                     builder.getConstInt(loc, cgf.sizeTy, 0));
+  }
 
-  return result;
+  return builder.createBitcast(loc, result, resultTy);
 }
 
 
//===----------------------------------------------------------------------===//
@@ -2451,7 +2455,8 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned 
builtinID, const CallExpr *expr,
       findARMVectorIntrinsicInMap(ArrayRef(AArch64SISDIntrinsicMap), builtinID,
                                   aarch64SISDIntrinsicsProvenSorted);
   if (builtin)
-    return emitCommonNeonSISDBuiltinExpr(*this, *builtin, ops, expr);
+    return emitCommonNeonSISDBuiltinExpr(*this, *builtin, ops, expr,
+                                         iceArguments);
 
   // Not all intrinsics handled by the common case work for AArch64 yet, so 
only
   // defer to common code if it's been added to our special map.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to