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

>From a6fb1d4b920682aa6bd83ec93b54268dc215be85 Mon Sep 17 00:00:00 2001
From: Vicky Nguyen <[email protected]>
Date: Wed, 1 Jul 2026 21:35:32 -0700
Subject: [PATCH] [CIR][AArch64] Upstream narrowing-subtraction NEON builtins

---
 .../include/clang/Basic/AArch64CodeGenUtils.h |   2 +-
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  |  30 +-
 clang/test/CodeGen/AArch64/neon-intrinsics.c  | 556 ------------------
 clang/test/CodeGen/AArch64/neon/subtraction.c | 466 ++++++++++++++-
 4 files changed, 494 insertions(+), 560 deletions(-)

diff --git a/clang/include/clang/Basic/AArch64CodeGenUtils.h 
b/clang/include/clang/Basic/AArch64CodeGenUtils.h
index 2c70ef5f777fd..8c57478a1acf2 100644
--- a/clang/include/clang/Basic/AArch64CodeGenUtils.h
+++ b/clang/include/clang/Basic/AArch64CodeGenUtils.h
@@ -350,7 +350,7 @@ const inline ARMNeonVectorIntrinsicInfo 
AArch64SIMDIntrinsicMap [] = {
   NEONMAP2(vrsqrteq_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
   NEONMAP1(vrsqrts_v, aarch64_neon_frsqrts, Add1ArgType),
   NEONMAP1(vrsqrtsq_v, aarch64_neon_frsqrts, Add1ArgType),
-  NEONMAP1(vrsubhn_v, aarch64_neon_rsubhn, Add1ArgType),
+  NEONMAP1(vrsubhn_v, aarch64_neon_rsubhn, Add1ArgType | WidenArgs),
   NEONMAP1(vsha1su0q_u32, aarch64_crypto_sha1su0, 0),
   NEONMAP1(vsha1su1q_u32, aarch64_crypto_sha1su1, 0),
   NEONMAP1(vsha256h2q_u32, aarch64_crypto_sha256h2, 0),
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index e3418d561df34..b29703e8f4825 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -718,6 +718,30 @@ static mlir::Value emitCommonNeonBuiltinExpr(
     // %res = trunc <4 x i32> %high to <4 x i16>
     return cgf.getBuilder().createIntCast(result, vTy);
   }
+  case NEON::BI__builtin_neon_vsubhn_v: {
+    // srcTy has double-width elements (e.g. <8 x i16> when VTy is <8 x i8>).
+    // Unsigned so createShiftRight emits lshr, not ashr.
+    cir::VectorType srcTy =
+        cgf.getBuilder().getExtendedOrTruncatedElementVectorType(
+            vTy, /*isExtended=*/true, /*isSigned=*/false);
+
+    // %diff = sub <4 x i32> %lhs, %rhs
+    ops[0] = cgf.getBuilder().createBitcast(ops[0], srcTy);
+    ops[1] = cgf.getBuilder().createBitcast(ops[1], srcTy);
+    mlir::Value result = cgf.getBuilder().createSub(loc, ops[0], ops[1]);
+
+    // %high = lshr <4 x i32> %diff, <i32 16, i32 16, i32 16, i32 16>
+    auto wideEltTy = mlir::cast<cir::IntType>(srcTy.getElementType());
+    mlir::Value shiftAmt = cgf.getBuilder().getConstantInt(
+        loc, wideEltTy, wideEltTy.getWidth() / 2);
+    mlir::Value shiftVec =
+        emitNeonShiftVector(cgf.getBuilder(), shiftAmt, srcTy, loc,
+                            /*neg=*/false);
+    result = cgf.getBuilder().createShiftRight(loc, result, shiftVec);
+
+    // %res = trunc <4 x i32> %high to <4 x i16>
+    return cgf.getBuilder().createIntCast(result, vTy);
+  }
   case NEON::BI__builtin_neon_vcale_v:
   case NEON::BI__builtin_neon_vcaleq_v:
   case NEON::BI__builtin_neon_vcalt_v:
@@ -1039,7 +1063,6 @@ static mlir::Value emitCommonNeonBuiltinExpr(
   case NEON::BI__builtin_neon_vst1q_x3_v:
   case NEON::BI__builtin_neon_vst1_x4_v:
   case NEON::BI__builtin_neon_vst1q_x4_v:
-  case NEON::BI__builtin_neon_vsubhn_v:
   case NEON::BI__builtin_neon_vtrn_v:
   case NEON::BI__builtin_neon_vtrnq_v:
   case NEON::BI__builtin_neon_vtst_v:
@@ -1094,11 +1117,14 @@ static mlir::Value emitCommonNeonBuiltinExpr(
     break;
   case NEON::BI__builtin_neon_vhadd_v:
   case NEON::BI__builtin_neon_vhaddq_v:
+  case NEON::BI__builtin_neon_vhsub_v:
+  case NEON::BI__builtin_neon_vhsubq_v:
   case NEON::BI__builtin_neon_vrhadd_v:
   case NEON::BI__builtin_neon_vrhaddq_v:
   case NEON::BI__builtin_neon_vshl_v:
   case NEON::BI__builtin_neon_vshlq_v:
-  case NEON::BI__builtin_neon_vraddhn_v: {
+  case NEON::BI__builtin_neon_vraddhn_v:
+  case NEON::BI__builtin_neon_vrsubhn_v: {
     // Pick the signed/unsigned intrinsic when the builtin has both
     // (UnsignedAlts); otherwise there is a single intrinsic.
     unsigned intrinsic =
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c 
b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index d956ed754c45a..2c2178a9d13cc 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -2385,174 +2385,6 @@ uint64x2_t test_vcltq_f64(float64x2_t v1, float64x2_t 
v2) {
   return vcltq_f64(v1, v2);
 }
 
-// CHECK-LABEL: define dso_local <8 x i8> @test_vhsub_s8(
-// CHECK-SAME: <8 x i8> noundef [[V1:%.*]], <8 x i8> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.shsub.v8i8(<8 x i8> [[V1]], <8 x i8> [[V2]])
-// CHECK-NEXT:    ret <8 x i8> [[VHSUB_V_I]]
-//
-int8x8_t test_vhsub_s8(int8x8_t v1, int8x8_t v2) {
-  return vhsub_s8(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vhsub_s16(
-// CHECK-SAME: <4 x i16> noundef [[V1:%.*]], <4 x i16> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i16> [[V1]] to <8 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[V2]] to <8 x i8>
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
-// CHECK-NEXT:    [[VHSUB_V1_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK-NEXT:    [[VHSUB_V2_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.shsub.v4i16(<4 x i16> [[VHSUB_V_I]], <4 x i16> 
[[VHSUB_V1_I]])
-// CHECK-NEXT:    [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 
x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VHSUB_V3_I]] to <4 x i16>
-// CHECK-NEXT:    ret <4 x i16> [[TMP2]]
-//
-int16x4_t test_vhsub_s16(int16x4_t v1, int16x4_t v2) {
-  return vhsub_s16(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vhsub_s32(
-// CHECK-SAME: <2 x i32> noundef [[V1:%.*]], <2 x i32> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i32> [[V1]] to <8 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[V2]] to <8 x i8>
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32>
-// CHECK-NEXT:    [[VHSUB_V1_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <2 x i32>
-// CHECK-NEXT:    [[VHSUB_V2_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.shsub.v2i32(<2 x i32> [[VHSUB_V_I]], <2 x i32> 
[[VHSUB_V1_I]])
-// CHECK-NEXT:    [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 
x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VHSUB_V3_I]] to <2 x i32>
-// CHECK-NEXT:    ret <2 x i32> [[TMP2]]
-//
-int32x2_t test_vhsub_s32(int32x2_t v1, int32x2_t v2) {
-  return vhsub_s32(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <8 x i8> @test_vhsub_u8(
-// CHECK-SAME: <8 x i8> noundef [[V1:%.*]], <8 x i8> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.uhsub.v8i8(<8 x i8> [[V1]], <8 x i8> [[V2]])
-// CHECK-NEXT:    ret <8 x i8> [[VHSUB_V_I]]
-//
-uint8x8_t test_vhsub_u8(uint8x8_t v1, uint8x8_t v2) {
-  return vhsub_u8(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vhsub_u16(
-// CHECK-SAME: <4 x i16> noundef [[V1:%.*]], <4 x i16> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i16> [[V1]] to <8 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[V2]] to <8 x i8>
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
-// CHECK-NEXT:    [[VHSUB_V1_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK-NEXT:    [[VHSUB_V2_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.uhsub.v4i16(<4 x i16> [[VHSUB_V_I]], <4 x i16> 
[[VHSUB_V1_I]])
-// CHECK-NEXT:    [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 
x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VHSUB_V3_I]] to <4 x i16>
-// CHECK-NEXT:    ret <4 x i16> [[TMP2]]
-//
-uint16x4_t test_vhsub_u16(uint16x4_t v1, uint16x4_t v2) {
-  return vhsub_u16(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vhsub_u32(
-// CHECK-SAME: <2 x i32> noundef [[V1:%.*]], <2 x i32> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i32> [[V1]] to <8 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[V2]] to <8 x i8>
-// CHECK-NEXT:    [[VHSUB_V_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32>
-// CHECK-NEXT:    [[VHSUB_V1_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <2 x i32>
-// CHECK-NEXT:    [[VHSUB_V2_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.uhsub.v2i32(<2 x i32> [[VHSUB_V_I]], <2 x i32> 
[[VHSUB_V1_I]])
-// CHECK-NEXT:    [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 
x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VHSUB_V3_I]] to <2 x i32>
-// CHECK-NEXT:    ret <2 x i32> [[TMP2]]
-//
-uint32x2_t test_vhsub_u32(uint32x2_t v1, uint32x2_t v2) {
-  return vhsub_u32(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vhsubq_s8(
-// CHECK-SAME: <16 x i8> noundef [[V1:%.*]], <16 x i8> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = call <16 x i8> 
@llvm.aarch64.neon.shsub.v16i8(<16 x i8> [[V1]], <16 x i8> [[V2]])
-// CHECK-NEXT:    ret <16 x i8> [[VHSUBQ_V_I]]
-//
-int8x16_t test_vhsubq_s8(int8x16_t v1, int8x16_t v2) {
-  return vhsubq_s8(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vhsubq_s16(
-// CHECK-SAME: <8 x i16> noundef [[V1:%.*]], <8 x i16> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[V1]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[V2]] to <16 x i8>
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VHSUBQ_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VHSUBQ_V2_I:%.*]] = call <8 x i16> 
@llvm.aarch64.neon.shsub.v8i16(<8 x i16> [[VHSUBQ_V_I]], <8 x i16> 
[[VHSUBQ_V1_I]])
-// CHECK-NEXT:    [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to 
<16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[VHSUBQ_V3_I]] to <8 x i16>
-// CHECK-NEXT:    ret <8 x i16> [[TMP2]]
-//
-int16x8_t test_vhsubq_s16(int16x8_t v1, int16x8_t v2) {
-  return vhsubq_s16(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vhsubq_s32(
-// CHECK-SAME: <4 x i32> noundef [[V1:%.*]], <4 x i32> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[V1]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[V2]] to <16 x i8>
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VHSUBQ_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VHSUBQ_V2_I:%.*]] = call <4 x i32> 
@llvm.aarch64.neon.shsub.v4i32(<4 x i32> [[VHSUBQ_V_I]], <4 x i32> 
[[VHSUBQ_V1_I]])
-// CHECK-NEXT:    [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to 
<16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[VHSUBQ_V3_I]] to <4 x i32>
-// CHECK-NEXT:    ret <4 x i32> [[TMP2]]
-//
-int32x4_t test_vhsubq_s32(int32x4_t v1, int32x4_t v2) {
-  return vhsubq_s32(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vhsubq_u8(
-// CHECK-SAME: <16 x i8> noundef [[V1:%.*]], <16 x i8> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = call <16 x i8> 
@llvm.aarch64.neon.uhsub.v16i8(<16 x i8> [[V1]], <16 x i8> [[V2]])
-// CHECK-NEXT:    ret <16 x i8> [[VHSUBQ_V_I]]
-//
-uint8x16_t test_vhsubq_u8(uint8x16_t v1, uint8x16_t v2) {
-  return vhsubq_u8(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vhsubq_u16(
-// CHECK-SAME: <8 x i16> noundef [[V1:%.*]], <8 x i16> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[V1]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[V2]] to <16 x i8>
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VHSUBQ_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VHSUBQ_V2_I:%.*]] = call <8 x i16> 
@llvm.aarch64.neon.uhsub.v8i16(<8 x i16> [[VHSUBQ_V_I]], <8 x i16> 
[[VHSUBQ_V1_I]])
-// CHECK-NEXT:    [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to 
<16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[VHSUBQ_V3_I]] to <8 x i16>
-// CHECK-NEXT:    ret <8 x i16> [[TMP2]]
-//
-uint16x8_t test_vhsubq_u16(uint16x8_t v1, uint16x8_t v2) {
-  return vhsubq_u16(v1, v2);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vhsubq_u32(
-// CHECK-SAME: <4 x i32> noundef [[V1:%.*]], <4 x i32> noundef [[V2:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[V1]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[V2]] to <16 x i8>
-// CHECK-NEXT:    [[VHSUBQ_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VHSUBQ_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VHSUBQ_V2_I:%.*]] = call <4 x i32> 
@llvm.aarch64.neon.uhsub.v4i32(<4 x i32> [[VHSUBQ_V_I]], <4 x i32> 
[[VHSUBQ_V1_I]])
-// CHECK-NEXT:    [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to 
<16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[VHSUBQ_V3_I]] to <4 x i32>
-// CHECK-NEXT:    ret <4 x i32> [[TMP2]]
-//
-uint32x4_t test_vhsubq_u32(uint32x4_t v1, uint32x4_t v2) {
-  return vhsubq_u32(v1, v2);
-}
-
 // CHECK-LABEL: define dso_local <8 x i8> @test_vqadd_s8(
 // CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i8> noundef [[B:%.*]]) 
#[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -4864,394 +4696,6 @@ uint64x2_t test_vmovl_high_u32(uint32x4_t a) {
   return vmovl_high_u32(a);
 }
 
-// CHECK-LABEL: define dso_local <8 x i8> @test_vsubhn_s16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <8 x i16> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <8 x i16> [[VSUBHN_I]], splat (i16 
8)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <8 x i16> [[VSUBHN1_I]] to <8 x i8>
-// CHECK-NEXT:    ret <8 x i8> [[VSUBHN2_I]]
-//
-int8x8_t test_vsubhn_s16(int16x8_t a, int16x8_t b) {
-  return vsubhn_s16(a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vsubhn_s32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <4 x i32> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <4 x i32> [[VSUBHN_I]], splat (i32 
16)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <4 x i32> [[VSUBHN1_I]] to <4 x 
i16>
-// CHECK-NEXT:    ret <4 x i16> [[VSUBHN2_I]]
-//
-int16x4_t test_vsubhn_s32(int32x4_t a, int32x4_t b) {
-  return vsubhn_s32(a, b);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vsubhn_s64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x i64>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <2 x i64> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <2 x i64> [[VSUBHN_I]], splat (i64 
32)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <2 x i64> [[VSUBHN1_I]] to <2 x 
i32>
-// CHECK-NEXT:    ret <2 x i32> [[VSUBHN2_I]]
-//
-int32x2_t test_vsubhn_s64(int64x2_t a, int64x2_t b) {
-  return vsubhn_s64(a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i8> @test_vsubhn_u16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <8 x i16> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <8 x i16> [[VSUBHN_I]], splat (i16 
8)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <8 x i16> [[VSUBHN1_I]] to <8 x i8>
-// CHECK-NEXT:    ret <8 x i8> [[VSUBHN2_I]]
-//
-uint8x8_t test_vsubhn_u16(uint16x8_t a, uint16x8_t b) {
-  return vsubhn_u16(a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vsubhn_u32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <4 x i32> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <4 x i32> [[VSUBHN_I]], splat (i32 
16)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <4 x i32> [[VSUBHN1_I]] to <4 x 
i16>
-// CHECK-NEXT:    ret <4 x i16> [[VSUBHN2_I]]
-//
-uint16x4_t test_vsubhn_u32(uint32x4_t a, uint32x4_t b) {
-  return vsubhn_u32(a, b);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vsubhn_u64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x i64>
-// CHECK-NEXT:    [[VSUBHN_I:%.*]] = sub <2 x i64> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I:%.*]] = lshr <2 x i64> [[VSUBHN_I]], splat (i64 
32)
-// CHECK-NEXT:    [[VSUBHN2_I:%.*]] = trunc <2 x i64> [[VSUBHN1_I]] to <2 x 
i32>
-// CHECK-NEXT:    ret <2 x i32> [[VSUBHN2_I]]
-//
-uint32x2_t test_vsubhn_u64(uint64x2_t a, uint64x2_t b) {
-  return vsubhn_u64(a, b);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vsubhn_high_s16(
-// CHECK-SAME: <8 x i8> noundef [[R:%.*]], <8 x i16> noundef [[A:%.*]], <8 x 
i16> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <8 x i16> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <8 x i16> [[VSUBHN_I_I]], splat 
(i16 8)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <8 x i16> [[VSUBHN1_I_I]] to <8 
x i8>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> 
[[VSUBHN2_I_I]], <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_I]]
-//
-int8x16_t test_vsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
-  return vsubhn_high_s16(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vsubhn_high_s32(
-// CHECK-SAME: <4 x i16> noundef [[R:%.*]], <4 x i32> noundef [[A:%.*]], <4 x 
i32> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <4 x i32> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <4 x i32> [[VSUBHN_I_I]], splat 
(i32 16)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <4 x i32> [[VSUBHN1_I_I]] to <4 
x i16>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> [[R]], <4 x 
i16> [[VSUBHN2_I_I]], <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_I]]
-//
-int16x8_t test_vsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
-  return vsubhn_high_s32(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vsubhn_high_s64(
-// CHECK-SAME: <2 x i32> noundef [[R:%.*]], <2 x i64> noundef [[A:%.*]], <2 x 
i64> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x i64>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <2 x i64> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <2 x i64> [[VSUBHN_I_I]], splat 
(i64 32)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <2 x i64> [[VSUBHN1_I_I]] to <2 
x i32>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> [[R]], <2 x 
i32> [[VSUBHN2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I_I]]
-//
-int32x4_t test_vsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
-  return vsubhn_high_s64(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vsubhn_high_u16(
-// CHECK-SAME: <8 x i8> noundef [[R:%.*]], <8 x i16> noundef [[A:%.*]], <8 x 
i16> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <8 x i16> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <8 x i16> [[VSUBHN_I_I]], splat 
(i16 8)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <8 x i16> [[VSUBHN1_I_I]] to <8 
x i8>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> 
[[VSUBHN2_I_I]], <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_I]]
-//
-uint8x16_t test_vsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
-  return vsubhn_high_u16(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vsubhn_high_u32(
-// CHECK-SAME: <4 x i16> noundef [[R:%.*]], <4 x i32> noundef [[A:%.*]], <4 x 
i32> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x i32>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <4 x i32> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <4 x i32> [[VSUBHN_I_I]], splat 
(i32 16)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <4 x i32> [[VSUBHN1_I_I]] to <4 
x i16>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> [[R]], <4 x 
i16> [[VSUBHN2_I_I]], <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_I]]
-//
-uint16x8_t test_vsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
-  return vsubhn_high_u32(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vsubhn_high_u64(
-// CHECK-SAME: <2 x i32> noundef [[R:%.*]], <2 x i64> noundef [[A:%.*]], <2 x 
i64> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x i64>
-// CHECK-NEXT:    [[VSUBHN_I_I:%.*]] = sub <2 x i64> [[TMP2]], [[TMP3]]
-// CHECK-NEXT:    [[VSUBHN1_I_I:%.*]] = lshr <2 x i64> [[VSUBHN_I_I]], splat 
(i64 32)
-// CHECK-NEXT:    [[VSUBHN2_I_I:%.*]] = trunc <2 x i64> [[VSUBHN1_I_I]] to <2 
x i32>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> [[R]], <2 x 
i32> [[VSUBHN2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I_I]]
-//
-uint32x4_t test_vsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
-  return vsubhn_high_u64(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i8> @test_vrsubhn_s16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> [[VRSUBHN_V_I]], <8 x i16> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    ret <8 x i8> [[VRSUBHN_V2_I]]
-//
-int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
-  return vrsubhn_s16(a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vrsubhn_s32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> [[VRSUBHN_V_I]], <4 x i32> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to 
<8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I]] to <4 x i16>
-// CHECK-NEXT:    ret <4 x i16> [[TMP2]]
-//
-int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
-  return vrsubhn_s32(a, b);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vrsubhn_s64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> [[VRSUBHN_V_I]], <2 x i64> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to 
<8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I]] to <2 x i32>
-// CHECK-NEXT:    ret <2 x i32> [[TMP2]]
-//
-int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
-  return vrsubhn_s64(a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i8> @test_vrsubhn_u16(
-// CHECK-SAME: <8 x i16> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> [[VRSUBHN_V_I]], <8 x i16> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    ret <8 x i8> [[VRSUBHN_V2_I]]
-//
-uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
-  return vrsubhn_u16(a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i16> @test_vrsubhn_u32(
-// CHECK-SAME: <4 x i32> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> [[VRSUBHN_V_I]], <4 x i32> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to 
<8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I]] to <4 x i16>
-// CHECK-NEXT:    ret <4 x i16> [[TMP2]]
-//
-uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
-  return vrsubhn_u32(a, b);
-}
-
-// CHECK-LABEL: define dso_local <2 x i32> @test_vrsubhn_u64(
-// CHECK-SAME: <2 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) 
#[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64>
-// CHECK-NEXT:    [[VRSUBHN_V1_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V2_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> [[VRSUBHN_V_I]], <2 x i64> 
[[VRSUBHN_V1_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to 
<8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I]] to <2 x i32>
-// CHECK-NEXT:    ret <2 x i32> [[TMP2]]
-//
-uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
-  return vrsubhn_u64(a, b);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vrsubhn_high_s16(
-// CHECK-SAME: <8 x i8> noundef [[R:%.*]], <8 x i16> noundef [[A:%.*]], <8 x 
i16> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> [[VRSUBHN_V_I_I]], <8 x i16> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> 
[[VRSUBHN_V2_I_I]], <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_I]]
-//
-int8x16_t test_vrsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
-  return vrsubhn_high_s16(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vrsubhn_high_s32(
-// CHECK-SAME: <4 x i16> noundef [[R:%.*]], <4 x i32> noundef [[A:%.*]], <4 x 
i32> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> [[VRSUBHN_V_I_I]], <4 x i32> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I_I:%.*]] = bitcast <4 x i16> 
[[VRSUBHN_V2_I_I]] to <8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I_I]] to <4 x 
i16>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> [[R]], <4 x 
i16> [[TMP2]], <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_I]]
-//
-int16x8_t test_vrsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
-  return vrsubhn_high_s32(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vrsubhn_high_s64(
-// CHECK-SAME: <2 x i32> noundef [[R:%.*]], <2 x i64> noundef [[A:%.*]], <2 x 
i64> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> [[VRSUBHN_V_I_I]], <2 x i64> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I_I:%.*]] = bitcast <2 x i32> 
[[VRSUBHN_V2_I_I]] to <8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I_I]] to <2 x 
i32>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> [[R]], <2 x 
i32> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I_I]]
-//
-int32x4_t test_vrsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
-  return vrsubhn_high_s64(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <16 x i8> @test_vrsubhn_high_u16(
-// CHECK-SAME: <8 x i8> noundef [[R:%.*]], <8 x i16> noundef [[A:%.*]], <8 x 
i16> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x 
i16>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> 
@llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> [[VRSUBHN_V_I_I]], <8 x i16> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> 
[[VRSUBHN_V2_I_I]], <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_I]]
-//
-uint8x16_t test_vrsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
-  return vrsubhn_high_u16(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <8 x i16> @test_vrsubhn_high_u32(
-// CHECK-SAME: <4 x i16> noundef [[R:%.*]], <4 x i32> noundef [[A:%.*]], <4 x 
i32> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <4 x 
i32>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> 
@llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> [[VRSUBHN_V_I_I]], <4 x i32> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I_I:%.*]] = bitcast <4 x i16> 
[[VRSUBHN_V2_I_I]] to <8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I_I]] to <4 x 
i16>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> [[R]], <4 x 
i16> [[TMP2]], <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_I]]
-//
-uint16x8_t test_vrsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
-  return vrsubhn_high_u32(r, a, b);
-}
-
-// CHECK-LABEL: define dso_local <4 x i32> @test_vrsubhn_high_u64(
-// CHECK-SAME: <2 x i32> noundef [[R:%.*]], <2 x i64> noundef [[A:%.*]], <2 x 
i64> noundef [[B:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8>
-// CHECK-NEXT:    [[VRSUBHN_V_I_I:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V1_I_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x 
i64>
-// CHECK-NEXT:    [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> 
@llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> [[VRSUBHN_V_I_I]], <2 x i64> 
[[VRSUBHN_V1_I_I]])
-// CHECK-NEXT:    [[VRSUBHN_V3_I_I:%.*]] = bitcast <2 x i32> 
[[VRSUBHN_V2_I_I]] to <8 x i8>
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[VRSUBHN_V3_I_I]] to <2 x 
i32>
-// CHECK-NEXT:    [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> [[R]], <2 x 
i32> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
-// CHECK-NEXT:    ret <4 x i32> [[SHUFFLE_I_I]]
-//
-uint32x4_t test_vrsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
-  return vrsubhn_high_u64(r, a, b);
-}
-
 // CHECK-LABEL: define dso_local <8 x i16> @test_vabdl_s8(
 // CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i8> noundef [[B:%.*]]) 
#[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon/subtraction.c 
b/clang/test/CodeGen/AArch64/neon/subtraction.c
index d23f5907f0362..91f3d7158fa4f 100644
--- a/clang/test/CodeGen/AArch64/neon/subtraction.c
+++ b/clang/test/CodeGen/AArch64/neon/subtraction.c
@@ -3,6 +3,9 @@
 // RUN:                   %clang_cc1_cg_arm64_neon           -emit-llvm %s 
-disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s 
--check-prefixes=LLVM
 // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s 
-disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s 
--check-prefixes=LLVM %}
 // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-cir  %s 
-disable-O0-optnone |                               FileCheck %s 
--check-prefixes=CIR %}
+// Narrowing-subtraction checks use instcombine to fold no-op bitcasts 
(LLVM-IC prefix).
+// RUN:                   %clang_cc1_cg_arm64_neon           -emit-llvm %s 
-disable-O0-optnone | opt -S -passes=mem2reg,sroa,instcombine | FileCheck %s 
--check-prefixes=LLVM-IC
+// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s 
-disable-O0-optnone | opt -S -passes=mem2reg,sroa,instcombine | FileCheck %s 
--check-prefixes=LLVM-IC %}
 
 //=============================================================================
 // NOTES
@@ -12,7 +15,7 @@
 // ACLE section headings based on v2025Q2 of the ACLE specification:
 //  * https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#subtract
 //
-// TODO: Migrate Narrowing subtraction and Saturating subtract test cases.
+// TODO: Migrate Saturating subtract test cases.
 //
 //=============================================================================
 
@@ -671,3 +674,464 @@ uint64x2_t test_vsubw_high_u32(uint64x2_t a, uint32x4_t 
b) {
 // LLVM: ret <2 x i64> [[SUB_I]]
   return vsubw_high_u32(a, b);
 }
+
+//===----------------------------------------------------------------------===//
+// 2.1.1.5.3. Narrowing subtraction
+// 
https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#narrowing-subtraction
+//===----------------------------------------------------------------------===//
+
+// LLVM-IC-LABEL: @test_vhsub_s8(
+// CIR-LABEL: @vhsub_s8(
+int8x8_t test_vhsub_s8(int8x8_t v1, int8x8_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[V1:%.*]], <8 x i8> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i8> @llvm.aarch64.neon.shsub.v8i8(<8 x 
i8> [[V1]], <8 x i8> [[V2]])
+  // LLVM-IC: ret <8 x i8> [[RES]]
+  return vhsub_s8(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsub_s16(
+// CIR-LABEL: @vhsub_s16(
+int16x4_t test_vhsub_s16(int16x4_t v1, int16x4_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[V1:%.*]], <4 x i16> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i16> @llvm.aarch64.neon.shsub.v4i16(<4 x 
i16> [[V1]], <4 x i16> [[V2]])
+  // LLVM-IC: ret <4 x i16> [[RES]]
+  return vhsub_s16(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsub_s32(
+// CIR-LABEL: @vhsub_s32(
+int32x2_t test_vhsub_s32(int32x2_t v1, int32x2_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[V1:%.*]], <2 x i32> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <2 x i32> @llvm.aarch64.neon.shsub.v2i32(<2 x 
i32> [[V1]], <2 x i32> [[V2]])
+  // LLVM-IC: ret <2 x i32> [[RES]]
+  return vhsub_s32(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsub_u8(
+// CIR-LABEL: @vhsub_u8(
+uint8x8_t test_vhsub_u8(uint8x8_t v1, uint8x8_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[V1:%.*]], <8 x i8> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i8> @llvm.aarch64.neon.uhsub.v8i8(<8 x 
i8> [[V1]], <8 x i8> [[V2]])
+  // LLVM-IC: ret <8 x i8> [[RES]]
+  return vhsub_u8(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsub_u16(
+// CIR-LABEL: @vhsub_u16(
+uint16x4_t test_vhsub_u16(uint16x4_t v1, uint16x4_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[V1:%.*]], <4 x i16> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i16> @llvm.aarch64.neon.uhsub.v4i16(<4 x 
i16> [[V1]], <4 x i16> [[V2]])
+  // LLVM-IC: ret <4 x i16> [[RES]]
+  return vhsub_u16(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsub_u32(
+// CIR-LABEL: @vhsub_u32(
+uint32x2_t test_vhsub_u32(uint32x2_t v1, uint32x2_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[V1:%.*]], <2 x i32> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <2 x i32> @llvm.aarch64.neon.uhsub.v2i32(<2 x 
i32> [[V1]], <2 x i32> [[V2]])
+  // LLVM-IC: ret <2 x i32> [[RES]]
+  return vhsub_u32(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_s8(
+// CIR-LABEL: @vhsubq_s8(
+int8x16_t test_vhsubq_s8(int8x16_t v1, int8x16_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <16 x i8> {{.*}}[[V1:%.*]], <16 x i8> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <16 x i8> @llvm.aarch64.neon.shsub.v16i8(<16 
x i8> [[V1]], <16 x i8> [[V2]])
+  // LLVM-IC: ret <16 x i8> [[RES]]
+  return vhsubq_s8(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_s16(
+// CIR-LABEL: @vhsubq_s16(
+int16x8_t test_vhsubq_s16(int16x8_t v1, int16x8_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[V1:%.*]], <8 x i16> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i16> @llvm.aarch64.neon.shsub.v8i16(<8 x 
i16> [[V1]], <8 x i16> [[V2]])
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vhsubq_s16(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_s32(
+// CIR-LABEL: @vhsubq_s32(
+int32x4_t test_vhsubq_s32(int32x4_t v1, int32x4_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.shsub"
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[V1:%.*]], <4 x i32> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i32> @llvm.aarch64.neon.shsub.v4i32(<4 x 
i32> [[V1]], <4 x i32> [[V2]])
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vhsubq_s32(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_u8(
+// CIR-LABEL: @vhsubq_u8(
+uint8x16_t test_vhsubq_u8(uint8x16_t v1, uint8x16_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <16 x i8> {{.*}}[[V1:%.*]], <16 x i8> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <16 x i8> @llvm.aarch64.neon.uhsub.v16i8(<16 
x i8> [[V1]], <16 x i8> [[V2]])
+  // LLVM-IC: ret <16 x i8> [[RES]]
+  return vhsubq_u8(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_u16(
+// CIR-LABEL: @vhsubq_u16(
+uint16x8_t test_vhsubq_u16(uint16x8_t v1, uint16x8_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[V1:%.*]], <8 x i16> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i16> @llvm.aarch64.neon.uhsub.v8i16(<8 x 
i16> [[V1]], <8 x i16> [[V2]])
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vhsubq_u16(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vhsubq_u32(
+// CIR-LABEL: @vhsubq_u32(
+uint32x4_t test_vhsubq_u32(uint32x4_t v1, uint32x4_t v2) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.uhsub"
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[V1:%.*]], <4 x i32> {{.*}}[[V2:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i32> @llvm.aarch64.neon.uhsub.v4i32(<4 x 
i32> [[V1]], <4 x i32> [[V2]])
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vhsubq_u32(v1, v2);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_s16(
+// CIR-LABEL: @vsubhn_s16(
+int8x8_t test_vsubhn_s16(int16x8_t a, int16x8_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[A:%.*]], <8 x i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <8 x i16> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <8 x i16> [[SUB]], splat (i16 8)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <8 x i16> [[SH]] to <8 x i8>
+  // LLVM-IC: ret <8 x i8> [[TR]]
+  return vsubhn_s16(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_s32(
+// CIR-LABEL: @vsubhn_s32(
+int16x4_t test_vsubhn_s32(int32x4_t a, int32x4_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[A:%.*]], <4 x i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <4 x i32> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <4 x i32> [[SUB]], splat (i32 16)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <4 x i32> [[SH]] to <4 x i16>
+  // LLVM-IC: ret <4 x i16> [[TR]]
+  return vsubhn_s32(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_s64(
+// CIR-LABEL: @vsubhn_s64(
+int32x2_t test_vsubhn_s64(int64x2_t a, int64x2_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <2 x i64> {{.*}}[[A:%.*]], <2 x i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <2 x i64> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <2 x i64> [[SUB]], splat (i64 32)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <2 x i64> [[SH]] to <2 x i32>
+  // LLVM-IC: ret <2 x i32> [[TR]]
+  return vsubhn_s64(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_u16(
+// CIR-LABEL: @vsubhn_u16(
+uint8x8_t test_vsubhn_u16(uint16x8_t a, uint16x8_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[A:%.*]], <8 x i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <8 x i16> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <8 x i16> [[SUB]], splat (i16 8)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <8 x i16> [[SH]] to <8 x i8>
+  // LLVM-IC: ret <8 x i8> [[TR]]
+  return vsubhn_u16(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_u32(
+// CIR-LABEL: @vsubhn_u32(
+uint16x4_t test_vsubhn_u32(uint32x4_t a, uint32x4_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[A:%.*]], <4 x i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <4 x i32> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <4 x i32> [[SUB]], splat (i32 16)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <4 x i32> [[SH]] to <4 x i16>
+  // LLVM-IC: ret <4 x i16> [[TR]]
+  return vsubhn_u32(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_u64(
+// CIR-LABEL: @vsubhn_u64(
+uint32x2_t test_vsubhn_u64(uint64x2_t a, uint64x2_t b) {
+  // CIR: cir.sub
+  // CIR: cir.shift(right
+  // CIR: cir.cast integral
+
+  // LLVM-IC-SAME: <2 x i64> {{.*}}[[A:%.*]], <2 x i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <2 x i64> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <2 x i64> [[SUB]], splat (i64 32)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <2 x i64> [[SH]] to <2 x i32>
+  // LLVM-IC: ret <2 x i32> [[TR]]
+  return vsubhn_u64(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_s16(
+// CIR-LABEL: @vsubhn_high_s16(
+int8x16_t test_vsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+  // CIR: cir.call @vsubhn_s16(
+  // CIR: cir.call @vcombine_s8(
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[R:%.*]], <8 x i16> {{.*}}[[A:%.*]], <8 x 
i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <8 x i16> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <8 x i16> [[SUB]], splat (i16 8)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <8 x i16> [[SH]] to <8 x i8>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> [[TR]], <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-IC: ret <16 x i8> [[RES]]
+  return vsubhn_high_s16(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_s32(
+// CIR-LABEL: @vsubhn_high_s32(
+int16x8_t test_vsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+  // CIR: cir.call @vsubhn_s32(
+  // CIR: cir.call @vcombine_s16(
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[R:%.*]], <4 x i32> {{.*}}[[A:%.*]], <4 x 
i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <4 x i32> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <4 x i32> [[SUB]], splat (i32 16)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <4 x i32> [[SH]] to <4 x i16>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <4 x i16> [[R]], <4 x i16> [[TR]], 
<8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vsubhn_high_s32(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_s64(
+// CIR-LABEL: @vsubhn_high_s64(
+int32x4_t test_vsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+  // CIR: cir.call @vsubhn_s64(
+  // CIR: cir.call @vcombine_s32(
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[R:%.*]], <2 x i64> {{.*}}[[A:%.*]], <2 x 
i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <2 x i64> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <2 x i64> [[SUB]], splat (i64 32)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <2 x i64> [[SH]] to <2 x i32>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <2 x i32> [[R]], <2 x i32> [[TR]], 
<4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vsubhn_high_s64(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_u16(
+// CIR-LABEL: @vsubhn_high_u16(
+uint8x16_t test_vsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+  // CIR: cir.call @vsubhn_u16(
+  // CIR: cir.call @vcombine_u8(
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[R:%.*]], <8 x i16> {{.*}}[[A:%.*]], <8 x 
i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <8 x i16> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <8 x i16> [[SUB]], splat (i16 8)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <8 x i16> [[SH]] to <8 x i8>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> [[TR]], <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-IC: ret <16 x i8> [[RES]]
+  return vsubhn_high_u16(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_u32(
+// CIR-LABEL: @vsubhn_high_u32(
+uint16x8_t test_vsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+  // CIR: cir.call @vsubhn_u32(
+  // CIR: cir.call @vcombine_u16(
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[R:%.*]], <4 x i32> {{.*}}[[A:%.*]], <4 x 
i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <4 x i32> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <4 x i32> [[SUB]], splat (i32 16)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <4 x i32> [[SH]] to <4 x i16>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <4 x i16> [[R]], <4 x i16> [[TR]], 
<8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vsubhn_high_u32(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vsubhn_high_u64(
+// CIR-LABEL: @vsubhn_high_u64(
+uint32x4_t test_vsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+  // CIR: cir.call @vsubhn_u64(
+  // CIR: cir.call @vcombine_u32(
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[R:%.*]], <2 x i64> {{.*}}[[A:%.*]], <2 x 
i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[SUB:%.*]] = sub <2 x i64> [[A]], [[B]]
+  // LLVM-IC: [[SH:%.*]] = lshr <2 x i64> [[SUB]], splat (i64 32)
+  // LLVM-IC: [[TR:%.*]] = trunc nuw <2 x i64> [[SH]] to <2 x i32>
+  // LLVM-IC: [[RES:%.*]] = shufflevector <2 x i32> [[R]], <2 x i32> [[TR]], 
<4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vsubhn_high_u64(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_s16(
+// CIR-LABEL: @vrsubhn_s16(
+int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[A:%.*]], <8 x i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x 
i16> [[A]], <8 x i16> [[B]])
+  // LLVM-IC: ret <8 x i8> [[RES]]
+  return vrsubhn_s16(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_s32(
+// CIR-LABEL: @vrsubhn_s32(
+int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[A:%.*]], <4 x i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 
x i32> [[A]], <4 x i32> [[B]])
+  // LLVM-IC: ret <4 x i16> [[RES]]
+  return vrsubhn_s32(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_s64(
+// CIR-LABEL: @vrsubhn_s64(
+int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <2 x i64> {{.*}}[[A:%.*]], <2 x i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 
x i64> [[A]], <2 x i64> [[B]])
+  // LLVM-IC: ret <2 x i32> [[RES]]
+  return vrsubhn_s64(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_u16(
+// CIR-LABEL: @vrsubhn_u16(
+uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <8 x i16> {{.*}}[[A:%.*]], <8 x i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x 
i16> [[A]], <8 x i16> [[B]])
+  // LLVM-IC: ret <8 x i8> [[RES]]
+  return vrsubhn_u16(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_u32(
+// CIR-LABEL: @vrsubhn_u32(
+uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <4 x i32> {{.*}}[[A:%.*]], <4 x i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 
x i32> [[A]], <4 x i32> [[B]])
+  // LLVM-IC: ret <4 x i16> [[RES]]
+  return vrsubhn_u32(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_u64(
+// CIR-LABEL: @vrsubhn_u64(
+uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
+  // CIR: cir.call_llvm_intrinsic "aarch64.neon.rsubhn"
+
+  // LLVM-IC-SAME: <2 x i64> {{.*}}[[A:%.*]], <2 x i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[RES:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 
x i64> [[A]], <2 x i64> [[B]])
+  // LLVM-IC: ret <2 x i32> [[RES]]
+  return vrsubhn_u64(a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_s16(
+// CIR-LABEL: @vrsubhn_high_s16(
+int8x16_t test_vrsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+  // CIR: cir.call @vrsubhn_s16(
+  // CIR: cir.call @vcombine_s8(
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[R:%.*]], <8 x i16> {{.*}}[[A:%.*]], <8 x 
i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x 
i16> [[A]], <8 x i16> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> [[TMP]], 
<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-IC: ret <16 x i8> [[RES]]
+  return vrsubhn_high_s16(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_s32(
+// CIR-LABEL: @vrsubhn_high_s32(
+int16x8_t test_vrsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+  // CIR: cir.call @vrsubhn_s32(
+  // CIR: cir.call @vcombine_s16(
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[R:%.*]], <4 x i32> {{.*}}[[A:%.*]], <4 x 
i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 
x i32> [[A]], <4 x i32> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <4 x i16> [[R]], <4 x i16> [[TMP]], 
<8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vrsubhn_high_s32(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_s64(
+// CIR-LABEL: @vrsubhn_high_s64(
+int32x4_t test_vrsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+  // CIR: cir.call @vrsubhn_s64(
+  // CIR: cir.call @vcombine_s32(
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[R:%.*]], <2 x i64> {{.*}}[[A:%.*]], <2 x 
i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 
x i64> [[A]], <2 x i64> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <2 x i32> [[R]], <2 x i32> [[TMP]], 
<4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vrsubhn_high_s64(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_u16(
+// CIR-LABEL: @vrsubhn_high_u16(
+uint8x16_t test_vrsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+  // CIR: cir.call @vrsubhn_u16(
+  // CIR: cir.call @vcombine_u8(
+
+  // LLVM-IC-SAME: <8 x i8> {{.*}}[[R:%.*]], <8 x i16> {{.*}}[[A:%.*]], <8 x 
i16> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x 
i16> [[A]], <8 x i16> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <8 x i8> [[R]], <8 x i8> [[TMP]], 
<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-IC: ret <16 x i8> [[RES]]
+  return vrsubhn_high_u16(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_u32(
+// CIR-LABEL: @vrsubhn_high_u32(
+uint16x8_t test_vrsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+  // CIR: cir.call @vrsubhn_u32(
+  // CIR: cir.call @vcombine_u16(
+
+  // LLVM-IC-SAME: <4 x i16> {{.*}}[[R:%.*]], <4 x i32> {{.*}}[[A:%.*]], <4 x 
i32> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 
x i32> [[A]], <4 x i32> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <4 x i16> [[R]], <4 x i16> [[TMP]], 
<8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  // LLVM-IC: ret <8 x i16> [[RES]]
+  return vrsubhn_high_u32(r, a, b);
+}
+
+// LLVM-IC-LABEL: @test_vrsubhn_high_u64(
+// CIR-LABEL: @vrsubhn_high_u64(
+uint32x4_t test_vrsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+  // CIR: cir.call @vrsubhn_u64(
+  // CIR: cir.call @vcombine_u32(
+
+  // LLVM-IC-SAME: <2 x i32> {{.*}}[[R:%.*]], <2 x i64> {{.*}}[[A:%.*]], <2 x 
i64> {{.*}}[[B:%.*]])
+  // LLVM-IC: [[TMP:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 
x i64> [[A]], <2 x i64> [[B]])
+  // LLVM-IC: [[RES:%.*]] = shufflevector <2 x i32> [[R]], <2 x i32> [[TMP]], 
<4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  // LLVM-IC: ret <4 x i32> [[RES]]
+  return vrsubhn_high_u64(r, a, b);
+}

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

Reply via email to