[clang] [CIR][AArch64] Implement vqshrun_n NEON builtin (PR #195080)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 30 06:00:12 PDT 2026


https://github.com/IAmCheese1231 created https://github.com/llvm/llvm-project/pull/195080

This patch adds CIR lowering support for the AArch64 NEON builtin vqsrhun. Carries over most changes from original PR, plus addresses the feedback. The builtin is lowers to the corresponding LLVM intrinsic using emitNeonCall.

Important tests:

- correctly constructs the wide input vector type
- handles vector width
- it bitcasts CIR values to match intrinsic expectations
- uses the proper argument types
Changes:
- added vqshrun.c in clang/test/CodeGen/AArch64/neon/
- verified IR and CIR lowering matches
- updated with existing test patterns (target guards, run lines, filecheck usage)

>From bc97a2d505fd912ac920c5265d9a6a8a0c8d3981 Mon Sep 17 00:00:00 2001
From: IAmCheese1231 <ezhang2 at andrew.cmu.edu>
Date: Thu, 23 Apr 2026 22:01:56 -0400
Subject: [PATCH] [CIR][AArch64] Implement vqshrun_n NEON builtin

---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  | 27 ++++++++++++-
 clang/test/CodeGen/AArch64/neon/vqshrun.c     | 40 +++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/AArch64/neon/vqshrun.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 834f66586833b..9717843c223b3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2594,7 +2594,32 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
   case NEON::BI__builtin_neon_vrecpss_f32:
   case NEON::BI__builtin_neon_vrecpsd_f64:
   case NEON::BI__builtin_neon_vrecpsh_f16:
-  case NEON::BI__builtin_neon_vqshrun_n_v:
+  case NEON::BI__builtin_neon_vqshrun_n_v: {
+    mlir::Type inputTy;
+
+    switch (type.getEltType()) {
+    case NeonTypeFlags::Int8:
+      inputTy = getNeonType(
+          this, NeonTypeFlags(NeonTypeFlags::Int16, false, true), loc);
+      break;
+    case NeonTypeFlags::Int16:
+      inputTy = getNeonType(
+          this, NeonTypeFlags(NeonTypeFlags::Int32, false, true), loc);
+      break;
+    case NeonTypeFlags::Int32:
+      inputTy = getNeonType(
+          this, NeonTypeFlags(NeonTypeFlags::Int64, false, true), loc);
+      break;
+    default:
+      llvm_unreachable("unexpected vqshrun element type");
+    }
+
+    auto shiftTy = ops[1].getType();
+    ops[0] = builder.createBitcast(loc, ops[0], inputTy);
+
+    intrName = "aarch64.neon.sqshrun";
+    return emitNeonCall(cgm, builder, {inputTy, shiftTy}, ops, intrName, ty, loc);
+  }
   case NEON::BI__builtin_neon_vqrshrun_n_v:
   case NEON::BI__builtin_neon_vqshrn_n_v:
   case NEON::BI__builtin_neon_vrshrn_n_v:
diff --git a/clang/test/CodeGen/AArch64/neon/vqshrun.c b/clang/test/CodeGen/AArch64/neon/vqshrun.c
new file mode 100644
index 0000000000000..04cb61df1987e
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/neon/vqshrun.c
@@ -0,0 +1,40 @@
+// REQUIRES: aarch64-registered-target || arm-registered-target
+
+// RUN:                   %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -flax-vector-conversions=none           -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa,simplifycfg | FileCheck %s --check-prefixes=LLVM
+// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -flax-vector-conversions=none -fclangir -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa,simplifycfg | FileCheck %s --check-prefixes=LLVM %}
+// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -flax-vector-conversions=none -fclangir -emit-cir  -o - %s |                               FileCheck %s --check-prefixes=CIR %}
+
+#include <arm_neon.h>
+
+// LLVM-LABEL: @test_vqshrun_n_s16(
+// CIR-LABEL: @test_vqshrun_n_s16(
+uint8x8_t test_vqshrun_n_s16(int16x8_t a) {
+// CIR:      cir.call_llvm_intrinsic "aarch64.neon.sqshrun" {{.*}} : (!cir.vector<8 x !s16i>, !s32i) -> !cir.vector<8 x !u8i>
+
+// LLVM-SAME: <8 x i16> {{.*}} [[A:%.*]]) {{.*}} {
+// LLVM:      [[R:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshrun.v8i8(<8 x i16> {{.*}}, i32 3)
+// LLVM-NEXT: ret <8 x i8> [[R]]
+  return vqshrun_n_s16(a, 3);
+}
+
+// LLVM-LABEL: @test_vqshrun_n_s32(
+// CIR-LABEL: @test_vqshrun_n_s32(
+uint16x4_t test_vqshrun_n_s32(int32x4_t a) {
+// CIR:      cir.call_llvm_intrinsic "aarch64.neon.sqshrun" {{.*}} : (!cir.vector<4 x !s32i>, !s32i) -> !cir.vector<4 x !u16i>
+
+// LLVM-SAME: <4 x i32> {{.*}} [[A:%.*]]) {{.*}} {
+// LLVM:      [[R:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshrun.v4i16(<4 x i32> {{.*}}, i32 9)
+// LLVM-NEXT: ret <4 x i16> [[R]]
+  return vqshrun_n_s32(a, 9);
+}
+
+// LLVM-LABEL: @test_vqshrun_n_s64(
+// CIR-LABEL: @test_vqshrun_n_s64(
+uint32x2_t test_vqshrun_n_s64(int64x2_t a) {
+// CIR:      cir.call_llvm_intrinsic "aarch64.neon.sqshrun" {{.*}} : (!cir.vector<2 x !s64i>, !s32i) -> !cir.vector<2 x !u32i>
+
+// LLVM-SAME: <2 x i64> {{.*}} [[A:%.*]]) {{.*}} {
+// LLVM:      [[R:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshrun.v2i32(<2 x i64> {{.*}}, i32 19)
+// LLVM-NEXT: ret <2 x i32> [[R]]
+  return vqshrun_n_s64(a, 19);
+}



More information about the cfe-commits mailing list