[clang] Cir neon rounding (PR #195021)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 30 00:55:28 PDT 2026


https://github.com/AbdallahRashed updated https://github.com/llvm/llvm-project/pull/195021

>From 33bc249daa042ed0da4b8b35b4920139e589e1c9 Mon Sep 17 00:00:00 2001
From: AbdallahRashed <abdallah.mrashed at gmail.com>
Date: Tue, 28 Apr 2026 23:08:48 +0200
Subject: [PATCH] [CIR][NFC] Add AArch64 NEON rounding builtins

Implement CIR lowering for AArch64 NEON rounding builtins:
- vrnd (trunc), vrnda (round), vrndi (nearbyint), vrndm (floor),
  vrndn (roundeven), vrndp (ceil), vrndx (rint)
- vrnd32x, vrnd32z, vrnd64x, vrnd64z (v8.5-a FRINT variants)

The standard rounding builtins lower to the corresponding LLVM
math intrinsics (llvm.trunc, llvm.round, etc.). The vrndi_v/vrndiq_v
cases are handled in the common NEON switch since they enter via
AArch64SIMDIntrinsicMap (NEONMAP0). The vrnd32/64 builtins use
NEONMAP1 entries with their aarch64.neon.frint* intrinsic names.

Part of #185382
---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  |  85 +++++-
 clang/test/CodeGen/AArch64/neon-intrinsics.c  |  99 ------
 clang/test/CodeGen/AArch64/neon-misc.c        |  91 ------
 clang/test/CodeGen/AArch64/neon/intrinsics.c  | 281 ++++++++++++++++++
 4 files changed, 351 insertions(+), 205 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index cac5f8eced8a7..fe994b45974c0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -744,8 +744,6 @@ static mlir::Value emitCommonNeonBuiltinExpr(
   case NEON::BI__builtin_neon_vrecpeq_v:
   case NEON::BI__builtin_neon_vrsqrte_v:
   case NEON::BI__builtin_neon_vrsqrteq_v:
-  case NEON::BI__builtin_neon_vrndi_v:
-  case NEON::BI__builtin_neon_vrndiq_v:
     cgf.cgm.errorNYI(expr->getSourceRange(),
                      std::string("unimplemented AArch64 builtin call: ") +
                          ctx.BuiltinInfo.getName(builtinID));
@@ -843,6 +841,32 @@ static mlir::Value emitCommonNeonBuiltinExpr(
   case NEON::BI__builtin_neon_vmulq_v:
     return cgf.getBuilder().emitIntrinsicCallOp(loc, "aarch64.neon.pmul", vTy,
                                                 ops);
+  case NEON::BI__builtin_neon_vrndi_v:
+  case NEON::BI__builtin_neon_vrndiq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgf.cgm, cgf.getBuilder(), {ty}, ops, "nearbyint", ty,
+                        loc);
+  case NEON::BI__builtin_neon_vrnd32x_f32:
+  case NEON::BI__builtin_neon_vrnd32xq_f32:
+  case NEON::BI__builtin_neon_vrnd32x_f64:
+  case NEON::BI__builtin_neon_vrnd32xq_f64:
+  case NEON::BI__builtin_neon_vrnd32z_f32:
+  case NEON::BI__builtin_neon_vrnd32zq_f32:
+  case NEON::BI__builtin_neon_vrnd32z_f64:
+  case NEON::BI__builtin_neon_vrnd32zq_f64:
+  case NEON::BI__builtin_neon_vrnd64x_f32:
+  case NEON::BI__builtin_neon_vrnd64xq_f32:
+  case NEON::BI__builtin_neon_vrnd64x_f64:
+  case NEON::BI__builtin_neon_vrnd64xq_f64:
+  case NEON::BI__builtin_neon_vrnd64z_f32:
+  case NEON::BI__builtin_neon_vrnd64zq_f32:
+  case NEON::BI__builtin_neon_vrnd64z_f64:
+  case NEON::BI__builtin_neon_vrnd64zq_f64: {
+    llvm::StringRef intrName = getLLVMIntrNameNoPrefix(
+        static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
+    return emitNeonCall(cgf.cgm, cgf.getBuilder(), {ty}, ops, intrName, ty,
+                        loc);
+  }
   case NEON::BI__builtin_neon_vusmmlaq_s32:
   case NEON::BI__builtin_neon_vusdot_s32:
   case NEON::BI__builtin_neon_vusdotq_s32:
@@ -2600,22 +2624,11 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vrshrn_n_v:
   case NEON::BI__builtin_neon_vqrshrn_n_v:
   case NEON::BI__builtin_neon_vrndah_f16:
-  case NEON::BI__builtin_neon_vrnda_v:
-  case NEON::BI__builtin_neon_vrndaq_v:
   case NEON::BI__builtin_neon_vrndih_f16:
   case NEON::BI__builtin_neon_vrndmh_f16:
-  case NEON::BI__builtin_neon_vrndm_v:
-  case NEON::BI__builtin_neon_vrndmq_v:
   case NEON::BI__builtin_neon_vrndnh_f16:
-  case NEON::BI__builtin_neon_vrndn_v:
-  case NEON::BI__builtin_neon_vrndnq_v:
-  case NEON::BI__builtin_neon_vrndns_f32:
   case NEON::BI__builtin_neon_vrndph_f16:
-  case NEON::BI__builtin_neon_vrndp_v:
-  case NEON::BI__builtin_neon_vrndpq_v:
   case NEON::BI__builtin_neon_vrndxh_f16:
-  case NEON::BI__builtin_neon_vrndx_v:
-  case NEON::BI__builtin_neon_vrndxq_v:
   case NEON::BI__builtin_neon_vrndh_f16:
   case NEON::BI__builtin_neon_vrnd32x_f32:
   case NEON::BI__builtin_neon_vrnd32xq_f32:
@@ -2633,12 +2646,54 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vrnd64zq_f32:
   case NEON::BI__builtin_neon_vrnd64z_f64:
   case NEON::BI__builtin_neon_vrnd64zq_f64:
-  case NEON::BI__builtin_neon_vrnd_v:
-  case NEON::BI__builtin_neon_vrndq_v:
     cgm.errorNYI(expr->getSourceRange(),
                  std::string("unimplemented AArch64 builtin call: ") +
                      getContext().BuiltinInfo.getName(builtinID));
     return mlir::Value{};
+  case NEON::BI__builtin_neon_vrnda_v:
+  case NEON::BI__builtin_neon_vrndaq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::RoundOp>(cgm, builder, {ty}, ops, std::nullopt,
+                                          ty, loc);
+  }
+  case NEON::BI__builtin_neon_vrndm_v:
+  case NEON::BI__builtin_neon_vrndmq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::FloorOp>(cgm, builder, {ty}, ops, std::nullopt,
+                                          ty, loc);
+  }
+  case NEON::BI__builtin_neon_vrndn_v:
+  case NEON::BI__builtin_neon_vrndnq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {ty}, ops,
+                                              std::nullopt, ty, loc);
+  }
+  case NEON::BI__builtin_neon_vrndns_f32: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    mlir::Value arg0 = emitScalarExpr(expr->getArg(0));
+    llvm::SmallVector<mlir::Value, 1> scalarArgs = {arg0};
+    return emitNeonCallToOp<cir::RoundEvenOp>(
+        cgm, builder, {arg0.getType()}, scalarArgs, std::nullopt, cgm.floatTy,
+        getLoc(expr->getExprLoc()));
+  }
+  case NEON::BI__builtin_neon_vrndp_v:
+  case NEON::BI__builtin_neon_vrndpq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::CeilOp>(cgm, builder, {ty}, ops, std::nullopt,
+                                         ty, loc);
+  }
+  case NEON::BI__builtin_neon_vrndx_v:
+  case NEON::BI__builtin_neon_vrndxq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::RintOp>(cgm, builder, {ty}, ops, std::nullopt,
+                                         ty, loc);
+  }
+  case NEON::BI__builtin_neon_vrnd_v:
+  case NEON::BI__builtin_neon_vrndq_v: {
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCallToOp<cir::TruncOp>(cgm, builder, {ty}, ops, std::nullopt,
+                                          ty, loc);
+  }
   case NEON::BI__builtin_neon_vcvt_f64_v:
   case NEON::BI__builtin_neon_vcvtq_f64_v:
     ops[0] = builder.createBitcast(ops[0], ty);
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index 784d9624823d5..ea523477b077b 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -20517,105 +20517,6 @@ float64x1_t test_vcvt_f64_u64(uint64x1_t a) {
   return vcvt_f64_u64(a);
 }
 
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrndn_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDN_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDN1_I:%.*]] = call <1 x double> @llvm.roundeven.v1f64(<1 x double> [[VRNDN_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDN1_I]]
-//
-float64x1_t test_vrndn_f64(float64x1_t a) {
-  return vrndn_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrnda_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDA_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDA1_I:%.*]] = call <1 x double> @llvm.round.v1f64(<1 x double> [[VRNDA_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDA1_I]]
-//
-float64x1_t test_vrnda_f64(float64x1_t a) {
-  return vrnda_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrndp_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDP_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDP1_I:%.*]] = call <1 x double> @llvm.ceil.v1f64(<1 x double> [[VRNDP_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDP1_I]]
-//
-float64x1_t test_vrndp_f64(float64x1_t a) {
-  return vrndp_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrndm_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDM_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDM1_I:%.*]] = call <1 x double> @llvm.floor.v1f64(<1 x double> [[VRNDM_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDM1_I]]
-//
-float64x1_t test_vrndm_f64(float64x1_t a) {
-  return vrndm_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrndx_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDX_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDX1_I:%.*]] = call <1 x double> @llvm.rint.v1f64(<1 x double> [[VRNDX_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDX1_I]]
-//
-float64x1_t test_vrndx_f64(float64x1_t a) {
-  return vrndx_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrnd_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDZ_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDZ1_I:%.*]] = call <1 x double> @llvm.trunc.v1f64(<1 x double> [[VRNDZ_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDZ1_I]]
-//
-float64x1_t test_vrnd_f64(float64x1_t a) {
-  return vrnd_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <1 x double> @test_vrndi_f64(
-// CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <1 x double> [[A]] to i64
-// CHECK-NEXT:    [[__P0_ADDR_I_SROA_0_0_VEC_INSERT:%.*]] = insertelement <1 x i64> undef, i64 [[TMP0]], i32 0
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <1 x i64> [[__P0_ADDR_I_SROA_0_0_VEC_INSERT]] to <8 x i8>
-// CHECK-NEXT:    [[VRNDI_V_I:%.*]] = bitcast <8 x i8> [[TMP1]] to <1 x double>
-// CHECK-NEXT:    [[VRNDI_V1_I:%.*]] = call <1 x double> @llvm.nearbyint.v1f64(<1 x double> [[VRNDI_V_I]])
-// CHECK-NEXT:    ret <1 x double> [[VRNDI_V1_I]]
-//
-float64x1_t test_vrndi_f64(float64x1_t a) {
-  return vrndi_f64(a);
-}
-
 // CHECK-LABEL: define dso_local <1 x double> @test_vrsqrte_f64(
 // CHECK-SAME: <1 x double> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon-misc.c b/clang/test/CodeGen/AArch64/neon-misc.c
index d4cfcfe4e9bdc..9a12d1948cd03 100644
--- a/clang/test/CodeGen/AArch64/neon-misc.c
+++ b/clang/test/CodeGen/AArch64/neon-misc.c
@@ -2748,97 +2748,6 @@ float64x2_t test_vcvt_high_f64_f32(float32x4_t a) {
   return vcvt_high_f64_f32(a);
 }
 
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndnq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDN_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDN1_I:%.*]] = call <2 x double> @llvm.roundeven.v2f64(<2 x double> [[VRNDN_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDN1_I]]
-//
-float64x2_t test_vrndnq_f64(float64x2_t a) {
-  return vrndnq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndaq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDA_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDA1_I:%.*]] = call <2 x double> @llvm.round.v2f64(<2 x double> [[VRNDA_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDA1_I]]
-//
-float64x2_t test_vrndaq_f64(float64x2_t a) {
-  return vrndaq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndpq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDP_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDP1_I:%.*]] = call <2 x double> @llvm.ceil.v2f64(<2 x double> [[VRNDP_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDP1_I]]
-//
-float64x2_t test_vrndpq_f64(float64x2_t a) {
-  return vrndpq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndmq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDM_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDM1_I:%.*]] = call <2 x double> @llvm.floor.v2f64(<2 x double> [[VRNDM_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDM1_I]]
-//
-float64x2_t test_vrndmq_f64(float64x2_t a) {
-  return vrndmq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndxq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDX_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDX1_I:%.*]] = call <2 x double> @llvm.rint.v2f64(<2 x double> [[VRNDX_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDX1_I]]
-//
-float64x2_t test_vrndxq_f64(float64x2_t a) {
-  return vrndxq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDZ_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDZ1_I:%.*]] = call <2 x double> @llvm.trunc.v2f64(<2 x double> [[VRNDZ_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDZ1_I]]
-//
-float64x2_t test_vrndq_f64(float64x2_t a) {
-  return vrndq_f64(a);
-}
-
-// CHECK-LABEL: define dso_local <2 x double> @test_vrndiq_f64(
-// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
-// CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
-// CHECK-NEXT:    [[VRNDIQ_V_I:%.*]] = bitcast <16 x i8> [[TMP1]] to <2 x double>
-// CHECK-NEXT:    [[VRNDIQ_V1_I:%.*]] = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> [[VRNDIQ_V_I]])
-// CHECK-NEXT:    ret <2 x double> [[VRNDIQ_V1_I]]
-//
-float64x2_t test_vrndiq_f64(float64x2_t a) {
-  return vrndiq_f64(a);
-}
-
 // CHECK-LABEL: define dso_local <2 x i32> @test_vcvt_s32_f32(
 // CHECK-SAME: <2 x float> noundef [[A:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index 83c1ea1ff6767..37f3b258bb5e1 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -4505,3 +4505,284 @@ uint64_t test_vrshrd_n_u64(uint64_t a) {
 // CHECK-NEXT:    [[VRSHR_N:%.*]] = call i64 @llvm.aarch64.neon.urshl.i64(i64 [[A]], i64 -63)
   return (uint64_t)vrshrd_n_u64(a, 63);
 }
+
+//===------------------------------------------------------===//
+// 2.1.1.12 Directed Rounding
+//===------------------------------------------------------===//
+
+// vrnda - Round to nearest, ties to away
+
+// ALL-LABEL: @test_vrnda_f32(
+float32x2_t test_vrnda_f32(float32x2_t a) {
+// CIR: cir.call @vrnda_f32
+
+// LLVM: [[VRNDA:%.*]] = call <2 x float> @llvm.round.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDA]]
+  return vrnda_f32(a);
+}
+
+// ALL-LABEL: @test_vrndaq_f32(
+float32x4_t test_vrndaq_f32(float32x4_t a) {
+// CIR: cir.call @vrndaq_f32
+
+// LLVM: [[VRNDA:%.*]] = call <4 x float> @llvm.round.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDA]]
+  return vrndaq_f32(a);
+}
+
+// ALL-LABEL: @test_vrnda_f64(
+float64x1_t test_vrnda_f64(float64x1_t a) {
+// CIR: cir.call @vrnda_f64
+
+// LLVM: [[VRNDA:%.*]] = call <1 x double> @llvm.round.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDA]]
+  return vrnda_f64(a);
+}
+
+// ALL-LABEL: @test_vrndaq_f64(
+float64x2_t test_vrndaq_f64(float64x2_t a) {
+// CIR: cir.call @vrndaq_f64
+
+// LLVM: [[VRNDA:%.*]] = call <2 x double> @llvm.round.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDA]]
+  return vrndaq_f64(a);
+}
+
+// vrndm - Round towards minus infinity (floor)
+
+// ALL-LABEL: @test_vrndm_f32(
+float32x2_t test_vrndm_f32(float32x2_t a) {
+// CIR: cir.call @vrndm_f32
+
+// LLVM: [[VRNDM:%.*]] = call <2 x float> @llvm.floor.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDM]]
+  return vrndm_f32(a);
+}
+
+// ALL-LABEL: @test_vrndmq_f32(
+float32x4_t test_vrndmq_f32(float32x4_t a) {
+// CIR: cir.call @vrndmq_f32
+
+// LLVM: [[VRNDM:%.*]] = call <4 x float> @llvm.floor.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDM]]
+  return vrndmq_f32(a);
+}
+
+// ALL-LABEL: @test_vrndm_f64(
+float64x1_t test_vrndm_f64(float64x1_t a) {
+// CIR: cir.call @vrndm_f64
+
+// LLVM: [[VRNDM:%.*]] = call <1 x double> @llvm.floor.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDM]]
+  return vrndm_f64(a);
+}
+
+// ALL-LABEL: @test_vrndmq_f64(
+float64x2_t test_vrndmq_f64(float64x2_t a) {
+// CIR: cir.call @vrndmq_f64
+
+// LLVM: [[VRNDM:%.*]] = call <2 x double> @llvm.floor.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDM]]
+  return vrndmq_f64(a);
+}
+
+// vrndn - Round to nearest, ties to even
+
+// ALL-LABEL: @test_vrndn_f32(
+float32x2_t test_vrndn_f32(float32x2_t a) {
+// CIR: cir.call @vrndn_f32
+
+// LLVM: [[VRNDN:%.*]] = call <2 x float> @llvm.roundeven.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDN]]
+  return vrndn_f32(a);
+}
+
+// ALL-LABEL: @test_vrndnq_f32(
+float32x4_t test_vrndnq_f32(float32x4_t a) {
+// CIR: cir.call @vrndnq_f32
+
+// LLVM: [[VRNDN:%.*]] = call <4 x float> @llvm.roundeven.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDN]]
+  return vrndnq_f32(a);
+}
+
+// ALL-LABEL: @test_vrndn_f64(
+float64x1_t test_vrndn_f64(float64x1_t a) {
+// CIR: cir.call @vrndn_f64
+
+// LLVM: [[VRNDN:%.*]] = call <1 x double> @llvm.roundeven.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDN]]
+  return vrndn_f64(a);
+}
+
+// ALL-LABEL: @test_vrndnq_f64(
+float64x2_t test_vrndnq_f64(float64x2_t a) {
+// CIR: cir.call @vrndnq_f64
+
+// LLVM: [[VRNDN:%.*]] = call <2 x double> @llvm.roundeven.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDN]]
+  return vrndnq_f64(a);
+}
+
+// vrndns - Round to nearest, ties to even (scalar f32)
+
+// ALL-LABEL: @test_vrndns_f32(
+float32_t test_vrndns_f32(float32_t a) {
+// CIR: cir.call @vrndns_f32
+
+// LLVM: [[VRNDN:%.*]] = call float @llvm.roundeven.f32(float {{%.*}})
+// LLVM: ret float [[VRNDN]]
+  return vrndns_f32(a);
+}
+
+// vrndp - Round towards plus infinity (ceil)
+
+// ALL-LABEL: @test_vrndp_f32(
+float32x2_t test_vrndp_f32(float32x2_t a) {
+// CIR: cir.call @vrndp_f32
+
+// LLVM: [[VRNDP:%.*]] = call <2 x float> @llvm.ceil.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDP]]
+  return vrndp_f32(a);
+}
+
+// ALL-LABEL: @test_vrndpq_f32(
+float32x4_t test_vrndpq_f32(float32x4_t a) {
+// CIR: cir.call @vrndpq_f32
+
+// LLVM: [[VRNDP:%.*]] = call <4 x float> @llvm.ceil.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDP]]
+  return vrndpq_f32(a);
+}
+
+// ALL-LABEL: @test_vrndp_f64(
+float64x1_t test_vrndp_f64(float64x1_t a) {
+// CIR: cir.call @vrndp_f64
+
+// LLVM: [[VRNDP:%.*]] = call <1 x double> @llvm.ceil.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDP]]
+  return vrndp_f64(a);
+}
+
+// ALL-LABEL: @test_vrndpq_f64(
+float64x2_t test_vrndpq_f64(float64x2_t a) {
+// CIR: cir.call @vrndpq_f64
+
+// LLVM: [[VRNDP:%.*]] = call <2 x double> @llvm.ceil.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDP]]
+  return vrndpq_f64(a);
+}
+
+// vrndx - Round using FPCR rounding mode (exact, rint)
+
+// ALL-LABEL: @test_vrndx_f32(
+float32x2_t test_vrndx_f32(float32x2_t a) {
+// CIR: cir.call @vrndx_f32
+
+// LLVM: [[VRNDX:%.*]] = call <2 x float> @llvm.rint.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDX]]
+  return vrndx_f32(a);
+}
+
+// ALL-LABEL: @test_vrndxq_f32(
+float32x4_t test_vrndxq_f32(float32x4_t a) {
+// CIR: cir.call @vrndxq_f32
+
+// LLVM: [[VRNDX:%.*]] = call <4 x float> @llvm.rint.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDX]]
+  return vrndxq_f32(a);
+}
+
+// ALL-LABEL: @test_vrndx_f64(
+float64x1_t test_vrndx_f64(float64x1_t a) {
+// CIR: cir.call @vrndx_f64
+
+// LLVM: [[VRNDX:%.*]] = call <1 x double> @llvm.rint.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDX]]
+  return vrndx_f64(a);
+}
+
+// ALL-LABEL: @test_vrndxq_f64(
+float64x2_t test_vrndxq_f64(float64x2_t a) {
+// CIR: cir.call @vrndxq_f64
+
+// LLVM: [[VRNDX:%.*]] = call <2 x double> @llvm.rint.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDX]]
+  return vrndxq_f64(a);
+}
+
+// vrnd - Round towards zero (truncate)
+
+// ALL-LABEL: @test_vrnd_f32(
+float32x2_t test_vrnd_f32(float32x2_t a) {
+// CIR: cir.call @vrnd_f32
+
+// LLVM: [[VRND:%.*]] = call <2 x float> @llvm.trunc.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRND]]
+  return vrnd_f32(a);
+}
+
+// ALL-LABEL: @test_vrndq_f32(
+float32x4_t test_vrndq_f32(float32x4_t a) {
+// CIR: cir.call @vrndq_f32
+
+// LLVM: [[VRND:%.*]] = call <4 x float> @llvm.trunc.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRND]]
+  return vrndq_f32(a);
+}
+
+// ALL-LABEL: @test_vrnd_f64(
+float64x1_t test_vrnd_f64(float64x1_t a) {
+// CIR: cir.call @vrnd_f64
+
+// LLVM: [[VRND:%.*]] = call <1 x double> @llvm.trunc.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRND]]
+  return vrnd_f64(a);
+}
+
+// ALL-LABEL: @test_vrndq_f64(
+float64x2_t test_vrndq_f64(float64x2_t a) {
+// CIR: cir.call @vrndq_f64
+
+// LLVM: [[VRND:%.*]] = call <2 x double> @llvm.trunc.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRND]]
+  return vrndq_f64(a);
+}
+
+// vrndi - Round using FPCR rounding mode (inexact, nearbyint)
+
+// ALL-LABEL: @test_vrndi_f32(
+float32x2_t test_vrndi_f32(float32x2_t a) {
+// CIR: cir.call @vrndi_f32
+
+// LLVM: [[VRNDI:%.*]] = call <2 x float> @llvm.nearbyint.v2f32(<2 x float> {{%.*}})
+// LLVM: ret <2 x float> [[VRNDI]]
+  return vrndi_f32(a);
+}
+
+// ALL-LABEL: @test_vrndiq_f32(
+float32x4_t test_vrndiq_f32(float32x4_t a) {
+// CIR: cir.call @vrndiq_f32
+
+// LLVM: [[VRNDI:%.*]] = call <4 x float> @llvm.nearbyint.v4f32(<4 x float> {{%.*}})
+// LLVM: ret <4 x float> [[VRNDI]]
+  return vrndiq_f32(a);
+}
+
+// ALL-LABEL: @test_vrndi_f64(
+float64x1_t test_vrndi_f64(float64x1_t a) {
+// CIR: cir.call @vrndi_f64
+
+// LLVM: [[VRNDI:%.*]] = call <1 x double> @llvm.nearbyint.v1f64(<1 x double> {{%.*}})
+// LLVM: ret <1 x double> [[VRNDI]]
+  return vrndi_f64(a);
+}
+
+// ALL-LABEL: @test_vrndiq_f64(
+float64x2_t test_vrndiq_f64(float64x2_t a) {
+// CIR: cir.call @vrndiq_f64
+
+// LLVM: [[VRNDI:%.*]] = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> {{%.*}})
+// LLVM: ret <2 x double> [[VRNDI]]
+  return vrndiq_f64(a);
+}



More information about the cfe-commits mailing list