[clang] [CIR][AArc64] Add lowering for fp16 intrinsics (step + rounding) (PR #207511)
Andrzej WarzyĆski via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 6 10:49:31 PDT 2026
https://github.com/banach-space updated https://github.com/llvm/llvm-project/pull/207511
>From 5a793813e4a065a20b2bb4eb5a0d1a0bb3797a9a Mon Sep 17 00:00:00 2001
From: Andrzej Warzynski <andrzej.warzynski at arm.com>
Date: Sat, 4 Jul 2026 16:29:04 +0000
Subject: [PATCH] [CIR][AArc64] Add lowering for fp16 intrinsics (FP16 step +
rounding)
This PR adds lowering for the following intrinsic groups:
* https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#markdown-toc-reciprocal-step
It also adds FP16 tests for these intrinsics (implemented in #195021
without tests):
* https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#markdown-toc-rounding-1
It also moves the corresponding tests from:
* clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
to:
* clang/test/CodeGen/AArch64/neon/fullfp16.c
The lowering follows the existing implementation in
CodeGen/TargetBuiltins/ARM.cpp.
---
.../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 13 ++-
clang/test/CodeGen/AArch64/neon/fullfp16.c | 86 +++++++++++++++++++
.../CodeGen/AArch64/v8.2a-fp16-intrinsics.c | 56 ------------
3 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index e2ad897b5ba90..dfb5ace82bb06 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -657,8 +657,8 @@ static mlir::Value emitCommonNeonBuiltinExpr(
// FIXME
// getTargetHooks().getABIInfo().allowBFloatArgsAndRet();
- cir::VectorType vTy = getNeonType(&cgf, neonType, hasLegalHalfType, false,
- allowBFloatArgsAndRet);
+ cir::VectorType vTy = getNeonType(&cgf, neonType, hasLegalHalfType,
+ /*v1Ty=*/false, allowBFloatArgsAndRet);
cir::VectorType ty = vTy;
if (!ty)
return nullptr;
@@ -2929,7 +2929,14 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vmaxnmh_f16:
case NEON::BI__builtin_neon_vrecpss_f32:
case NEON::BI__builtin_neon_vrecpsd_f64:
- case NEON::BI__builtin_neon_vrecpsh_f16:
+ cgm.errorNYI(expr->getSourceRange(),
+ std::string("unimplemented AArch64 builtin call: ") +
+ getContext().BuiltinInfo.getName(builtinID));
+ return mlir::Value{};
+ case NEON::BI__builtin_neon_vrecpsh_f16: {
+ auto halfTy = builder.getFp16Ty();
+ return builder.emitIntrinsicCallOp(loc, "aarch64.neon.frecps", halfTy, ops);
+ }
case NEON::BI__builtin_neon_vqshrun_n_v:
cgm.errorNYI(expr->getSourceRange(),
std::string("unimplemented AArch64 builtin call: ") +
diff --git a/clang/test/CodeGen/AArch64/neon/fullfp16.c b/clang/test/CodeGen/AArch64/neon/fullfp16.c
index ba65f76e924c4..cd93d30e7d2ae 100644
--- a/clang/test/CodeGen/AArch64/neon/fullfp16.c
+++ b/clang/test/CodeGen/AArch64/neon/fullfp16.c
@@ -174,6 +174,92 @@ float16_t test_vrsqrtsh_f16(float16_t a, float16_t b) {
return vrsqrtsh_f16(a, b);
}
+//===------------------------------------------------------===//
+// 2.5.1.2.3. Reciprocal step
+//===------------------------------------------------------===//
+// ALL-LABEL: test_vrecpsh_f16
+float16_t test_vrecpsh_f16(float16_t a, float16_t b) {
+// CIR: cir.call_llvm_intrinsic "aarch64.neon.frecps"
+
+// LLVM-SAME: half {{.*}} [[A:%.*]], half {{.*}} [[B:%.*]])
+// LLVM: [[RECPS:%.*]] = call half @llvm.aarch64.neon.frecps.f16(half [[A]], half [[B]])
+// LLVM: ret half [[RECPS]]
+ return vrecpsh_f16(a, b);
+}
+
+//===------------------------------------------------------===//
+// 2.5.1.3. Rounding
+//===------------------------------------------------------===//
+// ALL-LABEL: test_vrndh_f16
+float16_t test_vrndh_f16(float16_t a) {
+// CIR: cir.trunc
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.trunc.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndh_f16(a);
+}
+
+// ALL-LABEL: test_vrndah_f16
+float16_t test_vrndah_f16(float16_t a) {
+// CIR: cir.round
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.round.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndah_f16(a);
+}
+
+// ALL-LABEL: test_vrndih_f16
+float16_t test_vrndih_f16(float16_t a) {
+// CIR: cir.nearbyint
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.nearbyint.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndih_f16(a);
+}
+
+// ALL-LABEL: test_vrndmh_f16
+float16_t test_vrndmh_f16(float16_t a) {
+// CIR: cir.floor
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.floor.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndmh_f16(a);
+}
+
+// ALL-LABEL: test_vrndnh_f16
+float16_t test_vrndnh_f16(float16_t a) {
+// CIR: cir.roundeven
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.roundeven.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndnh_f16(a);
+}
+
+// ALL-LABEL: test_vrndph_f16
+float16_t test_vrndph_f16(float16_t a) {
+// CIR: cir.ceil
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.ceil.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndph_f16(a);
+}
+
+// ALL-LABEL: test_vrndxh_f16
+float16_t test_vrndxh_f16(float16_t a) {
+// CIR: cir.rint
+
+// LLVM-SAME: half {{.*}} [[A:%.*]])
+// LLVM: [[RND:%.*]] = call half @llvm.rint.f16(half [[A]])
+// LLVM: ret half [[RND]]
+ return vrndxh_f16(a);
+}
+
//===------------------------------------------------------===//
// 2.5.4.1. Negate
//===------------------------------------------------------===//
diff --git a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
index ed6246238bf8e..ad4a0e5eb7275 100644
--- a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
@@ -291,55 +291,6 @@ uint64_t test_vcvtph_u64_f16 (float16_t a) {
return vcvtph_u64_f16(a);
}
-// CHECK-LABEL: test_vrndh_f16
-// CHECK: [[RND:%.*]] = call half @llvm.trunc.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndh_f16(float16_t a) {
- return vrndh_f16(a);
-}
-
-// CHECK-LABEL: test_vrndah_f16
-// CHECK: [[RND:%.*]] = call half @llvm.round.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndah_f16(float16_t a) {
- return vrndah_f16(a);
-}
-
-// CHECK-LABEL: test_vrndih_f16
-// CHECK: [[RND:%.*]] = call half @llvm.nearbyint.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndih_f16(float16_t a) {
- return vrndih_f16(a);
-}
-
-// CHECK-LABEL: test_vrndmh_f16
-// CHECK: [[RND:%.*]] = call half @llvm.floor.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndmh_f16(float16_t a) {
- return vrndmh_f16(a);
-}
-
-// CHECK-LABEL: test_vrndnh_f16
-// CHECK: [[RND:%.*]] = call half @llvm.roundeven.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndnh_f16(float16_t a) {
- return vrndnh_f16(a);
-}
-
-// CHECK-LABEL: test_vrndph_f16
-// CHECK: [[RND:%.*]] = call half @llvm.ceil.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndph_f16(float16_t a) {
- return vrndph_f16(a);
-}
-
-// CHECK-LABEL: test_vrndxh_f16
-// CHECK: [[RND:%.*]] = call half @llvm.rint.f16(half %a)
-// CHECK: ret half [[RND]]
-float16_t test_vrndxh_f16(float16_t a) {
- return vrndxh_f16(a);
-}
-
// CHECK-LABEL: test_vsqrth_f16
// CHECK: [[SQR:%.*]] = call half @llvm.sqrt.f16(half %a)
// CHECK: ret half [[SQR]]
@@ -541,10 +492,3 @@ float16_t test_vminnmh_f16(float16_t a, float16_t b) {
float16_t test_vmulxh_f16(float16_t a, float16_t b) {
return vmulxh_f16(a, b);
}
-
-// CHECK-LABEL: test_vrecpsh_f16
-// CHECK: [[RECPS:%.*]] = call half @llvm.aarch64.neon.frecps.f16(half %a, half %b)
-// CHECK: ret half [[RECPS]]
-float16_t test_vrecpsh_f16(float16_t a, float16_t b) {
- return vrecpsh_f16(a, b);
-}
More information about the cfe-commits
mailing list