[clang] Cir neon rounding (PR #195021)

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


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

part of https://github.com/llvm/llvm-project/issues/185382

>From dd20db8747133a29124964af2f8d2bde23169d4b 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 1/2] init

---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  | 22 +++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index cac5f8eced8a7..cdbba85c88a7f 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));
@@ -2602,21 +2600,39 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vrndah_f16:
   case NEON::BI__builtin_neon_vrnda_v:
   case NEON::BI__builtin_neon_vrndaq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "round", ty, loc);
   case NEON::BI__builtin_neon_vrndih_f16:
+  case NEON::BI__builtin_neon_vrndi_v:
+  case NEON::BI__builtin_neon_vrndiq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "nearbyint", ty, loc);
   case NEON::BI__builtin_neon_vrndmh_f16:
   case NEON::BI__builtin_neon_vrndm_v:
   case NEON::BI__builtin_neon_vrndmq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "floor", ty, loc);
   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:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "roundeven", ty, loc);
   case NEON::BI__builtin_neon_vrndph_f16:
   case NEON::BI__builtin_neon_vrndp_v:
   case NEON::BI__builtin_neon_vrndpq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "ceil", ty, loc);
   case NEON::BI__builtin_neon_vrndxh_f16:
   case NEON::BI__builtin_neon_vrndx_v:
   case NEON::BI__builtin_neon_vrndxq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "rint", ty, loc);
   case NEON::BI__builtin_neon_vrndh_f16:
+  case NEON::BI__builtin_neon_vrnd_v:
+  case NEON::BI__builtin_neon_vrndq_v:
+    assert(!cir::MissingFeatures::emitConstrainedFPCall());
+    return emitNeonCall(cgm, builder, {ty}, ops, "trunc", ty, loc);
   case NEON::BI__builtin_neon_vrnd32x_f32:
   case NEON::BI__builtin_neon_vrnd32xq_f32:
   case NEON::BI__builtin_neon_vrnd32x_f64:
@@ -2633,8 +2649,6 @@ 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));

