[clang] [Clang][CIR] Add vqshlud and vqshld AArch64 builtins (PR #190728)
Kartik Ohlan via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 17 12:26:16 PDT 2026
https://github.com/Ko496-glitch updated https://github.com/llvm/llvm-project/pull/190728
>From d03d70432915e3513200f66ea7e2031ba0d12b1c Mon Sep 17 00:00:00 2001
From: kartikohlan <kartik7ohlan at gmail.com>
Date: Tue, 7 Apr 2026 00:20:16 -0400
Subject: [PATCH 1/3] [Clang][CIR] Add vqshlud and vqshld AArch64 builtins
---
.../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 23 +++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 3a9e7e2650500..c54781ea21464 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2177,9 +2177,28 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vsubd_u64:
case NEON::BI__builtin_neon_vqdmlalh_s16:
case NEON::BI__builtin_neon_vqdmlslh_s16:
- case NEON::BI__builtin_neon_vqshlud_n_s64:
+ case NEON::BI__builtin_neon_vqshlud_n_s64: {
+ cir::IntType intType = builder.getSInt64Ty();
+ std::optional<llvm::APSInt> amt =
+ expr->getArg(1)->getIntegerConstantExpr(getContext());
+ assert(amt && "Expected argument to be a constant");
+ ops[1] = builder.getSInt64(amt->getZExtValue(), loc);
+ return emitNeonCall(cgm, builder, {intType, intType}, ops,
+ "aarch64.neon.sqshlu", convertType(expr->getType()),
+ loc);
+ }
case NEON::BI__builtin_neon_vqshld_n_u64:
- case NEON::BI__builtin_neon_vqshld_n_s64:
+ case NEON::BI__builtin_neon_vqshld_n_s64: {
+ cir::IntType intType = builtinID == NEON::BI__builtin_neon_vqshld_n_u64
+ ? builder.getUInt64Ty()
+ : builder.getSInt64Ty();
+ llvm::StringRef intrinsicName =
+ builtinID == NEON::BI__builtin_neon_vqshld_n_u64 ? "aarch64.neon.uqshl"
+ : "aarch64.neon.sqshl";
+ ops[1] = builder.createIntCast(ops[1], intType);
+ return emitNeonCall(cgm, builder, {intType, intType}, ops, intrinsicName,
+ convertType(expr->getType()), loc);
+ }
case NEON::BI__builtin_neon_vrshrd_n_u64:
case NEON::BI__builtin_neon_vrshrd_n_s64:
case NEON::BI__builtin_neon_vrsrad_n_u64:
>From 9b66ee9a877f824b45b107b372bac76951525fd2 Mon Sep 17 00:00:00 2001
From: kartikohlan <kartik7ohlan at gmail.com>
Date: Tue, 7 Apr 2026 12:45:28 -0400
Subject: [PATCH 2/3] refactored to use lower ICE arguement
---
.../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 5 +-
.../CodeGen/AArch64/neon/vector-sat-left.c | 81 +++++++++++++++++++
2 files changed, 82 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGen/AArch64/neon/vector-sat-left.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index c54781ea21464..60ac79c514350 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2179,10 +2179,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
case NEON::BI__builtin_neon_vqdmlslh_s16:
case NEON::BI__builtin_neon_vqshlud_n_s64: {
cir::IntType intType = builder.getSInt64Ty();
- std::optional<llvm::APSInt> amt =
- expr->getArg(1)->getIntegerConstantExpr(getContext());
- assert(amt && "Expected argument to be a constant");
- ops[1] = builder.getSInt64(amt->getZExtValue(), loc);
+ ops[1] = builder.getSInt64(getZExtIntValueFromConstOp(ops[1]), loc);
return emitNeonCall(cgm, builder, {intType, intType}, ops,
"aarch64.neon.sqshlu", convertType(expr->getType()),
loc);
diff --git a/clang/test/CodeGen/AArch64/neon/vector-sat-left.c b/clang/test/CodeGen/AArch64/neon/vector-sat-left.c
new file mode 100644
index 0000000000000..8759346136117
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/neon/vector-sat-left.c
@@ -0,0 +1,81 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=LLVM
+#include<arm_neon.h>
+
+
+// LLVM-LABEL: define dso_local i64 @test_vqshlud_n_s64(
+// LLVM-SAME: i64 noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// LLVM-NEXT: [[ENTRY:.*:]]
+// LLVM-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__RET:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__S0:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[REF_TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8
+// LLVM-NEXT: [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// LLVM-NEXT: store i64 [[TMP0]], ptr [[__S0]], align 8
+// LLVM-NEXT: [[TMP1:%.*]] = load i64, ptr [[__S0]], align 8
+// LLVM-NEXT: [[VQSHLU_N:%.*]] = call i64 @llvm.aarch64.neon.sqshlu.i64(i64 [[TMP1]], i64 1)
+// LLVM-NEXT: store i64 [[VQSHLU_N]], ptr [[REF_TMP]], align 8
+// LLVM-NEXT: [[TMP2:%.*]] = load i64, ptr [[REF_TMP]], align 8
+// LLVM-NEXT: store i64 [[TMP2]], ptr [[__RET]], align 8
+// LLVM-NEXT: [[TMP3:%.*]] = load i64, ptr [[__RET]], align 8
+// LLVM-NEXT: store i64 [[TMP3]], ptr [[TMP]], align 8
+// LLVM-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP]], align 8
+// LLVM-NEXT: ret i64 [[TMP4]]
+//
+int64_t test_vqshlud_n_s64(int64_t a) {
+ return vqshlud_n_s64(a, 1);
+}
+
+// LLVM-LABEL: define dso_local i64 @test_vqshld_n_s64(
+// LLVM-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
+// LLVM-NEXT: [[ENTRY:.*:]]
+// LLVM-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__RET:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__S0:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[REF_TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8
+// LLVM-NEXT: [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// LLVM-NEXT: store i64 [[TMP0]], ptr [[__S0]], align 8
+// LLVM-NEXT: [[TMP1:%.*]] = load i64, ptr [[__S0]], align 8
+// LLVM-NEXT: [[VQSHL_N:%.*]] = call i64 @llvm.aarch64.neon.sqshl.i64(i64 [[TMP1]], i64 1)
+// LLVM-NEXT: store i64 [[VQSHL_N]], ptr [[REF_TMP]], align 8
+// LLVM-NEXT: [[TMP2:%.*]] = load i64, ptr [[REF_TMP]], align 8
+// LLVM-NEXT: store i64 [[TMP2]], ptr [[__RET]], align 8
+// LLVM-NEXT: [[TMP3:%.*]] = load i64, ptr [[__RET]], align 8
+// LLVM-NEXT: store i64 [[TMP3]], ptr [[TMP]], align 8
+// LLVM-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP]], align 8
+// LLVM-NEXT: ret i64 [[TMP4]]
+//
+int64_t test_vqshld_n_s64(int64_t a) {
+ return vqshld_n_s64(a, 1);
+}
+
+// LLVM-LABEL: define dso_local i64 @test_vqshld_n_u64(
+// LLVM-SAME: i64 noundef [[A:%.*]]) #[[ATTR0]] {
+// LLVM-NEXT: [[ENTRY:.*:]]
+// LLVM-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__RET:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[__S0:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[REF_TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: [[TMP:%.*]] = alloca i64, align 8
+// LLVM-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8
+// LLVM-NEXT: [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// LLVM-NEXT: store i64 [[TMP0]], ptr [[__S0]], align 8
+// LLVM-NEXT: [[TMP1:%.*]] = load i64, ptr [[__S0]], align 8
+// LLVM-NEXT: [[VQSHL_N:%.*]] = call i64 @llvm.aarch64.neon.uqshl.i64(i64 [[TMP1]], i64 1)
+// LLVM-NEXT: store i64 [[VQSHL_N]], ptr [[REF_TMP]], align 8
+// LLVM-NEXT: [[TMP2:%.*]] = load i64, ptr [[REF_TMP]], align 8
+// LLVM-NEXT: store i64 [[TMP2]], ptr [[__RET]], align 8
+// LLVM-NEXT: [[TMP3:%.*]] = load i64, ptr [[__RET]], align 8
+// LLVM-NEXT: store i64 [[TMP3]], ptr [[TMP]], align 8
+// LLVM-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP]], align 8
+// LLVM-NEXT: ret i64 [[TMP4]]
+//
+uint64_t test_vqshld_n_u64(uint64_t a) {
+ return vqshld_n_u64(a, 1);
+}
>From 6901921783c42f92f60fa8080b0cc2ff8f317379 Mon Sep 17 00:00:00 2001
From: Kartik Ohlan <kartik7ohlan at gmail.com>
Date: Fri, 17 Apr 2026 15:25:47 -0400
Subject: [PATCH 3/3] Added tests to intrinsics.c
---
clang/test/CodeGen/AArch64/neon/intrinsics.c | 36 ++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c
index e2708a846edc4..5e05fc555eb9f 100644
--- a/clang/test/CodeGen/AArch64/neon/intrinsics.c
+++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c
@@ -24,6 +24,42 @@
#include <arm_neon.h>
+// LLVM-LABEL: @test_vqshlud_n_s64(
+// CIR-LABEL: @test_vqshlud_n_s64(
+int64_t test_vqshlud_n_s64(int64_t a) {
+// CIR: [[CONST:%.*]] = cir.const #cir.int<63> : !s64i
+// CIR: {{%.*}} = cir.call_llvm_intrinsic "aarch64.neon.sqshlu" {{%.*}}, [[CONST]] : (!s64i, !s64i) -> !s64i
+
+// LLVM-SAME: i64 {{.*}}[[A:%.*]])
+// LLVM: [[VQSHLU_N:%.*]] = call i64 @llvm.aarch64.neon.sqshlu.i64(i64 [[A]], i64 63)
+// LLVM: ret i64 [[VQSHLU_N]]
+ return (int64_t)vqshlud_n_s64(a, 63);
+}
+
+// LLVM-LABEL: @test_vqshld_n_u64(
+// CIR-LABEL: @test_vqshld_n_u64(
+uint64_t test_vqshld_n_u64(uint64_t a) {
+// CIR: [[CONST:%.*]] = cir.const #cir.int<63> : !u64i
+// CIR: {{%.*}} = cir.call_llvm_intrinsic "aarch64.neon.uqshl" {{%.*}}, [[CONST]] : (!u64i, !u64i) -> !u64i
+
+// LLVM-SAME: i64 {{.*}}[[A:%.*]])
+// LLVM: [[VQSHLD_N_U64:%.*]] = call i64 @llvm.aarch64.neon.uqshl.i64(i64 [[A]], i64 63)
+// LLVM: ret i64 [[VQSHLD_N_U64]]
+ return vqshld_n_u64(a, 63);
+}
+
+// LLVM-LABEL: @test_vqshld_n_s64(
+// CIR-LABEL: @test_vqshld_n_s64(
+int64_t test_vqshld_n_s64(int64_t a) {
+// CIR: [[CONST:%.*]] = cir.const #cir.int<63> : !s64i
+// CIR: {{%.*}} = cir.call_llvm_intrinsic "aarch64.neon.sqshl" {{%.*}}, [[CONST]] : (!s64i, !s64i) -> !s64i
+
+// LLVM-SAME: i64 {{.*}}[[A:%.*]])
+// LLVM: [[VQSHL_N:%.*]] = call i64 @llvm.aarch64.neon.sqshl.i64(i64 [[A]], i64 63)
+// LLVM: ret i64 [[VQSHL_N]]
+ return (int64_t)vqshld_n_s64(a, 63);
+}
+
// LLVM-LABEL: @test_vnegd_s64
// CIR-LABEL: @vnegd_s64
int64_t test_vnegd_s64(int64_t a) {
More information about the cfe-commits
mailing list