[clang] [CIR][AArch64] Add support for the remaining `vceqz` builtins (PR #185440)

via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 9 08:06:26 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Andrzej WarzyƄski (banach-space)

<details>
<summary>Changes</summary>

Implement the remaining CIR lowerings for the AdvSIMD (Neon)
`vceqz` intrinsic group (bitwise equal to zero).

Most variants of `vceqz` variant were already supported; this patch
completes the rest of the group [1] that was left as a TODO.

Tests for these intrinsics are moved from:
  * test/CodeGen/AArch64/neon_intrinsics.c
  * test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c

to:
  * test/CodeGen/AArch64/neon/intrinsics.c
  * test/CodeGen/AArch64/neon/fullfp16,

respectively.

The implementation largely mirrors the existing lowering in
CodeGen/TargetBuiltins/ARM.cpp.

Reference:
[1] https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#bitwise-equal-to-zero


---
Full diff: https://github.com/llvm/llvm-project/pull/185440.diff


6 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp (+8-4) 
- (modified) clang/lib/CodeGen/TargetBuiltins/ARM.cpp (+3-4) 
- (modified) clang/test/CodeGen/AArch64/neon-intrinsics.c (-33) 
- (modified) clang/test/CodeGen/AArch64/neon/fullfp16.c (+20) 
- (modified) clang/test/CodeGen/AArch64/neon/intrinsics.c (+45-2) 
- (modified) clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c (-8) 


``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index ea215985f3032..0a6d2a7ee3ea8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2296,12 +2296,12 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
                      getContext().BuiltinInfo.getName(builtinID));
     return mlir::Value{};
   case NEON::BI__builtin_neon_vceqzd_s64:
-    return emitAArch64CompareBuiltinExpr(
-        *this, builder, loc, ops[0],
-        convertType(expr->getCallReturnType(getContext())), cir::CmpOpKind::eq);
   case NEON::BI__builtin_neon_vceqzd_f64:
   case NEON::BI__builtin_neon_vceqzs_f32:
   case NEON::BI__builtin_neon_vceqzh_f16:
+    return emitAArch64CompareBuiltinExpr(
+        *this, builder, loc, ops[0],
+        convertType(expr->getCallReturnType(getContext())), cir::CmpOpKind::eq);
   case NEON::BI__builtin_neon_vcgezd_s64:
   case NEON::BI__builtin_neon_vcgezd_f64:
   case NEON::BI__builtin_neon_vcgezs_f32:
@@ -2318,7 +2318,11 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vcltzd_f64:
   case NEON::BI__builtin_neon_vcltzs_f32:
   case NEON::BI__builtin_neon_vcltzh_f16:
-  case NEON::BI__builtin_neon_vceqzd_u64:
+  case NEON::BI__builtin_neon_vceqzd_u64: {
+    return emitAArch64CompareBuiltinExpr(
+        *this, builder, loc, ops[0],
+        convertType(expr->getCallReturnType(getContext())), cir::CmpOpKind::eq);
+  }
   case NEON::BI__builtin_neon_vceqd_f64:
   case NEON::BI__builtin_neon_vcled_f64:
   case NEON::BI__builtin_neon_vcltd_f64:
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index cdee440a5c60e..ccb9602e2a583 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -6212,10 +6212,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
         ICmpInst::FCMP_OLT, "vcltz");
 
   case NEON::BI__builtin_neon_vceqzd_u64: {
-    Ops[0] = Builder.CreateBitCast(Ops[0], Int64Ty);
-    Ops[0] =
-        Builder.CreateICmpEQ(Ops[0], llvm::Constant::getNullValue(Int64Ty));
-    return Builder.CreateSExt(Ops[0], Int64Ty, "vceqzd");
+    return EmitAArch64CompareBuiltinExpr(
+        Ops[0], ConvertType(E->getCallReturnType(getContext())),
+        ICmpInst::ICMP_EQ, "vceqzd");
   }
   case NEON::BI__builtin_neon_vceqd_f64:
   case NEON::BI__builtin_neon_vcled_f64:
diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c
index 33b0b6bc55426..f251551dc2217 100644
--- a/clang/test/CodeGen/AArch64/neon-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c
@@ -16878,17 +16878,6 @@ uint64_t test_vceqd_u64(uint64_t a, uint64_t b) {
   return (int64_t)vceqd_u64(a, b);
 }
 
