[clang] [CIR] Lowering for __builtin_reduce_add/mul (PR #224204)
Kunal Dubey via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 17 03:00:17 PDT 2026
https://github.com/xakep8 updated https://github.com/llvm/llvm-project/pull/224204
>From 422867a172ef2fbf49ef601ae0c2435720eb303f Mon Sep 17 00:00:00 2001
From: Kunal Dubey <xakep8 at protonmail.com>
Date: Thu, 17 Sep 2026 12:17:03 +0530
Subject: [PATCH 1/2] [CIR] Lowering for __builtin_reduce_add/mul
Added lowering for __builtin_reduce_add and __builtin_reduce_mul by
mimicking the same shape as __builtin_reduce_xor which mirrors classic
Codegen shape
Added test for the same
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 10 +++-
.../builtin-reduce-arithmetic.c | 49 +++++++++++++++++++
.../CodeGenBuiltins/builtin-undef-rvalue.cpp | 8 +--
3 files changed, 62 insertions(+), 5 deletions(-)
create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index e2fe3adefd4af..b0e3f0ae00ebe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2141,9 +2141,17 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_elementwise_minimumnum:
case Builtin::BI__builtin_reduce_max:
case Builtin::BI__builtin_reduce_min:
+ return errorBuiltinNYI(*this, e, builtinID);
case Builtin::BI__builtin_reduce_add:
+ return emitBuiltinWithOneOverloadedType<1>(
+ e, "vector.reduce.add",
+ cast<cir::VectorType>(convertType(e->getArg(0)->getType()))
+ .getElementType());
case Builtin::BI__builtin_reduce_mul:
- return errorBuiltinNYI(*this, e, builtinID);
+ return emitBuiltinWithOneOverloadedType<1>(
+ e, "vector.reduce.mul",
+ cast<cir::VectorType>(convertType(e->getArg(0)->getType()))
+ .getElementType());
case Builtin::BI__builtin_reduce_xor:
return emitBuiltinWithOneOverloadedType<1>(
e, "vector.reduce.xor",
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
new file mode 100644
index 0000000000000..271aaecf5e0a8
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+typedef int v4si __attribute__((vector_size(16)));
+typedef unsigned int v4su __attribute__((vector_size(16)));
+
+int test_reduce_add(v4si x) {
+ // CIR-LABEL: @test_reduce_add
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.add"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_add
+ // LLVM: call i32 @llvm.vector.reduce.add.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_add(x);
+}
+
+unsigned test_reduce_add_unsigned(v4su x) {
+ // CIR-LABEL: @test_reduce_add_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.add"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_add_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.add.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_add(x);
+}
+
+int test_reduce_mul(v4si x) {
+ // CIR-LABEL: @test_reduce_mul
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.mul"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_mul
+ // LLVM: call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_mul(x);
+}
+
+unsigned test_reduce_mul_unsigned(v4su x) {
+ // CIR-LABEL: @test_reduce_mul_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.mul"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_mul_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_mul(x);
+}
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
index c15375621f08a..372eb97c323f3 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
@@ -3,11 +3,11 @@
typedef int v4si __attribute__((vector_size(16)));
-int test_builtin_reduce_add_undef_rvalue(v4si x) {
- // expected-error at +1 {{unimplemented builtin call: __builtin_reduce_add}}
- return __builtin_reduce_add(x);
+int test_builtin_reduce_max_undef_rvalue(v4si x) {
+ // expected-error at +1 {{unimplemented builtin call: __builtin_reduce_max}}
+ return __builtin_reduce_max(x);
}
-// CIR-LABEL: @_Z36test_builtin_reduce_add_undef_rvalueDv4_i
+// CIR-LABEL: @_Z36test_builtin_reduce_max_undef_rvalueDv4_i
// CIR: cir.const #cir.undef : !s32i
// CIR: cir.return
>From b0dd4a8e6361f2e4084704b3b886a71a50aa60c2 Mon Sep 17 00:00:00 2001
From: Kunal Dubey <xakep8 at protonmail.com>
Date: Thu, 17 Sep 2026 15:13:03 +0530
Subject: [PATCH 2/2] [CIR] Lowering for __builtin_reduce_max/min
Added lowering for __builtin_reduce_max and __builtin_reduce_min
matching classic CodeGen by selecting signed, unsigned and
floating-point min/max reduction intrinsics from the vector element type,
including sizeless vector types.
Added test for same.
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 31 +++++++-
.../builtin-reduce-arithmetic-sve.c | 73 +++++++++++++++++++
.../builtin-reduce-arithmetic.c | 61 ++++++++++++++++
.../CodeGenBuiltins/builtin-undef-rvalue.cpp | 12 +--
4 files changed, 169 insertions(+), 8 deletions(-)
create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic-sve.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index b0e3f0ae00ebe..ae4ce14ea47e0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2139,9 +2139,36 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_elementwise_maximumnum:
case Builtin::BI__builtin_elementwise_minimumnum:
- case Builtin::BI__builtin_reduce_max:
- case Builtin::BI__builtin_reduce_min:
return errorBuiltinNYI(*this, e, builtinID);
+ case Builtin::BI__builtin_reduce_max:
+ case Builtin::BI__builtin_reduce_min: {
+ auto getIntrinsicName = [this, builtinIDIfNoAsmLabel](QualType type) {
+ if (const auto *vecTy = type->getAs<VectorType>())
+ type = vecTy->getElementType();
+ else if (type->isSizelessVectorType())
+ type = type->getSizelessVectorEltType(getContext());
+
+ if (builtinIDIfNoAsmLabel == Builtin::BI__builtin_reduce_max) {
+ if (type->isSignedIntegerType())
+ return "vector.reduce.smax";
+ if (type->isUnsignedIntegerType())
+ return "vector.reduce.umax";
+ assert(type->isFloatingType() && "must have a float here");
+ return "vector.reduce.fmax";
+ }
+
+ if (type->isSignedIntegerType())
+ return "vector.reduce.smin";
+ if (type->isUnsignedIntegerType())
+ return "vector.reduce.umin";
+ assert(type->isFloatingType() && "must have a float here");
+ return "vector.reduce.fmin";
+ };
+ return emitBuiltinWithOneOverloadedType<1>(
+ e, getIntrinsicName(e->getArg(0)->getType()),
+ cast<cir::VectorType>(convertType(e->getArg(0)->getType()))
+ .getElementType());
+ }
case Builtin::BI__builtin_reduce_add:
return emitBuiltinWithOneOverloadedType<1>(
e, "vector.reduce.add",
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic-sve.c b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic-sve.c
new file mode 100644
index 0000000000000..6f3320ed83d53
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic-sve.c
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -target-feature +sve \
+// RUN: -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -target-feature +sve \
+// RUN: -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -target-feature +sve \
+// RUN: -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+//
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sve.h>
+
+int test_sve_reduce_max(svint32_t x) {
+ // CIR-LABEL: @test_sve_reduce_max
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.smax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_max
+ // LLVM: call i32 @llvm.vector.reduce.smax.nxv4i32(<vscale x 4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_max(x);
+}
+
+unsigned test_sve_reduce_max_unsigned(svuint32_t x) {
+ // CIR-LABEL: @test_sve_reduce_max_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.umax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_max_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.umax.nxv4i32(<vscale x 4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_max(x);
+}
+
+float test_sve_reduce_max_float(svfloat32_t x) {
+ // CIR-LABEL: @test_sve_reduce_max_float
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_max_float
+ // LLVM: call float @llvm.vector.reduce.fmax.nxv4f32(<vscale x 4 x float>
+ // LLVM: ret float
+ return __builtin_reduce_max(x);
+}
+
+int test_sve_reduce_min(svint32_t x) {
+ // CIR-LABEL: @test_sve_reduce_min
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.smin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_min
+ // LLVM: call i32 @llvm.vector.reduce.smin.nxv4i32(<vscale x 4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_min(x);
+}
+
+unsigned test_sve_reduce_min_unsigned(svuint32_t x) {
+ // CIR-LABEL: @test_sve_reduce_min_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.umin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_min_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.umin.nxv4i32(<vscale x 4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_min(x);
+}
+
+float test_sve_reduce_min_float(svfloat32_t x) {
+ // CIR-LABEL: @test_sve_reduce_min_float
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_sve_reduce_min_float
+ // LLVM: call float @llvm.vector.reduce.fmin.nxv4f32(<vscale x 4 x float>
+ // LLVM: ret float
+ return __builtin_reduce_min(x);
+}
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
index 271aaecf5e0a8..095e841ee26a2 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-reduce-arithmetic.c
@@ -7,6 +7,7 @@
typedef int v4si __attribute__((vector_size(16)));
typedef unsigned int v4su __attribute__((vector_size(16)));
+typedef float v4sf __attribute__((vector_size(16)));
int test_reduce_add(v4si x) {
// CIR-LABEL: @test_reduce_add
@@ -47,3 +48,63 @@ unsigned test_reduce_mul_unsigned(v4su x) {
// LLVM: ret i32
return __builtin_reduce_mul(x);
}
+
+int test_reduce_max(v4si x) {
+ // CIR-LABEL: @test_reduce_max
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.smax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_max
+ // LLVM: call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_max(x);
+}
+
+unsigned test_reduce_max_unsigned(v4su x) {
+ // CIR-LABEL: @test_reduce_max_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.umax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_max_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_max(x);
+}
+
+float test_reduce_max_float(v4sf x) {
+ // CIR-LABEL: @test_reduce_max_float
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_max_float
+ // LLVM: call float @llvm.vector.reduce.fmax.v4f32(<4 x float>
+ // LLVM: ret float
+ return __builtin_reduce_max(x);
+}
+
+int test_reduce_min(v4si x) {
+ // CIR-LABEL: @test_reduce_min
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.smin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_min
+ // LLVM: call i32 @llvm.vector.reduce.smin.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_min(x);
+}
+
+unsigned test_reduce_min_unsigned(v4su x) {
+ // CIR-LABEL: @test_reduce_min_unsigned
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.umin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_min_unsigned
+ // LLVM: call i32 @llvm.vector.reduce.umin.v4i32(<4 x i32>
+ // LLVM: ret i32
+ return __builtin_reduce_min(x);
+}
+
+float test_reduce_min_float(v4sf x) {
+ // CIR-LABEL: @test_reduce_min_float
+ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin"
+ // CIR: cir.return
+ // LLVM-LABEL: @test_reduce_min_float
+ // LLVM: call float @llvm.vector.reduce.fmin.v4f32(<4 x float>
+ // LLVM: ret float
+ return __builtin_reduce_min(x);
+}
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
index 372eb97c323f3..a89006deb4c8d 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -verify %s -o - > %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-typedef int v4si __attribute__((vector_size(16)));
+typedef float v4sf __attribute__((vector_size(16)));
-int test_builtin_reduce_max_undef_rvalue(v4si x) {
- // expected-error at +1 {{unimplemented builtin call: __builtin_reduce_max}}
- return __builtin_reduce_max(x);
+float test_builtin_reduce_maximum_undef_rvalue(v4sf x) {
+ // expected-error at +1 {{unimplemented builtin call: __builtin_reduce_maximum}}
+ return __builtin_reduce_maximum(x);
}
-// CIR-LABEL: @_Z36test_builtin_reduce_max_undef_rvalueDv4_i
-// CIR: cir.const #cir.undef : !s32i
+// CIR-LABEL: test_builtin_reduce_maximum_undef_rvalue
+// CIR: cir.const #cir.undef : !cir.float
// CIR: cir.return
More information about the cfe-commits
mailing list