>From b841e042e4bda12968b40d1993c1523915233ec1 Mon Sep 17 00:00:00 2001
From: AbdallahRashed <abdallah.mrashed at gmail.com>
Date: Tue, 28 Apr 2026 23:24:36 +0200
Subject: [PATCH 2/2] [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  |  28 ++++-
 .../CIR/CodeGenBuiltins/AArch64/neon-vrnd.c   | 118 ++++++++++++++++++
 2 files changed, 144 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenBuiltins/AArch64/neon-vrnd.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index cdbba85c88a7f..079492148b6d7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -841,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:
@@ -2603,8 +2629,6 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
     assert(!cir::MissingFeatures::emitConstrainedFPCall());
     return emitNeonCall(cgm, builder, {ty}, ops, "round", ty, loc);
   case NEON::BI__builtin_neon_vrndih_f16:
-  case NEON::BI__builtin_neon_vrndi_v:
-  case NEON::BI__builtin_neon_vrndiq_v:
     assert(!cir::MissingFeatures::emitConstrainedFPCall());
     return emitNeonCall(cgm, builder, {ty}, ops, "nearbyint", ty, loc);
   case NEON::BI__builtin_neon_vrndmh_f16:
diff --git a/clang/test/CIR/CodeGenBuiltins/AArch64/neon-vrnd.c b/clang/test/CIR/CodeGenBuiltins/AArch64/neon-vrnd.c
new file mode 100644
index 0000000000000..e2ce08af5626b
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/AArch64/neon-vrnd.c
@@ -0,0 +1,118 @@
+// Test AArch64 NEON rounding builtins
+
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon \
+// RUN:   -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon \
+// RUN:   -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_neon.h>
+
+// vrndq (trunc)
+float32x4_t test_vrndq_f32(float32x4_t a) {
+  return vrndq_f32(a);
+}
+// CIR-LABEL: @vrndq_f32
+// CIR: cir.call_llvm_intrinsic "trunc" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndq_f32
+// LLVM: call <4 x float> @llvm.trunc.v4f32
+
+// vrndaq (round)
+float32x4_t test_vrndaq_f32(float32x4_t a) {
+  return vrndaq_f32(a);
+}
+// CIR-LABEL: @vrndaq_f32
+// CIR: cir.call_llvm_intrinsic "round" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndaq_f32
+// LLVM: call <4 x float> @llvm.round.v4f32
+
+// vrndiq (nearbyint)
+float32x4_t test_vrndiq_f32(float32x4_t a) {
+  return vrndiq_f32(a);
+}
+// CIR-LABEL: @vrndiq_f32
+// CIR: cir.call_llvm_intrinsic "nearbyint" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndiq_f32
+// LLVM: call <4 x float> @llvm.nearbyint.v4f32
+
+// vrndmq (floor)
+float32x4_t test_vrndmq_f32(float32x4_t a) {
+  return vrndmq_f32(a);
+}
+// CIR-LABEL: @vrndmq_f32
+// CIR: cir.call_llvm_intrinsic "floor" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndmq_f32
+// LLVM: call <4 x float> @llvm.floor.v4f32
+
+// vrndnq (roundeven)
+float32x4_t test_vrndnq_f32(float32x4_t a) {
+  return vrndnq_f32(a);
+}
+// CIR-LABEL: @vrndnq_f32
+// CIR: cir.call_llvm_intrinsic "roundeven" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndnq_f32
+// LLVM: call <4 x float> @llvm.roundeven.v4f32
+
+// vrndpq (ceil)
+float32x4_t test_vrndpq_f32(float32x4_t a) {
+  return vrndpq_f32(a);
+}
+// CIR-LABEL: @vrndpq_f32
+// CIR: cir.call_llvm_intrinsic "ceil" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndpq_f32
+// LLVM: call <4 x float> @llvm.ceil.v4f32
+
+// vrndxq (rint)
+float32x4_t test_vrndxq_f32(float32x4_t a) {
+  return vrndxq_f32(a);
+}
+// CIR-LABEL: @vrndxq_f32
+// CIR: cir.call_llvm_intrinsic "rint" {{%.*}} : (!cir.vector<4 x !cir.float>) -> !cir.vector<4 x !cir.float>
+// LLVM-LABEL: @test_vrndxq_f32
+// LLVM: call <4 x float> @llvm.rint.v4f32
+
+// Non-q (64-bit) variants
+float32x2_t test_vrnd_f32(float32x2_t a) {
+  return vrnd_f32(a);
+}
+// CIR-LABEL: @vrnd_f32
+// CIR: cir.call_llvm_intrinsic "trunc" {{%.*}} : (!cir.vector<2 x !cir.float>) -> !cir.vector<2 x !cir.float>
+// LLVM-LABEL: @test_vrnd_f32
+// LLVM: call <2 x float> @llvm.trunc.v2f32
+
+float32x2_t test_vrnda_f32(float32x2_t a) {
+  return vrnda_f32(a);
+}
+// CIR-LABEL: @vrnda_f32
+// CIR: cir.call_llvm_intrinsic "round" {{%.*}} : (!cir.vector<2 x !cir.float>) -> !cir.vector<2 x !cir.float>
+// LLVM-LABEL: @test_vrnda_f32
+// LLVM: call <2 x float> @llvm.round.v2f32
+
+float32x2_t test_vrndi_f32(float32x2_t a) {
+  return vrndi_f32(a);
+}
+// CIR-LABEL: @vrndi_f32
+// CIR: cir.call_llvm_intrinsic "nearbyint" {{%.*}} : (!cir.vector<2 x !cir.float>) -> !cir.vector<2 x !cir.float>
+// LLVM-LABEL: @test_vrndi_f32
+// LLVM: call <2 x float> @llvm.nearbyint.v2f32
+
+// f64 variants
+float64x2_t test_vrndq_f64(float64x2_t a) {
+  return vrndq_f64(a);
+}
+// CIR-LABEL: @vrndq_f64
+// CIR: cir.call_llvm_intrinsic "trunc" {{%.*}} : (!cir.vector<2 x !cir.double>) -> !cir.vector<2 x !cir.double>
+// LLVM-LABEL: @test_vrndq_f64
+// LLVM: call <2 x double> @llvm.trunc.v2f64
+
+float64x2_t test_vrndiq_f64(float64x2_t a) {
+  return vrndiq_f64(a);
+}
+// CIR-LABEL: @vrndiq_f64
+// CIR: cir.call_llvm_intrinsic "nearbyint" {{%.*}} : (!cir.vector<2 x !cir.double>) -> !cir.vector<2 x !cir.double>
+// LLVM-LABEL: @test_vrndiq_f64
+// LLVM: call <2 x double> @llvm.nearbyint.v2f64



More information about the cfe-commits mailing list