[clang] [CIR][Aarch64] upstream scalar & vector intrinsics (FP16) (PR #190310)
Rafe Murray via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 2 22:46:11 PDT 2026
https://github.com/rafe-murray created https://github.com/llvm/llvm-project/pull/190310
This PR upstreams the following fp16 intrinsics as part of #185382:
- vaddh_f16,
- vsubh_f16,
- vmulh_f16,
- vdivh_f16
This is my first PR to LLVM, so any feedback is greatly appreciated!
>From 878e98c1a5887e1d8ef0c0b552aff5e5a245bce2 Mon Sep 17 00:00:00 2001
From: Rafe Murray <rafemurr at gmail.com>
Date: Thu, 12 Mar 2026 17:19:27 -0700
Subject: [PATCH] [CIR][Aarch64] upstream scalar & vector intrinsics (FP16)
---
.../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 16 ++++--
.../CodeGen/AArch64/neon/fp16_intrinsics.c | 57 +++++++++++++++++++
2 files changed, 69 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGen/AArch64/neon/fp16_intrinsics.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index d9d303cd07b92..ce7b3fa9f9877 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2122,14 +2122,22 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vdups_laneq_f32:
case NEON::BI__builtin_neon_vgetq_lane_f64:
case NEON::BI__builtin_neon_vdupd_laneq_f64:
- case NEON::BI__builtin_neon_vaddh_f16:
- case NEON::BI__builtin_neon_vsubh_f16:
- case NEON::BI__builtin_neon_vmulh_f16:
- case NEON::BI__builtin_neon_vdivh_f16:
cgm.errorNYI(expr->getSourceRange(),
std::string("unimplemented AArch64 builtin call: ") +
getContext().BuiltinInfo.getName(builtinID));
return mlir::Value{};
+ case NEON::BI__builtin_neon_vaddh_f16:
+ ops.push_back(emitScalarExpr(expr->getArg(1)));
+ return builder.createFAdd(loc, ops[0], ops[1]);
+ case NEON::BI__builtin_neon_vsubh_f16:
+ ops.push_back(emitScalarExpr(expr->getArg(1)));
+ return builder.createFSub(loc, ops[0], ops[1]);
+ case NEON::BI__builtin_neon_vmulh_f16:
+ ops.push_back(emitScalarExpr(expr->getArg(1)));
+ return builder.createFMul(loc, ops[0], ops[1]);
+ case NEON::BI__builtin_neon_vdivh_f16:
+ ops.push_back(emitScalarExpr(expr->getArg(1)));
+ return builder.createFDiv(loc, ops[0], ops[1]);
case NEON::BI__builtin_neon_vfmah_f16:
// NEON intrinsic puts accumulator first, unlike the LLVM fma.
std::rotate(ops.begin(), ops.begin() + 1, ops.end());
diff --git a/clang/test/CodeGen/AArch64/neon/fp16_intrinsics.c b/clang/test/CodeGen/AArch64/neon/fp16_intrinsics.c
new file mode 100644
index 0000000000000..8077d914cce81
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/neon/fp16_intrinsics.c
@@ -0,0 +1,57 @@
+#include <arm_fp16.h>
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +fullfp16 \
+// RUN: -fclangir -disable-O0-optnone \
+// RUN: -flax-vector-conversions=none -emit-cir -o %t.cir %s
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +fullfp16 \
+// RUN: -fclangir -disable-O0-optnone \
+// RUN: -flax-vector-conversions=none -emit-llvm -o - %s \
+// RUN: | opt -S -passes=mem2reg,simplifycfg -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+// REQUIRES: aarch64-registered-target || arm-registered-target
+
+// LLVM-LABEL: @test_vaddh_f16(
+// CIR-LABEL: @test_vaddh_f16(
+float16_t test_vaddh_f16(float16_t a, float16_t b) {
+// CIR: {{%.*}} = cir.add {{%.*}}, {{%.*}} : !cir.f16
+
+// LLVM-SAME: half {{.*}} [[A:%.*]], half{{.*}} [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// LLVM: [[ADD:%.*]] = fadd half [[A]], [[B]]
+// LLVM: ret half [[ADD]]
+ return vaddh_f16(a, b);
+}
+
+// LLVM-LABEL: @test_vsubh_f16(
+// CIR-LABEL: @test_vsubh_f16(
+float16_t test_vsubh_f16(float16_t a, float16_t b) {
+// CIR: {{%.*}} = cir.sub {{%.*}}, {{%.*}} : !cir.f16
+
+// LLVM-SAME: half {{.*}} [[A:%.]], half {{.*}} [[B:%.]]) #[[ATTR0:[0-9]+]] {
+// LLVM: [[SUB:%.*]] = fsub half [[A]], [[B]]
+// LLVM: ret half [[SUB]]
+ return vsubh_f16(a, b);
+}
+
+// LLVM-LABEL: @test_vmulh_f16(
+// CIR-LABEL: @test_vmulh_f16(
+float16_t test_vmulh_f16(float16_t a, float16_t b) {
+// CIR: {{%.*}} = cir.mul {{%.*}}, {{%.*}} : !cir.f16
+
+// LLVM-SAME: half {{.*}} [[A:%.]], half {{.*}} [[B:%.]]) #[[ATTR0:[0-9]+]] {
+// LLVM: [[MUL:%.*]] = fmul half [[A]], [[B]]
+// LLVM: ret half [[MUL]]
+ return vmulh_f16(a, b);
+}
+
+// LLVM-LABEL: @test_vdivh_f16(
+// CIR-LABEL: @test_vdivh_f16(
+float16_t test_vdivh_f16(float16_t a, float16_t b) {
+// CIR: {{%.*}} = cir.div {{%.*}}, {{%.*}} : !cir.f16
+
+// LLVM-SAME: half {{.*}} [[A:%.]], half {{.*}} [[B:%.]]) #[[ATTR0:[0-9]+]] {
+// LLVM: [[DIV:%.*]] = fdiv half [[A]], [[B]]
+// LLVM: ret half [[DIV]]
+ return vdivh_f16(a, b);
+}
More information about the cfe-commits
mailing list