-// CHECK-LABEL: define dso_local i64 @test_vceqzd_u64(
-// CHECK-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i64 [[A]], 0
-// CHECK-NEXT:    [[VCEQZD_I:%.*]] = sext i1 [[TMP0]] to i64
-// CHECK-NEXT:    ret i64 [[VCEQZD_I]]
-//
-int64_t test_vceqzd_u64(int64_t a) {
-  return (int64_t)vceqzd_u64(a);
-}
-
 // CHECK-LABEL: define dso_local i64 @test_vcged_s64(
 // CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
@@ -17432,28 +17421,6 @@ uint64_t test_vceqd_f64(float64_t a, float64_t b) {
   return (uint64_t)vceqd_f64(a, b);
 }
 
-// CHECK-LABEL: define dso_local i32 @test_vceqzs_f32(
-// CHECK-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = fcmp oeq float [[A]], 0.000000e+00
-// CHECK-NEXT:    [[VCEQZ_I:%.*]] = sext i1 [[TMP0]] to i32
-// CHECK-NEXT:    ret i32 [[VCEQZ_I]]
-//
-uint32_t test_vceqzs_f32(float32_t a) {
-  return (uint32_t)vceqzs_f32(a);
-}
-
-// CHECK-LABEL: define dso_local i64 @test_vceqzd_f64(
-// CHECK-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT:  [[ENTRY:.*:]]
-// CHECK-NEXT:    [[TMP0:%.*]] = fcmp oeq double [[A]], 0.000000e+00
-// CHECK-NEXT:    [[VCEQZ_I:%.*]] = sext i1 [[TMP0]] to i64
-// CHECK-NEXT:    ret i64 [[VCEQZ_I]]
-//
-uint64_t test_vceqzd_f64(float64_t a) {
-  return (uint64_t)vceqzd_f64(a);
-}
-
 // CHECK-LABEL: define dso_local i32 @test_vcges_f32(
 // CHECK-SAME: float noundef [[A:%.*]], float noundef [[B:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
diff --git a/clang/test/CodeGen/AArch64/neon/fullfp16.c b/clang/test/CodeGen/AArch64/neon/fullfp16.c
index 3cac22ee5ad54..2cb1487e4569d 100644
--- a/clang/test/CodeGen/AArch64/neon/fullfp16.c
+++ b/clang/test/CodeGen/AArch64/neon/fullfp16.c
@@ -24,12 +24,32 @@
 // hence for CIR we use `opt -passes=simplifycfg` to reduce the control flow
 // and to make LLVM IR match for all paths.
 //
+// ACLE section headings based on v2025Q2 of the ACLE specification:
+//  * https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#bitwise-equal-to-zero
+//
 // TODO: Remove `-simplifycfg` once CIR lowering includes the relevant
 //       optimizations to reduce the CFG.
 //=============================================================================
 
 #include <arm_fp16.h>
 
