https://github.com/E00N777 created https://github.com/llvm/llvm-project/pull/209389
### summary part of : https://github.com/llvm/llvm-project/issues/185382 lower all intrinsics in : https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#vector-saturating-shift-right-and-narrow >From b2bfca73f1f36e1b141b61af982d68ce35ea2507 Mon Sep 17 00:00:00 2001 From: E00N777 <[email protected]> Date: Tue, 14 Jul 2026 11:18:07 +0800 Subject: [PATCH] [CIR][AArch64] Lower Vector saturating shift and narrow intrinsics --- .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 77 +++- clang/test/CodeGen/AArch64/neon-intrinsics.c | 403 ---------------- clang/test/CodeGen/AArch64/neon/intrinsics.c | 430 +++++++++++++++++- 3 files changed, 500 insertions(+), 410 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp index e2ad897b5ba90..8833fbf4dfa65 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -330,6 +330,30 @@ static cir::VectorType deriveNeonBinaryArgType(CIRGenBuilderTy &builder, return vTy; } +/// Vectorize value, usually for argument of a neon SISD intrinsic call. +static void vecExtendIntValue(CIRGenFunction &cgf, cir::VectorType argVTy, + mlir::Value &arg, mlir::Location loc) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + cir::IntType eltTy = mlir::dyn_cast<cir::IntType>(argVTy.getElementType()); + assert(mlir::isa<cir::IntType>(arg.getType()) && eltTy); + // Cast the scalar data operand to the vector element type before inserting + // it into lane 0. + arg = builder.createIntCast(arg, eltTy); + mlir::Value zero = builder.getConstInt(loc, cgf.sizeTy, 0); + mlir::Value poison = builder.getConstant(loc, cir::PoisonAttr::get(argVTy)); + arg = cir::VecInsertOp::create(builder, loc, poison, arg, zero); +} + +/// Reduce vector type value to scalar, usually for result of a +/// neon SISD intrinsic call +static mlir::Value vecReduceIntValue(CIRGenFunction &cgf, mlir::Value val, + mlir::Location loc) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + assert(mlir::isa<cir::VectorType>(val.getType())); + return cir::VecExtractOp::create(builder, loc, val, + builder.getConstInt(loc, cgf.sizeTy, 0)); +} + static mlir::Value emitCommonNeonSISDBuiltinExpr( CIRGenFunction &cgf, const ARMNeonVectorIntrinsicInfo &info, llvm::SmallVectorImpl<mlir::Value> &ops, const CallExpr *expr) { @@ -445,6 +469,9 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr( case NEON::BI__builtin_neon_vqrshrund_n_s64: case NEON::BI__builtin_neon_vqrshrnd_n_s64: case NEON::BI__builtin_neon_vqrshrnd_n_u64: + case NEON::BI__builtin_neon_vqshrund_n_s64: + case NEON::BI__builtin_neon_vqshrnd_n_s64: + case NEON::BI__builtin_neon_vqshrnd_n_u64: case NEON::BI__builtin_neon_vmaxnmv_f32: case NEON::BI__builtin_neon_vmaxnmvq_f32: case NEON::BI__builtin_neon_vmaxnmvq_f64: @@ -457,6 +484,36 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr( case NEON::BI__builtin_neon_vpmaxnms_f32: case NEON::BI__builtin_neon_vpmaxnmqd_f64: break; + case NEON::BI__builtin_neon_vqshrunh_n_s16: + case NEON::BI__builtin_neon_vqshruns_n_s32: + case NEON::BI__builtin_neon_vqshrnh_n_s16: + case NEON::BI__builtin_neon_vqshrns_n_s32: + case NEON::BI__builtin_neon_vqshrnh_n_u16: + case NEON::BI__builtin_neon_vqshrns_n_u32: + case NEON::BI__builtin_neon_vqrshrnh_n_s16: + case NEON::BI__builtin_neon_vqrshrns_n_s32: + case NEON::BI__builtin_neon_vqrshrnh_n_u16: + case NEON::BI__builtin_neon_vqrshrns_n_u32: + case NEON::BI__builtin_neon_vqrshrunh_n_s16: + case NEON::BI__builtin_neon_vqrshruns_n_s32: { + // The 8/16-bit scalar narrowing shifts have no scalar LLVM intrinsic + // form: vectorize the operand into lane 0, call the 64-bit-vector form + // of the intrinsic and extract lane 0 of the result. + CIRGenBuilderTy &builder = cgf.getBuilder(); + cir::IntType resEltTy = + mlir::cast<cir::IntType>(cgf.convertType(expr->getType())); + cir::VectorType resVecTy = + cir::VectorType::get(resEltTy, 64 / resEltTy.getWidth()); + // The intrinsic's source operand has double-width elements + // (LLVMExtendedType<0>), which is exactly the scalar operand's type. + cir::VectorType argVecTy = cir::VectorType::get( + cgf.convertType(expr->getArg(0)->getType()), resVecTy.getSize()); + vecExtendIntValue(cgf, argVecTy, ops[0], loc); + mlir::Value result = + emitNeonCall(cgf.cgm, builder, {argVecTy, cgf.sInt32Ty}, ops, + llvmIntrName, resVecTy, loc); + return vecReduceIntValue(cgf, result, loc); + } } CIRGenBuilderTy &builder = cgf.getBuilder(); @@ -2930,22 +2987,30 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, case NEON::BI__builtin_neon_vrecpss_f32: case NEON::BI__builtin_neon_vrecpsd_f64: case NEON::BI__builtin_neon_vrecpsh_f16: - case NEON::BI__builtin_neon_vqshrun_n_v: cgm.errorNYI(expr->getSourceRange(), std::string("unimplemented AArch64 builtin call: ") + getContext().BuiltinInfo.getName(builtinID)); return mlir::Value{}; + case NEON::BI__builtin_neon_vqshrun_n_v: { + cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType( + ty, /*isExtended=*/true, /*isSigned=*/true); + return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, + "aarch64.neon.sqshrun", ty, loc); + } case NEON::BI__builtin_neon_vqrshrun_n_v: { cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType( ty, /*isExtended=*/true, /*isSigned=*/true); return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, "aarch64.neon.sqrshrun", ty, loc); } - case NEON::BI__builtin_neon_vqshrn_n_v: - cgm.errorNYI(expr->getSourceRange(), - std::string("unimplemented AArch64 builtin call: ") + - getContext().BuiltinInfo.getName(builtinID)); - return mlir::Value{}; + case NEON::BI__builtin_neon_vqshrn_n_v: { + cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType( + ty, /*isExtended=*/true, /*isSigned=*/!usgn); + llvm::StringRef intrName = + usgn ? "aarch64.neon.uqshrn" : "aarch64.neon.sqshrn"; + return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty, + loc); + } case NEON::BI__builtin_neon_vrshrn_n_v: cgm.errorNYI(expr->getSourceRange(), std::string("unimplemented AArch64 builtin call: ") + diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c index 8e03ea78e2fd1..0608d68e5b6fd 100644 --- a/clang/test/CodeGen/AArch64/neon-intrinsics.c +++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c @@ -4246,81 +4246,6 @@ uint32x4_t test_vshrn_high_n_u64(uint32x2_t a, uint64x2_t b) { return vshrn_high_n_u64(a, b, 19); } -// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrun_n_s16( -// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRUN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3) -// CHECK-NEXT: ret <8 x i8> [[VQSHRUN_N1]] -// -uint8x8_t test_vqshrun_n_s16(int16x8_t a) { - return vqshrun_n_s16(a, 3); -} - -// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrun_n_s32( -// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRUN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9) -// CHECK-NEXT: ret <4 x i16> [[VQSHRUN_N1]] -// -uint16x4_t test_vqshrun_n_s32(int32x4_t a) { - return vqshrun_n_s32(a, 9); -} - -// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrun_n_s64( -// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRUN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19) -// CHECK-NEXT: ret <2 x i32> [[VQSHRUN_N1]] -// -uint32x2_t test_vqshrun_n_s64(int64x2_t a) { - return vqshrun_n_s64(a, 19); -} - -// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrun_high_n_s16( -// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRUN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> -// CHECK-NEXT: ret <16 x i8> [[SHUFFLE_I]] -// -uint8x16_t test_vqshrun_high_n_s16(uint8x8_t a, int16x8_t b) { - return vqshrun_high_n_s16(a, b, 3); -} - -// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrun_high_n_s32( -// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRUN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> -// CHECK-NEXT: ret <8 x i16> [[SHUFFLE_I]] -// -uint16x8_t test_vqshrun_high_n_s32(uint16x4_t a, int32x4_t b) { - return vqshrun_high_n_s32(a, b, 9); -} - -// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrun_high_n_s64( -// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRUN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> -// CHECK-NEXT: ret <4 x i32> [[SHUFFLE_I]] -// -uint32x4_t test_vqshrun_high_n_s64(uint32x2_t a, int64x2_t b) { - return vqshrun_high_n_s64(a, b, 19); -} - // CHECK-LABEL: define dso_local <8 x i8> @test_vrshrn_n_s16( // CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -4471,157 +4396,6 @@ uint32x4_t test_vrshrn_high_n_u64(uint32x2_t a, uint64x2_t b) { return vrshrn_high_n_u64(a, b, 19); } -// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrn_n_s16( -// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) -// CHECK-NEXT: ret <8 x i8> [[VQSHRN_N1]] -// -int8x8_t test_vqshrn_n_s16(int16x8_t a) { - return vqshrn_n_s16(a, 3); -} - -// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrn_n_s32( -// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) -// CHECK-NEXT: ret <4 x i16> [[VQSHRN_N1]] -// -int16x4_t test_vqshrn_n_s32(int32x4_t a) { - return vqshrn_n_s32(a, 9); -} - -// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrn_n_s64( -// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) -// CHECK-NEXT: ret <2 x i32> [[VQSHRN_N1]] -// -int32x2_t test_vqshrn_n_s64(int64x2_t a) { - return vqshrn_n_s64(a, 19); -} - -// CHECK-LABEL: define dso_local <8 x i8> @test_vqshrn_n_u16( -// CHECK-SAME: <8 x i16> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) -// CHECK-NEXT: ret <8 x i8> [[VQSHRN_N1]] -// -uint8x8_t test_vqshrn_n_u16(uint16x8_t a) { - return vqshrn_n_u16(a, 3); -} - -// CHECK-LABEL: define dso_local <4 x i16> @test_vqshrn_n_u32( -// CHECK-SAME: <4 x i32> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) -// CHECK-NEXT: ret <4 x i16> [[VQSHRN_N1]] -// -uint16x4_t test_vqshrn_n_u32(uint32x4_t a) { - return vqshrn_n_u32(a, 9); -} - -// CHECK-LABEL: define dso_local <2 x i32> @test_vqshrn_n_u64( -// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) -// CHECK-NEXT: ret <2 x i32> [[VQSHRN_N1]] -// -uint32x2_t test_vqshrn_n_u64(uint64x2_t a) { - return vqshrn_n_u64(a, 19); -} - -// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrn_high_n_s16( -// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> -// CHECK-NEXT: ret <16 x i8> [[SHUFFLE_I]] -// -int8x16_t test_vqshrn_high_n_s16(int8x8_t a, int16x8_t b) { - return vqshrn_high_n_s16(a, b, 3); -} - -// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrn_high_n_s32( -// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> -// CHECK-NEXT: ret <8 x i16> [[SHUFFLE_I]] -// -int16x8_t test_vqshrn_high_n_s32(int16x4_t a, int32x4_t b) { - return vqshrn_high_n_s32(a, b, 9); -} - -// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrn_high_n_s64( -// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> -// CHECK-NEXT: ret <4 x i32> [[SHUFFLE_I]] -// -int32x4_t test_vqshrn_high_n_s64(int32x2_t a, int64x2_t b) { - return vqshrn_high_n_s64(a, b, 19); -} - -// CHECK-LABEL: define dso_local <16 x i8> @test_vqshrn_high_n_u16( -// CHECK-SAME: <8 x i8> noundef [[A:%.*]], <8 x i16> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> -// CHECK-NEXT: ret <16 x i8> [[SHUFFLE_I]] -// -uint8x16_t test_vqshrn_high_n_u16(uint8x8_t a, uint16x8_t b) { - return vqshrn_high_n_u16(a, b, 3); -} - -// CHECK-LABEL: define dso_local <8 x i16> @test_vqshrn_high_n_u32( -// CHECK-SAME: <4 x i16> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> -// CHECK-NEXT: ret <8 x i16> [[SHUFFLE_I]] -// -uint16x8_t test_vqshrn_high_n_u32(uint16x4_t a, uint32x4_t b) { - return vqshrn_high_n_u32(a, b, 9); -} - -// CHECK-LABEL: define dso_local <4 x i32> @test_vqshrn_high_n_u64( -// CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> -// CHECK-NEXT: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> -// CHECK-NEXT: [[VQSHRN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) -// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> -// CHECK-NEXT: ret <4 x i32> [[SHUFFLE_I]] -// -uint32x4_t test_vqshrn_high_n_u64(uint32x2_t a, uint64x2_t b) { - return vqshrn_high_n_u64(a, b, 19); -} - - // CHECK-LABEL: define dso_local <8 x i16> @test_vmovl_high_s8( // CHECK-SAME: <16 x i8> noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -10070,7 +9844,6 @@ float64x1x3_t test_vld1_f64_x3(float64_t const *a) { return vld1_f64_x3(a); } - // CHECK-LABEL: define dso_local %struct.mfloat8x8x3_t @test_vld1_mf8_x3( // CHECK-SAME: ptr noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -11663,180 +11436,6 @@ uint64x1_t test_vqshlu_n_s64(int64x1_t a) { return vqshlu_n_s64(a, 1); } -// CHECK-LABEL: define dso_local i8 @test_vqshrnh_n_s16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_S16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -int8_t test_vqshrnh_n_s16(int16_t a) { - return (int8_t)vqshrnh_n_s16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqshrns_n_s32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_S32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -int16_t test_vqshrns_n_s32(int32_t a) { - return (int16_t)vqshrns_n_s32(a, 16); -} - -// CHECK-LABEL: define dso_local i32 @test_vqshrnd_n_s64( -// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[VQSHRND_N_S64:%.*]] = call i32 @llvm.aarch64.neon.sqshrn.i32(i64 [[A]], i32 32) -// CHECK-NEXT: ret i32 [[VQSHRND_N_S64]] -// -int32_t test_vqshrnd_n_s64(int64_t a) { - return (int32_t)vqshrnd_n_s64(a, 32); -} - -// CHECK-LABEL: define dso_local i8 @test_vqshrnh_n_u16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRNH_N_U16:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_U16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -uint8_t test_vqshrnh_n_u16(uint16_t a) { - return (uint8_t)vqshrnh_n_u16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqshrns_n_u32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRNS_N_U32:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_U32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -uint16_t test_vqshrns_n_u32(uint32_t a) { - return (uint16_t)vqshrns_n_u32(a, 16); -} - -// CHECK-LABEL: define dso_local i32 @test_vqshrnd_n_u64( -// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[VQSHRND_N_U64:%.*]] = call i32 @llvm.aarch64.neon.uqshrn.i32(i64 [[A]], i32 32) -// CHECK-NEXT: ret i32 [[VQSHRND_N_U64]] -// -uint32_t test_vqshrnd_n_u64(uint64_t a) { - return (uint32_t)vqshrnd_n_u64(a, 32); -} - -// CHECK-LABEL: define dso_local i8 @test_vqrshrnh_n_s16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshrn.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRNH_N_S16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -int8_t test_vqrshrnh_n_s16(int16_t a) { - return (int8_t)vqrshrnh_n_s16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqrshrns_n_s32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshrn.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRNS_N_S32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -int16_t test_vqrshrns_n_s32(int32_t a) { - return (int16_t)vqrshrns_n_s32(a, 16); -} - -// CHECK-LABEL: define dso_local i8 @test_vqrshrnh_n_u16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRNH_N_U16:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshrn.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRNH_N_U16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -uint8_t test_vqrshrnh_n_u16(uint16_t a) { - return (uint8_t)vqrshrnh_n_u16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqrshrns_n_u32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRNS_N_U32:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshrn.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRNS_N_U32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -uint16_t test_vqrshrns_n_u32(uint32_t a) { - return (uint16_t)vqrshrns_n_u32(a, 16); -} - -// CHECK-LABEL: define dso_local i8 @test_vqshrunh_n_s16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRUNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRUNH_N_S16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -int8_t test_vqshrunh_n_s16(int16_t a) { - return (int8_t)vqshrunh_n_s16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqshruns_n_s32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQSHRUNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRUNS_N_S32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -int16_t test_vqshruns_n_s32(int32_t a) { - return (int16_t)vqshruns_n_s32(a, 16); -} - -// CHECK-LABEL: define dso_local i32 @test_vqshrund_n_s64( -// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[VQSHRUND_N_S64:%.*]] = call i32 @llvm.aarch64.neon.sqshrun.i32(i64 [[A]], i32 32) -// CHECK-NEXT: ret i32 [[VQSHRUND_N_S64]] -// -int32_t test_vqshrund_n_s64(int64_t a) { - return (int32_t)vqshrund_n_s64(a, 32); -} - -// CHECK-LABEL: define dso_local i8 @test_vqrshrunh_n_s16( -// CHECK-SAME: i16 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRUNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshrun.v8i8(<8 x i16> [[TMP0]], i32 8) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRUNH_N_S16]], i64 0 -// CHECK-NEXT: ret i8 [[TMP1]] -// -uint8_t test_vqrshrunh_n_s16(int16_t a) { - return (uint8_t)vqrshrunh_n_s16(a, 8); -} - -// CHECK-LABEL: define dso_local i16 @test_vqrshruns_n_s32( -// CHECK-SAME: i32 noundef [[A:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 -// CHECK-NEXT: [[VQRSHRUNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshrun.v4i16(<4 x i32> [[TMP0]], i32 16) -// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRUNS_N_S32]], i64 0 -// CHECK-NEXT: ret i16 [[TMP1]] -// -uint16_t test_vqrshruns_n_s32(int32_t a) { - return (uint16_t)vqrshruns_n_s32(a, 16); -} - // CHECK-LABEL: define dso_local <8 x i8> @test_vreinterpret_s8_s16( // CHECK-SAME: <4 x i16> noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -16143,8 +15742,6 @@ float64x1_t test_vrecpe_f64(float64x1_t a) { return vrecpe_f64(a); } - - // CHECK-LABEL: define dso_local <1 x double> @test_vrecps_f64( // CHECK-SAME: <1 x double> noundef [[A:%.*]], <1 x double> noundef [[B:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c index 7f4ef381e6e5d..4c989e10245bd 100644 --- a/clang/test/CodeGen/AArch64/neon/intrinsics.c +++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c @@ -7540,4 +7540,432 @@ float64x2_t test_vrndxq_f64(float64x2_t a) { // LLVM: [[VRNDX1_I:%.*]] = call <2 x double> @llvm.rint.v2f64(<2 x double> [[VRNDX_I]]) // LLVM: ret <2 x double> [[VRNDX1_I]] return vrndxq_f64(a); -} \ No newline at end of file +} + +//===------------------------------------------------------===// +// 2.1.3.2.6. Vector saturating shift right and narrow +// https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#vector-saturating-shift-right-and-narrow +//===------------------------------------------------------===// + +// ALL-LABEL: @test_vqshrun_n_s16( +uint8x8_t test_vqshrun_n_s16(int16x8_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRUN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3) + // LLVM: ret <8 x i8> [[VQSHRUN_N1]] + return vqshrun_n_s16(a, 3); +} + +// ALL-LABEL: @test_vqshrun_n_s32( +uint16x4_t test_vqshrun_n_s32(int32x4_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRUN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9) + // LLVM: ret <4 x i16> [[VQSHRUN_N1]] + return vqshrun_n_s32(a, 9); +} + +// ALL-LABEL: @test_vqshrun_n_s64( +uint32x2_t test_vqshrun_n_s64(int64x2_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRUN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19) + // LLVM: ret <2 x i32> [[VQSHRUN_N1]] + return vqshrun_n_s64(a, 19); +} + +// ALL-LABEL: @test_vqshrunh_n_s16( +int8_t test_vqshrunh_n_s16(int16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQSHRUNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRUNH_N_S16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (int8_t)vqshrunh_n_s16(a, 8); +} + +// ALL-LABEL: @test_vqshruns_n_s32( +int16_t test_vqshruns_n_s32(int32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQSHRUNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRUNS_N_S32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (int16_t)vqshruns_n_s32(a, 16); +} + +// ALL-LABEL: @test_vqshrund_n_s64( +int32_t test_vqshrund_n_s64(int64_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: i64 {{.*}} [[A:%.*]]) + // LLVM: [[VQSHRUND_N_S64:%.*]] = call i32 @llvm.aarch64.neon.sqshrun.i32(i64 [[A]], i32 32) + // LLVM: ret i32 [[VQSHRUND_N_S64]] + return (int32_t)vqshrund_n_s64(a, 32); +} + +// ALL-LABEL: @test_vqshrun_high_n_s16( +uint8x16_t test_vqshrun_high_n_s16(uint8x8_t a, int16x8_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRUN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> [[VQSHRUN_N]], i32 3) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + // LLVM: ret <16 x i8> [[SHUFFLE_I]] + return vqshrun_high_n_s16(a, b, 3); +} + +// ALL-LABEL: @test_vqshrun_high_n_s32( +uint16x8_t test_vqshrun_high_n_s32(uint16x4_t a, int32x4_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRUN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> [[VQSHRUN_N]], i32 9) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + // LLVM: ret <8 x i16> [[SHUFFLE_I]] + return vqshrun_high_n_s32(a, b, 9); +} + +// ALL-LABEL: @test_vqshrun_high_n_s64( +uint32x4_t test_vqshrun_high_n_s64(uint32x2_t a, int64x2_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrun" + + // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> + // LLVM: [[VQSHRUN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRUN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> [[VQSHRUN_N]], i32 19) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> + // LLVM: ret <4 x i32> [[SHUFFLE_I]] + return vqshrun_high_n_s64(a, b, 19); +} + +// ALL-LABEL: @test_vqshrn_n_s16( +int8x8_t test_vqshrn_n_s16(int16x8_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) + // LLVM: ret <8 x i8> [[VQSHRN_N1]] + return vqshrn_n_s16(a, 3); +} + +// ALL-LABEL: @test_vqshrn_n_s32( +int16x4_t test_vqshrn_n_s32(int32x4_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) + // LLVM: ret <4 x i16> [[VQSHRN_N1]] + return vqshrn_n_s32(a, 9); +} + +// ALL-LABEL: @test_vqshrn_n_s64( +int32x2_t test_vqshrn_n_s64(int64x2_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) + // LLVM: ret <2 x i32> [[VQSHRN_N1]] + return vqshrn_n_s64(a, 19); +} + +// ALL-LABEL: @test_vqshrn_n_u16( +uint8x8_t test_vqshrn_n_u16(uint16x8_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRN_N1:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) + // LLVM: ret <8 x i8> [[VQSHRN_N1]] + return vqshrn_n_u16(a, 3); +} + +// ALL-LABEL: @test_vqshrn_n_u32( +uint16x4_t test_vqshrn_n_u32(uint32x4_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRN_N1:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) + // LLVM: ret <4 x i16> [[VQSHRN_N1]] + return vqshrn_n_u32(a, 9); +} + +// ALL-LABEL: @test_vqshrn_n_u64( +uint32x2_t test_vqshrn_n_u64(uint64x2_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRN_N1:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) + // LLVM: ret <2 x i32> [[VQSHRN_N1]] + return vqshrn_n_u64(a, 19); +} + +// ALL-LABEL: @test_vqshrn_high_n_s16( +int8x16_t test_vqshrn_high_n_s16(int8x8_t a, int16x8_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + // LLVM: ret <16 x i8> [[SHUFFLE_I]] + return vqshrn_high_n_s16(a, b, 3); +} + +// ALL-LABEL: @test_vqshrn_high_n_s32( +int16x8_t test_vqshrn_high_n_s32(int16x4_t a, int32x4_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + // LLVM: ret <8 x i16> [[SHUFFLE_I]] + return vqshrn_high_n_s32(a, b, 9); +} + +// ALL-LABEL: @test_vqshrn_high_n_s64( +int32x4_t test_vqshrn_high_n_s64(int32x2_t a, int64x2_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> + // LLVM: ret <4 x i32> [[SHUFFLE_I]] + return vqshrn_high_n_s64(a, b, 19); +} + +// ALL-LABEL: @test_vqshrn_high_n_u16( +uint8x16_t test_vqshrn_high_n_u16(uint8x8_t a, uint16x8_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <8 x i8> {{.*}} [[A:%.*]], <8 x i16> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> + // LLVM: [[VQSHRN_N3:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[VQSHRN_N]], i32 3) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> + // LLVM: ret <16 x i8> [[SHUFFLE_I]] + return vqshrn_high_n_u16(a, b, 3); +} + +// ALL-LABEL: @test_vqshrn_high_n_u32( +uint16x8_t test_vqshrn_high_n_u32(uint16x4_t a, uint32x4_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <4 x i16> {{.*}} [[A:%.*]], <4 x i32> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32> + // LLVM: [[VQSHRN_N3:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[VQSHRN_N]], i32 9) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + // LLVM: ret <8 x i16> [[SHUFFLE_I]] + return vqshrn_high_n_u32(a, b, 9); +} + +// ALL-LABEL: @test_vqshrn_high_n_u64( +uint32x4_t test_vqshrn_high_n_u64(uint32x2_t a, uint64x2_t b) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: <2 x i32> {{.*}} [[A:%.*]], <2 x i64> {{.*}} [[B:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i64> [[B]] to <16 x i8> + // LLVM: [[VQSHRN_N:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x i64> + // LLVM: [[VQSHRN_N3:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshrn.v2i32(<2 x i64> [[VQSHRN_N]], i32 19) + // LLVM: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> + // LLVM: ret <4 x i32> [[SHUFFLE_I]] + return vqshrn_high_n_u64(a, b, 19); +} + +// ALL-LABEL: @test_vqshrnh_n_s16( +int8_t test_vqshrnh_n_s16(int16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQSHRNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrn.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_S16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (int8_t)vqshrnh_n_s16(a, 8); +} + +// ALL-LABEL: @test_vqshrns_n_s32( +int16_t test_vqshrns_n_s32(int32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQSHRNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrn.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_S32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (int16_t)vqshrns_n_s32(a, 16); +} + +// ALL-LABEL: @test_vqshrnd_n_s64( +int32_t test_vqshrnd_n_s64(int64_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqshrn" + + // LLVM-SAME: i64 {{.*}} [[A:%.*]]) + // LLVM: [[VQSHRND_N_S64:%.*]] = call i32 @llvm.aarch64.neon.sqshrn.i32(i64 [[A]], i32 32) + // LLVM: ret i32 [[VQSHRND_N_S64]] + return (int32_t)vqshrnd_n_s64(a, 32); +} + +// ALL-LABEL: @test_vqshrnh_n_u16( +uint8_t test_vqshrnh_n_u16(uint16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQSHRNH_N_U16:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshrn.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQSHRNH_N_U16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (uint8_t)vqshrnh_n_u16(a, 8); +} + +// ALL-LABEL: @test_vqshrns_n_u32( +uint16_t test_vqshrns_n_u32(uint32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQSHRNS_N_U32:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshrn.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQSHRNS_N_U32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (uint16_t)vqshrns_n_u32(a, 16); +} + +// ALL-LABEL: @test_vqshrnd_n_u64( +uint32_t test_vqshrnd_n_u64(uint64_t a) { + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqshrn" + + // LLVM-SAME: i64 {{.*}} [[A:%.*]]) + // LLVM: [[VQSHRND_N_U64:%.*]] = call i32 @llvm.aarch64.neon.uqshrn.i32(i64 [[A]], i32 32) + // LLVM: ret i32 [[VQSHRND_N_U64]] + return (uint32_t)vqshrnd_n_u64(a, 32); +} + +// ALL-LABEL: @test_vqrshrnh_n_s16( +int8_t test_vqrshrnh_n_s16(int16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqrshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQRSHRNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshrn.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRNH_N_S16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (int8_t)vqrshrnh_n_s16(a, 8); +} + +// ALL-LABEL: @test_vqrshrns_n_s32( +int16_t test_vqrshrns_n_s32(int32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqrshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQRSHRNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshrn.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRNS_N_S32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (int16_t)vqrshrns_n_s32(a, 16); +} + +// ALL-LABEL: @test_vqrshrnh_n_u16( +uint8_t test_vqrshrnh_n_u16(uint16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqrshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQRSHRNH_N_U16:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshrn.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRNH_N_U16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (uint8_t)vqrshrnh_n_u16(a, 8); +} + +// ALL-LABEL: @test_vqrshrns_n_u32( +uint16_t test_vqrshrns_n_u32(uint32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.uqrshrn" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQRSHRNS_N_U32:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshrn.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRNS_N_U32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (uint16_t)vqrshrns_n_u32(a, 16); +} + +// ALL-LABEL: @test_vqrshrunh_n_s16( +uint8_t test_vqrshrunh_n_s16(int16_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqrshrun" + // CIR: cir.vec.extract + + // LLVM-SAME: i16 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 + // LLVM: [[VQRSHRUNH_N_S16:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshrun.v8i8(<8 x i16> [[TMP0]], i32 8) + // LLVM: [[TMP1:%.*]] = extractelement <8 x i8> [[VQRSHRUNH_N_S16]], i64 0 + // LLVM: ret i8 [[TMP1]] + return (uint8_t)vqrshrunh_n_s16(a, 8); +} + +// ALL-LABEL: @test_vqrshruns_n_s32( +uint16_t test_vqrshruns_n_s32(int32_t a) { + // CIR: cir.vec.insert + // CIR: cir.call_llvm_intrinsic "aarch64.neon.sqrshrun" + // CIR: cir.vec.extract + + // LLVM-SAME: i32 {{.*}} [[A:%.*]]) + // LLVM: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 + // LLVM: [[VQRSHRUNS_N_S32:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshrun.v4i16(<4 x i32> [[TMP0]], i32 16) + // LLVM: [[TMP1:%.*]] = extractelement <4 x i16> [[VQRSHRUNS_N_S32]], i64 0 + // LLVM: ret i16 [[TMP1]] + return (uint16_t)vqrshruns_n_s32(a, 16); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
