[clang] ec18b92 - [CIR][NEON] Add lowering for `vnegd_s64` and `vnegh_f16` (#180597)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 11 03:11:02 PST 2026
Author: Andrzej Warzyński
Date: 2026-02-11T11:10:57Z
New Revision: ec18b92815dfadb080a8dff39914eb113b55cacf
URL: https://github.com/llvm/llvm-project/commit/ec18b92815dfadb080a8dff39914eb113b55cacf
DIFF: https://github.com/llvm/llvm-project/commit/ec18b92815dfadb080a8dff39914eb113b55cacf.diff
LOG: [CIR][NEON] Add lowering for `vnegd_s64` and `vnegh_f16` (#180597)
Add CIR lowering support for the non-overloaded NEON intrinsics
`vnegd_s64` and `vnegh_f16`.
The associated tests are shared with the existing default codegen tests:
* `neon-intrinsics.c` → `neon/intrinsics.c`
* `v8.2a-fp16-intrinsics.c` → `neon/fullfp16.c`
A new test file,
* `clang/test/CodeGen/AArch64/neon/fullfp16.c`
is introduced and is intended to eventually replace:
* `clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c`
Since both intrinsics are non-overloaded, the CIR and default codegen
handling is moved to the appropriate switch statements. The previous
placement was incorrect.
This change also includes minor refactoring in `CIRGenBuilder.h` to
better group related hooks.
Added:
clang/test/CodeGen/AArch64/neon/fullfp16.c
Modified:
clang/lib/CIR/CodeGen/CIRGenBuilder.h
clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
clang/lib/CodeGen/TargetBuiltins/ARM.cpp
clang/test/CodeGen/AArch64/neon-intrinsics.c
clang/test/CodeGen/AArch64/neon/intrinsics.c
clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 99a8152e7d365..c262f5dc3d812 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -362,6 +362,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return getConstantInt(loc, getUInt64Ty(), c);
}
+ //
+ // UnaryOp creation helpers
+ // -------------------------
+ //
mlir::Value createNeg(mlir::Value value) {
if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
@@ -375,6 +379,18 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
llvm_unreachable("negation for the given type is NYI");
}
+ mlir::Value createFNeg(mlir::Value value) {
+ assert(mlir::isa<cir::FPTypeInterface>(value.getType()) &&
+ "Non-fp input type!");
+
+ assert(!cir::MissingFeatures::metaDataNode());
+ assert(!cir::MissingFeatures::fpConstraints());
+ assert(!cir::MissingFeatures::fastMathFlags());
+
+ return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
+ cir::UnaryOpKind::Minus, value);
+ }
+
cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
cir::FPClassTest flags) {
return cir::IsFPClassOp::create(*this, loc, src, flags);
@@ -414,6 +430,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::BinOp::create(*this, loc, cir::BinOpKind::Add, lhs, rhs);
}
+
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
assert(!cir::MissingFeatures::metaDataNode());
assert(!cir::MissingFeatures::fpConstraints());
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index ae0aa8b7f733f..71cf896aede10 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -1446,6 +1446,18 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vcged_s64:
case NEON::BI__builtin_neon_vcled_u64:
case NEON::BI__builtin_neon_vcled_s64:
+ cgm.errorNYI(expr->getSourceRange(),
+ std::string("unimplemented AArch64 builtin call: ") +
+ getContext().BuiltinInfo.getName(builtinID));
+ return mlir::Value{};
+ case NEON::BI__builtin_neon_vnegd_s64: {
+ ops.push_back(emitScalarExpr(expr->getArg(0)));
+ return builder.createNeg(ops[0]);
+ }
+ case NEON::BI__builtin_neon_vnegh_f16: {
+ ops.push_back(emitScalarExpr(expr->getArg(0)));
+ return builder.createFNeg(ops[0]);
+ }
case NEON::BI__builtin_neon_vtstd_s64:
case NEON::BI__builtin_neon_vtstd_u64:
case NEON::BI__builtin_neon_vset_lane_i8:
@@ -1706,8 +1718,6 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vmulxh_laneq_f16:
case NEON::BI__builtin_neon_vmul_lane_v:
case NEON::BI__builtin_neon_vmul_laneq_v:
- case NEON::BI__builtin_neon_vnegd_s64:
- case NEON::BI__builtin_neon_vnegh_f16:
case NEON::BI__builtin_neon_vpmaxnm_v:
case NEON::BI__builtin_neon_vpmaxnmq_v:
case NEON::BI__builtin_neon_vpminnm_v:
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index 4fa803371d8db..06538756b91a8 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -6297,6 +6297,10 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateICmp(P, Ops[0], Ops[1]);
return Builder.CreateSExt(Ops[0], Int64Ty, "vceqd");
}
+ case NEON::BI__builtin_neon_vnegd_s64:
+ return Builder.CreateNeg(EmitScalarExpr(E->getArg(0)), "vnegd");
+ case NEON::BI__builtin_neon_vnegh_f16:
+ return Builder.CreateFNeg(EmitScalarExpr(E->getArg(0)), "vnegh");
case NEON::BI__builtin_neon_vtstd_s64:
case NEON::BI__builtin_neon_vtstd_u64: {
Ops.push_back(EmitScalarExpr(E->getArg(1)));
@@ -7168,10 +7172,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Value *Result = Builder.CreateFMul(Ops[0], Ops[1]);
return Builder.CreateBitCast(Result, Ty);
}
- case NEON::BI__builtin_neon_vnegd_s64:
- return Builder.CreateNeg(EmitScalarExpr(E->getArg(0)), "vnegd");
- case NEON::BI__builtin_neon_vnegh_f16:
- return Builder.CreateFNeg(EmitScalarExpr(E->getArg(0)), "vnegh");
case NEON::BI__builtin_neon_vpmaxnm_v:
case NEON::BI__builtin_neon_vpmaxnmq_v: {
Int = Intrinsic::aarch64_neon_fmaxnmp;
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index 3fc299b926009..42799d27bba89 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -17463,16 +17463,6 @@ int64_t test_vqabsd_s64(int64_t a) {
return (int64_t)vqabsd_s64(a);
}
-// CHECK-LABEL: define dso_local i64 @test_vnegd_s64(
-// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[VNEGD_I:%.*]] = sub i64 0, [[A]]
-// CHECK-NEXT: ret i64 [[VNEGD_I]]
-//
-int64_t test_vnegd_s64(int64_t a) {
- return (int64_t)vnegd_s64(a);
-}
-
// CHECK-LABEL: define dso_local i8 @test_vqnegb_s8(
// CHECK-SAME: i8 noundef [[A:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon/fullfp16.c b/clang/test/CodeGen/AArch64/neon/fullfp16.c
new file mode 100644
index 0000000000000..b4aca52372bf7
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/neon/fullfp16.c
@@ -0,0 +1,42 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +fullfp16 -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg | FileCheck %s --check-prefixes=ALL,LLVM
+// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +fullfp16 -disable-O0-optnone -fclangir -emit-llvm -o - %s | opt -S -passes=mem2reg,simplifycfg | FileCheck %s --check-prefixes=ALL,LLVM %}
+// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +fullfp16 -disable-O0-optnone -fclangir -emit-cir -o - %s | FileCheck %s --check-prefixes=ALL,CIR %}
+
+//=============================================================================
+// NOTES
+//
+// Tests for unconstrained intrinsics that require the fullfp16 extension.
+//
+// These intrinsics expand to code containing multiple compound and declaration
+// statements rather than just plain function calls, which leads to:
+// * "scopes" at the CIR level, and then
+// * redundant branches at the LLVM IR level.
+// The default lowering path never generates those redundant LLVM IR branches,
+// hence for CIR we use `opt -passes=simplifycfg` to reduce the control flow
+// and to make LLVM IR match for all paths.
+//
+// Minor
diff erences between RUN lines (e.g., the presence of `noundef` on
+// arguments or the `align` attribute on pointers) are matched using
+// catch-alls such as `{{.*}}`.
+//
+// TODO: Remove `-simplifycfg` once CIR lowering includes the relevant
+// optimizations to reduce the CFG.
+//
+// TODO: Merge this file with
+// * clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
+// (the source of these tests).
+//=============================================================================
+
+#include <arm_fp16.h>
+
+// ALL-LABEL: @test_vnegh_f16
+float16_t test_vnegh_f16(float16_t a) {
+// CIR: cir.unary(minus, {{.*}}) : !cir.f16
+
+// LLVM-SAME: half{{.*}} [[A:%.*]])
+// LLVM: [[NEG:%.*]] = fneg half [[A:%.*]]
+// LLVM: ret half [[NEG]]
+ return vnegh_f16(a);
+}
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index 6d0b25e6a66b7..039a08c23852e 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -31,3 +31,14 @@ uint64_t test_vceqzd_s64(int64_t a) {
// LLVM-NEXT: ret i64 [[VCEQZ_I]]
return (uint64_t)vceqzd_s64(a);
}
+
+// LLVM-LABEL: @test_vnegd_s64
+// CIR-LABEL: @vnegd_s64
+int64_t test_vnegd_s64(int64_t a) {
+// CIR: cir.unary(minus, {{.*}}) : !s64
+
+// LLVM-SAME: i64{{.*}} [[A:%.*]])
+// LLVM: [[VNEGD_I:%.*]] = sub i64 0, [[A]]
+// LLVM-NEXT: ret i64 [[VNEGD_I]]
+ return (int64_t)vnegd_s64(a);
+}
diff --git a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
index c3bbd5a43398a..a4d544d26ae27 100644
--- a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
@@ -306,13 +306,6 @@ uint64_t test_vcvtph_u64_f16 (float16_t a) {
return vcvtph_u64_f16(a);
}
-// CHECK-LABEL: test_vnegh_f16
-// CHECK: [[NEG:%.*]] = fneg half %a
-// CHECK: ret half [[NEG]]
-float16_t test_vnegh_f16(float16_t a) {
- return vnegh_f16(a);
-}
-
// CHECK-LABEL: test_vrecpeh_f16
// CHECK: [[VREC:%.*]] = call half @llvm.aarch64.neon.frecpe.f16(half %a)
// CHECK: ret half [[VREC]]
More information about the cfe-commits
mailing list