+//===------------------------------------------------------===//
+// 2.5.2.1.  Bitwise equal to zero
+//===------------------------------------------------------===//
+// LLVM-LABEL: test_vceqzh_f16
+uint16_t test_vceqzh_f16(float16_t a) {
+// CIR:   [[C_0:%.*]] = cir.const #cir.fp<0.000000e+00>
+// CIR:   [[CMP:%.*]] = cir.cmp(eq, %{{.*}}, [[C_0]]) : !cir.f16, !cir.bool
+// CIR:   [[RES:%.*]] = cir.cast bool_to_int [[CMP]] : !cir.bool -> !cir.int<s, 1>
+// CIR:   cir.cast integral [[RES]] : !cir.int<s, 1> -> !u16i
+
+// LLVM-SAME: (half {{.*}} [[A:%.*]])
+// LLVM:  [[TMP1:%.*]] = fcmp oeq half [[A]], 0xH0000
+// LLVM:  [[TMP2:%.*]] = sext i1 [[TMP1]] to i16
+// LLVM:  ret i16 [[TMP2]]
+  return vceqzh_f16(a);
+}
+
 // ALL-LABEL: @test_vabsh_f16
 float16_t test_vabsh_f16(float16_t a) {
 // CIR: {{%.*}} = cir.fabs {{%.*}} : !cir.f16
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index 47d2a58afb550..a730c979b9aa6 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -412,8 +412,51 @@ uint64_t test_vceqzd_s64(int64_t a) {
   return (uint64_t)vceqzd_s64(a);
 }
 
-// TODO SISD variants:
-// vceqzd_u64, vceqzs_f32, vceqzd_f64
+// LLVM-LABEL: @test_vceqzd_u64(
+// CIR-LABEL: @vceqzd_u64(
+int64_t test_vceqzd_u64(int64_t a) {
+// CIR:   [[C_0:%.*]] = cir.const #cir.int<0>
+// CIR:   [[CMP:%.*]] = cir.cmp(eq, %{{.*}}, [[C_0]]) : !u64i, !cir.bool
+// CIR:   [[RES:%.*]] = cir.cast bool_to_int [[CMP]] : !cir.bool -> !cir.int<s, 1>
+// CIR:   cir.cast integral [[RES]] : !cir.int<s, 1> -> !u64i
+
+// LLVM-SAME: i64 {{.*}} [[A:%.*]])
+// LLVM:    [[TMP0:%.*]] = icmp eq i64 [[A]], 0
+// LLVM-NEXT:    [[VCEQZD_I:%.*]] = sext i1 [[TMP0]] to i64
+// LLVM-NEXT:    ret i64 [[VCEQZD_I]]
+  return (int64_t)vceqzd_u64(a);
+}
+
+// LLVM-LABEL: @test_vceqzs_f32(
+// CIR-LABEL: @vceqzs_f32(
+uint32_t test_vceqzs_f32(float32_t a) {
+// CIR:   [[C_0:%.*]] = cir.const #cir.fp<0.000000e+00>
+// CIR:   [[CMP:%.*]] = cir.cmp(eq, %{{.*}}, [[C_0]]) : !cir.float, !cir.bool
+// CIR:   [[RES:%.*]] = cir.cast bool_to_int [[CMP]] : !cir.bool -> !cir.int<s, 1>
+// CIR:   cir.cast integral [[RES]] : !cir.int<s, 1> -> !u32i
+
+// LLVM-SAME: float {{.*}} [[A:%.*]])
+// LLVM:    [[TMP0:%.*]] = fcmp oeq float [[A]], 0.000000e+00
+// LLVM-NEXT:    [[VCEQZ_I:%.*]] = sext i1 [[TMP0]] to i32
+// LLVM-NEXT:    ret i32 [[VCEQZ_I]]
+  return (uint32_t)vceqzs_f32(a);
+}
+
+// LLVM-LABEL: @test_vceqzd_f64(
+// CIR-LABEL: @vceqzd_f64(
+uint64_t test_vceqzd_f64(float64_t a) {
+// CIR:   [[C_0:%.*]] = cir.const #cir.fp<0.000000e+00>
+// CIR:   [[CMP:%.*]] = cir.cmp(eq, %{{.*}}, [[C_0]]) : !cir.double, !cir.bool
+// CIR:   [[RES:%.*]] = cir.cast bool_to_int [[CMP]] : !cir.bool -> !cir.int<s, 1>
+// CIR:   cir.cast integral [[RES]] : !cir.int<s, 1> -> !u64i
+
+
+// LLVM-SAME: double {{.*}} [[A:%.*]])
+// LLVM:    [[TMP0:%.*]] = fcmp oeq double [[A]], 0.000000e+00
+// LLVM-NEXT:    [[VCEQZ_I:%.*]] = sext i1 [[TMP0]] to i64
+// LLVM-NEXT:    ret i64 [[VCEQZ_I]]
+  return (uint64_t)vceqzd_f64(a);
+}
 
 
 //===------------------------------------------------------===//
diff --git a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
index 080e2351ff1e7..c80d9e9d7f759 100644
--- a/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
+++ b/clang/test/CodeGen/AArch64/v8.2a-fp16-intrinsics.c
@@ -7,14 +7,6 @@
 
 #include <arm_fp16.h>
 
-// CHECK-LABEL: test_vceqzh_f16
-// CHECK:  [[TMP1:%.*]] = fcmp oeq half %a, 0xH0000
-// CHECK:  [[TMP2:%.*]] = sext i1 [[TMP1]] to i16
-// CHECK:  ret i16 [[TMP2]]
-uint16_t test_vceqzh_f16(float16_t a) {
-  return vceqzh_f16(a);
-}
-
 // CHECK-LABEL: test_vcgezh_f16
 // CHECK:  [[TMP1:%.*]] = fcmp oge half %a, 0xH0000
 // CHECK:  [[TMP2:%.*]] = sext i1 [[TMP1]] to i16

``````````

</details>


https://github.com/llvm/llvm-project/pull/185440


More information about the cfe-commits mailing list