[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