[clang] [CIR][AArch64] Upstream addition-across-vector (incl. widening) NEON builtins (PR #193396)

Vicky Nguyen via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 29 10:55:39 PDT 2026


https://github.com/iamvickynguyen updated https://github.com/llvm/llvm-project/pull/193396

>From 25324adab84c9b116187aa920ef83595711d15f9 Mon Sep 17 00:00:00 2001
From: Vicky Nguyen <vicky.trucviennguyen at gmail.com>
Date: Fri, 24 Apr 2026 21:40:30 -0700
Subject: [PATCH] [CIR][AArch64] Upstream addition-across-vector (incl.
 widening) NEON builtins

---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  |  42 ++-
 clang/lib/CodeGen/TargetBuiltins/ARM.cpp      |  79 ++--
 clang/test/CodeGen/AArch64/neon-across.c      | 206 +----------
 clang/test/CodeGen/AArch64/neon-intrinsics.c  |  90 -----
 clang/test/CodeGen/AArch64/neon/intrinsics.c  | 337 ++++++++++++++++++
 5 files changed, 402 insertions(+), 352 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 294e87168b0e5..f2eeaf62acce3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -317,6 +317,27 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr(
   case NEON::BI__builtin_neon_vcvtd_n_f64_u64:
   case NEON::BI__builtin_neon_vcvtd_n_s64_f64:
   case NEON::BI__builtin_neon_vcvtd_n_u64_f64:
+  case NEON::BI__builtin_neon_vaddlv_s32:
+  case NEON::BI__builtin_neon_vaddlv_u32:
+  case NEON::BI__builtin_neon_vaddlvq_s32:
+  case NEON::BI__builtin_neon_vaddlvq_u32:
+  case NEON::BI__builtin_neon_vaddv_s8:
+  case NEON::BI__builtin_neon_vaddv_s16:
+  case NEON::BI__builtin_neon_vaddv_s32:
+  case NEON::BI__builtin_neon_vaddv_u8:
+  case NEON::BI__builtin_neon_vaddv_u16:
+  case NEON::BI__builtin_neon_vaddv_u32:
+  case NEON::BI__builtin_neon_vaddv_f32:
+  case NEON::BI__builtin_neon_vaddvq_s8:
+  case NEON::BI__builtin_neon_vaddvq_s16:
+  case NEON::BI__builtin_neon_vaddvq_s32:
+  case NEON::BI__builtin_neon_vaddvq_s64:
+  case NEON::BI__builtin_neon_vaddvq_u8:
+  case NEON::BI__builtin_neon_vaddvq_u16:
+  case NEON::BI__builtin_neon_vaddvq_u32:
+  case NEON::BI__builtin_neon_vaddvq_u64:
+  case NEON::BI__builtin_neon_vaddvq_f32:
+  case NEON::BI__builtin_neon_vaddvq_f64:
     return emitNeonCall(cgf.cgm, cgf.getBuilder(),
                         {cgf.convertType(expr->getArg(0)->getType())}, ops,
                         llvmIntrName, cgf.convertType(expr->getType()), loc);
@@ -2708,7 +2729,26 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vaddlv_s8:
   case NEON::BI__builtin_neon_vaddlv_s16:
   case NEON::BI__builtin_neon_vaddlvq_s8:
-  case NEON::BI__builtin_neon_vaddlvq_s16:
+  case NEON::BI__builtin_neon_vaddlvq_s16: {
+    mlir::Type argTy = convertType(expr->getArg(0)->getType());
+    mlir::Type userRetTy = convertType(expr->getType());
+    auto eltTy = mlir::cast<cir::IntType>(
+        mlir::cast<cir::VectorType>(argTy).getElementType());
+    bool isUnsigned = !eltTy.isSigned();
+    // These builtins only use 8 and 16-bit element vectors; the intrinsic
+    // always produces i32. The C result is i32 for 16-bit elements, but i16
+    // for 8-bit elements, so we emit at i32 and narrow only in that case.
+    bool needsTrunc = eltTy.getWidth() == 8;
+    intrName = isUnsigned ? "aarch64.neon.uaddlv" : "aarch64.neon.saddlv";
+    mlir::Type intrRetTy = userRetTy;
+    if (needsTrunc)
+      intrRetTy = isUnsigned ? builder.getUInt32Ty() : builder.getSInt32Ty();
+    mlir::Value result =
+        emitNeonCall(cgm, builder, {argTy}, ops, intrName, intrRetTy, loc);
+    if (needsTrunc)
+      result = builder.createIntCast(result, userRetTy);
+    return result;
+  }
   case NEON::BI__builtin_neon_vsri_n_v:
   case NEON::BI__builtin_neon_vsriq_n_v:
   case NEON::BI__builtin_neon_vsli_n_v:
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index d897e52b711fd..4fc66307c54c7 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -6569,65 +6569,32 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
     Value *RHS = Builder.CreateBitCast(Ops[1], DoubleTy);
     return Builder.CreateFMul(Ops[0], RHS);
   }
-  case NEON::BI__builtin_neon_vaddlv_u8: {
-    Int = Intrinsic::aarch64_neon_uaddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int8Ty, 8);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-    return Builder.CreateTrunc(Ops[0], Int16Ty);
-  }
-  case NEON::BI__builtin_neon_vaddlv_u16: {
-    Int = Intrinsic::aarch64_neon_uaddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int16Ty, 4);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-  }
-  case NEON::BI__builtin_neon_vaddlvq_u8: {
-    Int = Intrinsic::aarch64_neon_uaddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int8Ty, 16);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-    return Builder.CreateTrunc(Ops[0], Int16Ty);
-  }
-  case NEON::BI__builtin_neon_vaddlvq_u16: {
-    Int = Intrinsic::aarch64_neon_uaddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int16Ty, 8);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-  }
-  case NEON::BI__builtin_neon_vaddlv_s8: {
-    Int = Intrinsic::aarch64_neon_saddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int8Ty, 8);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-    return Builder.CreateTrunc(Ops[0], Int16Ty);
-  }
-  case NEON::BI__builtin_neon_vaddlv_s16: {
-    Int = Intrinsic::aarch64_neon_saddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int16Ty, 4);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-  }
-  case NEON::BI__builtin_neon_vaddlvq_s8: {
-    Int = Intrinsic::aarch64_neon_saddlv;
-    Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int8Ty, 16);
-    llvm::Type *Tys[2] = {Ty, VTy};
-    Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
-    return Builder.CreateTrunc(Ops[0], Int16Ty);
-  }
+  case NEON::BI__builtin_neon_vaddlv_u8:
+  case NEON::BI__builtin_neon_vaddlvq_u8:
+  case NEON::BI__builtin_neon_vaddlv_u16:
+  case NEON::BI__builtin_neon_vaddlvq_u16:
+  case NEON::BI__builtin_neon_vaddlv_s8:
+  case NEON::BI__builtin_neon_vaddlvq_s8:
+  case NEON::BI__builtin_neon_vaddlv_s16:
   case NEON::BI__builtin_neon_vaddlvq_s16: {
-    Int = Intrinsic::aarch64_neon_saddlv;
+    switch (BuiltinID) {
+    case NEON::BI__builtin_neon_vaddlv_u8:
+    case NEON::BI__builtin_neon_vaddlvq_u8:
+    case NEON::BI__builtin_neon_vaddlv_u16:
+    case NEON::BI__builtin_neon_vaddlvq_u16:
+      Int = Intrinsic::aarch64_neon_uaddlv;
+      break;
+    default:
+      Int = Intrinsic::aarch64_neon_saddlv;
+      break;
+    }
     Ty = Int32Ty;
-    VTy = llvm::FixedVectorType::get(Int16Ty, 8);
+    VTy = cast<llvm::FixedVectorType>(Ops[0]->getType());
     llvm::Type *Tys[2] = {Ty, VTy};
-    return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+    Value *Result = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+    if (VTy->getElementType()->getPrimitiveSizeInBits() == 8)
+      return Builder.CreateTrunc(Result, Int16Ty);
+    return Result;
   }
   case NEON::BI__builtin_neon_vsri_n_v:
   case NEON::BI__builtin_neon_vsriq_n_v: {
diff --git a/clang/test/CodeGen/AArch64/neon-across.c b/clang/test/CodeGen/AArch64/neon-across.c
index 7a76173c54882..50044eb0ed045 100644
--- a/clang/test/CodeGen/AArch64/neon-across.c
+++ b/clang/test/CodeGen/AArch64/neon-across.c
@@ -6,112 +6,8 @@
 
 #include <arm_neon.h>
 
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlv_s8
-// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v8i8(<8 x i8> [[A]])
-// CHECK-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
-// CHECK-NEXT:    ret i16 [[TMP0]]
-//
-int16_t test_vaddlv_s8(int8x8_t a) {
-  return vaddlv_s8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlv_s16
-// CHECK-SAME: (<4 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v4i16(<4 x i16> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDLV_I]]
-//
-int32_t test_vaddlv_s16(int16x4_t a) {
-  return vaddlv_s16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlv_u8
-// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v8i8(<8 x i8> [[A]])
-// CHECK-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
-// CHECK-NEXT:    ret i16 [[TMP0]]
-//
-uint16_t test_vaddlv_u8(uint8x8_t a) {
-  return vaddlv_u8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlv_u16
-// CHECK-SAME: (<4 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v4i16(<4 x i16> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDLV_I]]
-//
-uint32_t test_vaddlv_u16(uint16x4_t a) {
-  return vaddlv_u16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_s8
-// CHECK-SAME: (<16 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v16i8(<16 x i8> [[A]])
-// CHECK-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
-// CHECK-NEXT:    ret i16 [[TMP0]]
-//
-int16_t test_vaddlvq_s8(int8x16_t a) {
-  return vaddlvq_s8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_s16
-// CHECK-SAME: (<8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v8i16(<8 x i16> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDLV_I]]
-//
-int32_t test_vaddlvq_s16(int16x8_t a) {
-  return vaddlvq_s16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_s32
-// CHECK-SAME: (<4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLVQ_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v4i32(<4 x i32> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDLVQ_S32_I]]
-//
-int64_t test_vaddlvq_s32(int32x4_t a) {
-  return vaddlvq_s32(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_u8
-// CHECK-SAME: (<16 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v16i8(<16 x i8> [[A]])
-// CHECK-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
-// CHECK-NEXT:    ret i16 [[TMP0]]
-//
-uint16_t test_vaddlvq_u8(uint8x16_t a) {
-  return vaddlvq_u8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_u16
-// CHECK-SAME: (<8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v8i16(<8 x i16> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDLV_I]]
-//
-uint32_t test_vaddlvq_u16(uint16x8_t a) {
-  return vaddlvq_u16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddlvq_u32
-// CHECK-SAME: (<4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDLVQ_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v4i32(<4 x i32> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDLVQ_U32_I]]
-//
-uint64_t test_vaddlvq_u32(uint32x4_t a) {
-  return vaddlvq_u32(a);
-}
-
 // CHECK-LABEL: define {{[^@]+}}@test_vmaxv_s8
-// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[VMAXV_S8_I:%.*]] = call i8 @llvm.vector.reduce.smax.v8i8(<8 x i8> [[A]])
 // CHECK-NEXT:    ret i8 [[VMAXV_S8_I]]
@@ -210,106 +106,6 @@ uint32_t test_vmaxvq_u32(uint32x4_t a) {
   return vmaxvq_u32(a);
 }
 
-// CHECK-LABEL: define {{[^@]+}}@test_vaddv_s8
-// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDV_S8_I:%.*]] = call i8 @llvm.vector.reduce.add.v8i8(<8 x i8> [[A]])
-// CHECK-NEXT:    ret i8 [[VADDV_S8_I]]
-//
-int8_t test_vaddv_s8(int8x8_t a) {
-  return vaddv_s8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddv_s16
-// CHECK-SAME: (<4 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDV_S16_I:%.*]] = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> [[A]])
-// CHECK-NEXT:    ret i16 [[VADDV_S16_I]]
-//
-int16_t test_vaddv_s16(int16x4_t a) {
-  return vaddv_s16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddv_u8
-// CHECK-SAME: (<8 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDV_U8_I:%.*]] = call i8 @llvm.vector.reduce.add.v8i8(<8 x i8> [[A]])
-// CHECK-NEXT:    ret i8 [[VADDV_U8_I]]
-//
-uint8_t test_vaddv_u8(uint8x8_t a) {
-  return vaddv_u8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddv_u16
-// CHECK-SAME: (<4 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDV_U16_I:%.*]] = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> [[A]])
-// CHECK-NEXT:    ret i16 [[VADDV_U16_I]]
-//
-uint16_t test_vaddv_u16(uint16x4_t a) {
-  return vaddv_u16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_s8
-// CHECK-SAME: (<16 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_S8_I:%.*]] = call i8 @llvm.vector.reduce.add.v16i8(<16 x i8> [[A]])
-// CHECK-NEXT:    ret i8 [[VADDVQ_S8_I]]
-//
-int8_t test_vaddvq_s8(int8x16_t a) {
-  return vaddvq_s8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_s16
-// CHECK-SAME: (<8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_S16_I:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[A]])
-// CHECK-NEXT:    ret i16 [[VADDVQ_S16_I]]
-//
-int16_t test_vaddvq_s16(int16x8_t a) {
-  return vaddvq_s16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_s32
-// CHECK-SAME: (<4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_S32_I:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDVQ_S32_I]]
-//
-int32_t test_vaddvq_s32(int32x4_t a) {
-  return vaddvq_s32(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_u8
-// CHECK-SAME: (<16 x i8> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_U8_I:%.*]] = call i8 @llvm.vector.reduce.add.v16i8(<16 x i8> [[A]])
-// CHECK-NEXT:    ret i8 [[VADDVQ_U8_I]]
-//
-uint8_t test_vaddvq_u8(uint8x16_t a) {
-  return vaddvq_u8(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_u16
-// CHECK-SAME: (<8 x i16> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_U16_I:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[A]])
-// CHECK-NEXT:    ret i16 [[VADDVQ_U16_I]]
-//
-uint16_t test_vaddvq_u16(uint16x8_t a) {
-  return vaddvq_u16(a);
-}
-
-// CHECK-LABEL: define {{[^@]+}}@test_vaddvq_u32
-// CHECK-SAME: (<4 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[VADDVQ_U32_I:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDVQ_U32_I]]
-//
-uint32_t test_vaddvq_u32(uint32x4_t a) {
-  return vaddvq_u32(a);
-}
-
 // CHECK-LABEL: define {{[^@]+}}@test_vmaxvq_f32
 // CHECK-SAME: (<4 x float> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index 920a0236bb433..255597a86fdbf 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -20307,36 +20307,6 @@ int64x1_t test_vneg_s64(int64x1_t a) {
   return vneg_s64(a);
 }
 
-// CHECK-LABEL: define dso_local float @test_vaddv_f32(
-// CHECK-SAME: <2 x float> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> [[A]])
-// CHECK-NEXT:    ret float [[VADDV_F32_I]]
-//
-float32_t test_vaddv_f32(float32x2_t a) {
-  return vaddv_f32(a);
-}
-
-// CHECK-LABEL: define dso_local float @test_vaddvq_f32(
-// CHECK-SAME: <4 x float> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> [[A]])
-// CHECK-NEXT:    ret float [[VADDVQ_F32_I]]
-//
-float32_t test_vaddvq_f32(float32x4_t a) {
-  return vaddvq_f32(a);
-}
-
-// CHECK-LABEL: define dso_local double @test_vaddvq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> [[A]])
-// CHECK-NEXT:    ret double [[VADDVQ_F64_I]]
-//
-float64_t test_vaddvq_f64(float64x2_t a) {
-  return vaddvq_f64(a);
-}
-
 // CHECK-LABEL: define dso_local float @test_vmaxv_f32(
 // CHECK-SAME: <2 x float> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -20419,26 +20389,6 @@ uint64_t test_vpaddd_u64(uint64x2_t a) {
   return vpaddd_u64(a);
 }
 
-// CHECK-LABEL: define dso_local i64 @test_vaddvq_s64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDVQ_S64_I:%.*]] = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDVQ_S64_I]]
-//
-int64_t test_vaddvq_s64(int64x2_t a) {
-  return vaddvq_s64(a);
-}
-
-// CHECK-LABEL: define dso_local i64 @test_vaddvq_u64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDVQ_U64_I:%.*]] = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDVQ_U64_I]]
-//
-uint64_t test_vaddvq_u64(uint64x2_t a) {
-  return vaddvq_u64(a);
-}
-
 // CHECK-LABEL: define dso_local <1 x double> @test_vadd_f64(
 // CHECK-SAME: <1 x double> noundef [[A:%.*]], <1 x double> noundef [[B:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -20944,43 +20894,3 @@ int32_t test_vmaxv_s32(int32x2_t a) {
 uint32_t test_vmaxv_u32(uint32x2_t a) {
   return vmaxv_u32(a);
 }
-
-// CHECK-LABEL: define dso_local i32 @test_vaddv_s32(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDV_S32_I:%.*]] = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDV_S32_I]]
-//
-int32_t test_vaddv_s32(int32x2_t a) {
-  return vaddv_s32(a);
-}
-
-// CHECK-LABEL: define dso_local i32 @test_vaddv_u32(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDV_U32_I:%.*]] = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> [[A]])
-// CHECK-NEXT:    ret i32 [[VADDV_U32_I]]
-//
-uint32_t test_vaddv_u32(uint32x2_t a) {
-  return vaddv_u32(a);
-}
-
-// CHECK-LABEL: define dso_local i64 @test_vaddlv_s32(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDLV_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v2i32(<2 x i32> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDLV_S32_I]]
-//
-int64_t test_vaddlv_s32(int32x2_t a) {
-  return vaddlv_s32(a);
-}
-
-// CHECK-LABEL: define dso_local i64 @test_vaddlv_u32(
-// CHECK-SAME: <2 x i32> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VADDLV_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v2i32(<2 x i32> [[A]])
-// CHECK-NEXT:    ret i64 [[VADDLV_U32_I]]
-//
-uint64_t test_vaddlv_u32(uint32x2_t a) {
-  return vaddlv_u32(a);
-}
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index bf14d1abc9d8e..756040aa7b5b9 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -4253,3 +4253,340 @@ float64_t test_vminnmvq_f64(float64x2_t a) {
 // LLVM-NEXT:    ret double [[VMINNMVQ_F64_I]]
   return vminnmvq_f64(a);
 }
+
+//===----------------------------------------------------------------------===//
+// 2.1.9.1 Addition across vector
+// https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#addition-across-vector
+//===----------------------------------------------------------------------===//
+
+// LLVM-LABEL: @test_vaddv_s8(
+// CIR-LABEL: @vaddv_s8(
+int8_t test_vaddv_s8(int8x8_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<8 x !s8i>) -> !s8i
+
+// LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i8 @llvm.vector.reduce.add.v8i8(<8 x i8> [[A]])
+// LLVM-NEXT:    ret i8 [[VADDV_I]]
+  return vaddv_s8(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_s8(
+// CIR-LABEL: @vaddvq_s8(
+int8_t test_vaddvq_s8(int8x16_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<16 x !s8i>) -> !s8i
+
+// LLVM-SAME: <16 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i8 @llvm.vector.reduce.add.v16i8(<16 x i8> [[A]])
+// LLVM-NEXT:    ret i8 [[VADDVQ_I]]
+  return vaddvq_s8(a);
+}
+
+// LLVM-LABEL: @test_vaddv_s16(
+// CIR-LABEL: @vaddv_s16(
+int16_t test_vaddv_s16(int16x4_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<4 x !s16i>) -> !s16i
+
+// LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> [[A]])
+// LLVM-NEXT:    ret i16 [[VADDV_I]]
+  return vaddv_s16(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_s16(
+// CIR-LABEL: @vaddvq_s16(
+int16_t test_vaddvq_s16(int16x8_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<8 x !s16i>) -> !s16i
+
+// LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[A]])
+// LLVM-NEXT:    ret i16 [[VADDVQ_I]]
+  return vaddvq_s16(a);
+}
+
+// LLVM-LABEL: @test_vaddv_s32(
+// CIR-LABEL: @vaddv_s32(
+int32_t test_vaddv_s32(int32x2_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<2 x !s32i>) -> !s32i
+
+// LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDV_I]]
+  return vaddv_s32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_s32(
+// CIR-LABEL: @vaddvq_s32(
+int32_t test_vaddvq_s32(int32x4_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<4 x !s32i>) -> !s32i
+
+// LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDVQ_I]]
+  return vaddvq_s32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_s64(
+// CIR-LABEL: @vaddvq_s64(
+int64_t test_vaddvq_s64(int64x2_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<2 x !s64i>) -> !s64i
+
+// LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDVQ_I]]
+  return vaddvq_s64(a);
+}
+
+// LLVM-LABEL: @test_vaddv_u8(
+// CIR-LABEL: @vaddv_u8(
+uint8_t test_vaddv_u8(uint8x8_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<8 x !u8i>) -> !u8i
+
+// LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i8 @llvm.vector.reduce.add.v8i8(<8 x i8> [[A]])
+// LLVM-NEXT:    ret i8 [[VADDV_I]]
+  return vaddv_u8(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_u8(
+// CIR-LABEL: @vaddvq_u8(
+uint8_t test_vaddvq_u8(uint8x16_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<16 x !u8i>) -> !u8i
+
+// LLVM-SAME: <16 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i8 @llvm.vector.reduce.add.v16i8(<16 x i8> [[A]])
+// LLVM-NEXT:    ret i8 [[VADDVQ_I]]
+  return vaddvq_u8(a);
+}
+
+// LLVM-LABEL: @test_vaddv_u16(
+// CIR-LABEL: @vaddv_u16(
+uint16_t test_vaddv_u16(uint16x4_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<4 x !u16i>) -> !u16i
+
+// LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> [[A]])
+// LLVM-NEXT:    ret i16 [[VADDV_I]]
+  return vaddv_u16(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_u16(
+// CIR-LABEL: @vaddvq_u16(
+uint16_t test_vaddvq_u16(uint16x8_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<8 x !u16i>) -> !u16i
+
+// LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[A]])
+// LLVM-NEXT:    ret i16 [[VADDVQ_I]]
+  return vaddvq_u16(a);
+}
+
+// LLVM-LABEL: @test_vaddv_u32(
+// CIR-LABEL: @vaddv_u32(
+uint32_t test_vaddv_u32(uint32x2_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<2 x !u32i>) -> !u32i
+
+// LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_I:%.*]] = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDV_I]]
+  return vaddv_u32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_u32(
+// CIR-LABEL: @vaddvq_u32(
+uint32_t test_vaddvq_u32(uint32x4_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<4 x !u32i>) -> !u32i
+
+// LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDVQ_I]]
+  return vaddvq_u32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_u64(
+// CIR-LABEL: @vaddvq_u64(
+uint64_t test_vaddvq_u64(uint64x2_t a) {
+// CIR: cir.call_llvm_intrinsic "vector.reduce.add" %{{.*}} : (!cir.vector<2 x !u64i>) -> !u64i
+
+// LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_I:%.*]] = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDVQ_I]]
+  return vaddvq_u64(a);
+}
+
+// LLVM-LABEL: @test_vaddv_f32(
+// CIR-LABEL: @vaddv_f32(
+float32_t test_vaddv_f32(float32x2_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.faddv" %{{.*}} : (!cir.vector<2 x !cir.float>) -> !cir.float
+
+// LLVM-SAME: <2 x float> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> [[A]])
+// LLVM-NEXT:    ret float [[VADDV_F32_I]]
+  return vaddv_f32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_f32(
+// CIR-LABEL: @vaddvq_f32(
+float32_t test_vaddvq_f32(float32x4_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.faddv" %{{.*}} : (!cir.vector<4 x !cir.float>) -> !cir.float
+
+// LLVM-SAME: <4 x float> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> [[A]])
+// LLVM-NEXT:    ret float [[VADDVQ_F32_I]]
+  return vaddvq_f32(a);
+}
+
+// LLVM-LABEL: @test_vaddvq_f64(
+// CIR-LABEL: @vaddvq_f64(
+float64_t test_vaddvq_f64(float64x2_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.faddv" %{{.*}} : (!cir.vector<2 x !cir.double>) -> !cir.double
+
+// LLVM-SAME: <2 x double> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> [[A]])
+// LLVM-NEXT:    ret double [[VADDVQ_F64_I]]
+  return vaddvq_f64(a);
+}
+
+//===----------------------------------------------------------------------===//
+// 2.1.9.2 Addition across vector widening
+// https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#addition-across-vector-widening
+//===----------------------------------------------------------------------===//
+
+// LLVM-LABEL: @test_vaddlv_s8(
+// CIR-LABEL: @vaddlv_s8(
+int16_t test_vaddlv_s8(int8x8_t a) {
+// CIR: [[VADDLV_I:%.*]] = cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<8 x !s8i>) -> !s32i
+// CIR: cir.cast integral [[VADDLV_I]] : !s32i -> !s16i
+
+// LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v8i8(<8 x i8> [[A]])
+// LLVM-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
+// LLVM-NEXT:    ret i16 [[TMP0]]
+  return vaddlv_s8(a);
+}
+
+// LLVM-LABEL: @test_vaddlv_s16(
+// CIR-LABEL: @vaddlv_s16(
+int32_t test_vaddlv_s16(int16x4_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<4 x !s16i>) -> !s32i
+
+// LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v4i16(<4 x i16> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDLV_I]]
+  return vaddlv_s16(a);
+}
+
+// LLVM-LABEL: @test_vaddlv_s32(
+// CIR-LABEL: @vaddlv_s32(
+int64_t test_vaddlv_s32(int32x2_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<2 x !s32i>) -> !s64i
+
+// LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v2i32(<2 x i32> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDLV_S32_I]]
+  return vaddlv_s32(a);
+}
+
+// LLVM-LABEL: @test_vaddlv_u8(
+// CIR-LABEL: @vaddlv_u8(
+uint16_t test_vaddlv_u8(uint8x8_t a) {
+// CIR: [[VADDLV_I:%.*]] = cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<8 x !u8i>) -> !u32i
+// CIR: cir.cast integral [[VADDLV_I]] : !u32i -> !u16i
+
+// LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v8i8(<8 x i8> [[A]])
+// LLVM-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
+// LLVM-NEXT:    ret i16 [[TMP0]]
+  return vaddlv_u8(a);
+}
+
+// LLVM-LABEL: @test_vaddlv_u16(
+// CIR-LABEL: @vaddlv_u16(
+uint32_t test_vaddlv_u16(uint16x4_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<4 x !u16i>) -> !u32i
+
+// LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v4i16(<4 x i16> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDLV_I]]
+  return vaddlv_u16(a);
+}
+
+// LLVM-LABEL: @test_vaddlv_u32(
+// CIR-LABEL: @vaddlv_u32(
+uint64_t test_vaddlv_u32(uint32x2_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<2 x !u32i>) -> !u64i
+
+// LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v2i32(<2 x i32> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDLV_U32_I]]
+  return vaddlv_u32(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_s8(
+// CIR-LABEL: @vaddlvq_s8(
+int16_t test_vaddlvq_s8(int8x16_t a) {
+// CIR: [[VADDLV_I:%.*]] = cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<16 x !s8i>) -> !s32i
+// CIR: cir.cast integral [[VADDLV_I]] : !s32i -> !s16i
+
+// LLVM-SAME: <16 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v16i8(<16 x i8> [[A]])
+// LLVM-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
+// LLVM-NEXT:    ret i16 [[TMP0]]
+  return vaddlvq_s8(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_s16(
+// CIR-LABEL: @vaddlvq_s16(
+int32_t test_vaddlvq_s16(int16x8_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<8 x !s16i>) -> !s32i
+
+// LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.saddlv.i32.v8i16(<8 x i16> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDLV_I]]
+  return vaddlvq_s16(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_s32(
+// CIR-LABEL: @vaddlvq_s32(
+int64_t test_vaddlvq_s32(int32x4_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.saddlv" %{{.*}} : (!cir.vector<4 x !s32i>) -> !s64i
+
+// LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLVQ_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v4i32(<4 x i32> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDLVQ_S32_I]]
+  return vaddlvq_s32(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_u8(
+// CIR-LABEL: @vaddlvq_u8(
+uint16_t test_vaddlvq_u8(uint8x16_t a) {
+// CIR: [[VADDLV_I:%.*]] = cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<16 x !u8i>) -> !u32i
+// CIR: cir.cast integral [[VADDLV_I]] : !u32i -> !u16i
+
+// LLVM-SAME: <16 x i8> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v16i8(<16 x i8> [[A]])
+// LLVM-NEXT:    [[TMP0:%.*]] = trunc i32 [[VADDLV_I]] to i16
+// LLVM-NEXT:    ret i16 [[TMP0]]
+  return vaddlvq_u8(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_u16(
+// CIR-LABEL: @vaddlvq_u16(
+uint32_t test_vaddlvq_u16(uint16x8_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<8 x !u16i>) -> !u32i
+
+// LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLV_I:%.*]] = call i32 @llvm.aarch64.neon.uaddlv.i32.v8i16(<8 x i16> [[A]])
+// LLVM-NEXT:    ret i32 [[VADDLV_I]]
+  return vaddlvq_u16(a);
+}
+
+// LLVM-LABEL: @test_vaddlvq_u32(
+// CIR-LABEL: @vaddlvq_u32(
+uint64_t test_vaddlvq_u32(uint32x4_t a) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.uaddlv" %{{.*}} : (!cir.vector<4 x !u32i>) -> !u64i
+
+// LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]])
+// LLVM:    [[VADDLVQ_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v4i32(<4 x i32> [[A]])
+// LLVM-NEXT:    ret i64 [[VADDLVQ_U32_I]]
+  return vaddlvq_u32(a);
+}



More information about the cfe-commits mailing list