[clang] [clang][Sema] Allow splat initialization of a sizeless vector in a C++ code (PR #205432)
Paul Osmialowski via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 24 02:14:38 PDT 2026
https://github.com/pawosm-arm updated https://github.com/llvm/llvm-project/pull/205432
>From bcdc832c392bef170c86ee2e3398f59d6ea7bcf4 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawel.osmialowski at arm.com>
Date: Tue, 23 Jun 2026 20:30:20 +0000
Subject: [PATCH] [clang][Sema] Allow splat initialization of a sizeless vector
in a C++ code
Consider the following C++ code:
```
typedef int8_t vint8x8 __attribute__((ext_vector_type(8U)));
vint8x8 vint8x8_fun(void)
{
vint8x8 vint8x8var(123);
return vint8x8var;
}
```
The `vint8x8 vi8x8(123);` initialization results in a splat operation:
```
define dso_local <8 x i8> @vint8x8_fun() #0 {
entry:
%vint8x8var = alloca <8 x i8>, align 8
store <8 x i8> splat (i8 123), ptr %vint8x8var, align 8
%0 = load <8 x i8>, ptr %vint8x8var, align 8
ret <8 x i8> %0
}
```
Unfortunately, similar C++ code with a sizeless vector type:
```
__SVInt8_t __SVInt8_t_fun(void)
{
__SVInt8_t __SVInt8_t_var(123);
return __SVInt8_t_var;
}
```
...would result in an error message like this:
```
error: cannot initialize a variable of type '__SVInt8_t' with an rvalue of type 'int'
```
This patch enables generation of the splat instead:
```
define dso_local <vscale x 16 x i8> @__SVInt8_t_fun() #0 {
entry:
%__SVInt8_t_var = alloca <vscale x 16 x i8>, align 16
store <vscale x 16 x i8> splat (i8 123), ptr %__SVInt8_t_var, align 16
%0 = load <vscale x 16 x i8>, ptr %__SVInt8_t_var, align 16
ret <vscale x 16 x i8> %0
}
```
---
clang/lib/Sema/SemaExpr.cpp | 4 +-
clang/lib/Sema/SemaInit.cpp | 20 +++++-
clang/lib/Sema/SemaOverload.cpp | 9 +++
clang/test/CodeGen/sizeless-splat-init.cpp | 81 ++++++++++++++++++++++
clang/test/SemaCXX/sizeless-1.cpp | 6 +-
5 files changed, 114 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CodeGen/sizeless-splat-init.cpp
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7c868d176e803..c7a6429cefced 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8057,7 +8057,9 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
}
ExprResult Sema::prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr) {
- QualType DestElemTy = VectorTy->castAs<VectorType>()->getElementType();
+ QualType DestElemTy = VectorTy->isSizelessVectorType()
+ ? VectorTy->getSizelessVectorEltType(Context)
+ : VectorTy->castAs<VectorType>()->getElementType();
if (DestElemTy == SplattedExpr->getType())
return SplattedExpr;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 8f685feac4beb..c00e0c6eb40ee 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -1484,8 +1484,24 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isOCLIntelSubgroupAVCType() ||
DeclType->isSizelessBuiltinType()) {
// Checks for scalar type are sufficient for these types too.
- CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
- StructuredIndex);
+ Expr *expr =
+ (Index < IList->getNumInits()) ? IList->getInit(Index) : nullptr;
+ // Prevent splat when doing list initialization.
+ if (expr && expr->getType()->isArithmeticType() &&
+ DeclType->isSizelessVectorType() &&
+ SemaRef.Context.getLangOpts().CPlusPlus) {
+ if (!VerifyOnly) {
+ PartialDiagnostic PDiag =
+ SemaRef.PDiag(diag::err_init_conversion_failed)
+ << static_cast<int>(Entity.getKind()) << DeclType
+ << expr->isLValue() << expr->getType() << expr->getSourceRange();
+ SemaRef.HandleFunctionTypeMismatch(PDiag, expr->getType(), DeclType);
+ SemaRef.Diag(expr->getBeginLoc(), PDiag);
+ }
+ hadError = true;
+ } else
+ CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
+ StructuredIndex);
} else if (DeclType->isDependentType()) {
// C++ [over.match.class.deduct]p1.5:
// brace elision is not considered for any aggregate element that has a
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c663765573612..c837641b20084 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -2203,6 +2203,15 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
ImplicitConversionKind &ICK,
ImplicitConversionKind &ElConv, Expr *From,
bool InOverloadResolution, bool CStyle) {
+ // A special treatment is needed when targeting a sizeless vector type.
+ if (ToType->isSizelessVectorType()) {
+ // Vector splat from any arithmetic type to a sizeless vector.
+ if (FromType->isArithmeticType() && S.getLangOpts().CPlusPlus) {
+ ICK = ICK_Vector_Splat;
+ return true;
+ }
+ }
+
// We need at least one of these types to be a vector type to have a vector
// conversion.
if (!ToType->isVectorType() && !FromType->isVectorType())
diff --git a/clang/test/CodeGen/sizeless-splat-init.cpp b/clang/test/CodeGen/sizeless-splat-init.cpp
new file mode 100644
index 0000000000000..8f640c9cc5ae9
--- /dev/null
+++ b/clang/test/CodeGen/sizeless-splat-init.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sve %s -emit-llvm -o - | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK-LABEL: @__SVInt8_t_fun(
+// CHECK: store <vscale x {{[0-9]*}} x i8> splat (i8 123), ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x i8>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x i8> %[[RETVAL]]
+extern "C" {
+__SVInt8_t __SVInt8_t_fun(void) {
+ __SVInt8_t svi8(123);
+ return svi8;
+}
+}
+
+// CHECK-LABEL: @__SVInt8_t_argfun(
+// CHECK: store i8 %arg, ptr %[[WHERE:.*]]
+// CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+// CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i8> poison, i8 %[[WHAT]], i64 0
+// CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i8> %[[INSERT]], <vscale x {{[0-9]*}} x i8> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+// CHECK: store <vscale x {{[0-9]*}} x i8> %[[SPLAT]], ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x i8>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x i8> %[[RETVAL]]
+extern "C" {
+__SVInt8_t __SVInt8_t_argfun(int8_t arg) {
+ __SVInt8_t svi8(arg);
+ return svi8;
+}
+}
+
+// CHECK-LABEL: @__SVUint32_t_fun(
+// CHECK: store <vscale x {{[0-9]*}} x i32> splat (i32 1024), ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x i32>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x i32> %[[RETVAL]]
+extern "C" {
+__SVUint32_t __SVUint32_t_fun(void) {
+ __SVUint32_t svui32(1024U);
+ return svui32;
+}
+}
+
+// CHECK-LABEL: @__SVUint32_t_argfun(
+// CHECK: store i32 %arg, ptr %[[WHERE:.*]]
+// CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+// CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+// CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+// CHECK: store <vscale x {{[0-9]*}} x i32> %[[SPLAT]], ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x i32>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x i32> %[[RETVAL]]
+extern "C" {
+__SVUint32_t __SVUint32_t_argfun(uint32_t arg) {
+ __SVUint32_t svui32(arg);
+ return svui32;
+}
+}
+
+// CHECK-LABEL: @__SVFloat32_t_fun(
+// CHECK: store <vscale x {{[0-9]*}} x float> splat (float 1.230000e-01), ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x float>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x float> %[[RETVAL]]
+extern "C" {
+__SVFloat32_t __SVFloat32_t_fun(void) {
+ __SVFloat32_t svfloat32(0.123);
+ return svfloat32;
+}
+}
+
+// CHECK-LABEL: @__SVFloat32_t_argfun(
+// CHECK: store float %arg, ptr %[[WHERE:.*]]
+// CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+// CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+// CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+// CHECK: store <vscale x {{[0-9]*}} x float> %[[SPLAT]], ptr %[[RETPTR:.*]]
+// CHECK: %[[RETVAL:.*]] = load <vscale x {{[0-9]*}} x float>, ptr %[[RETPTR]]
+// CHECK: ret <vscale x {{[0-9]*}} x float> %[[RETVAL]]
+extern "C" {
+__SVFloat32_t __SVFloat32_t_argfun(float arg) {
+ __SVFloat32_t svfloat32(arg);
+ return svfloat32;
+}
+}
diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp
index ef3eec9507b58..880880f973235 100644
--- a/clang/test/SemaCXX/sizeless-1.cpp
+++ b/clang/test/SemaCXX/sizeless-1.cpp
@@ -127,14 +127,14 @@ void func(int sel) {
init_int8 = local_int8;
init_int8 = local_int16; // expected-error {{assigning to 'svint8_t' (aka '__SVInt8_t') from incompatible type 'svint16_t'}}
- init_int8 = sel; // expected-error {{assigning to 'svint8_t' (aka '__SVInt8_t') from incompatible type 'int'}}
+ init_int8 = sel;
sel = local_int8; // expected-error {{assigning to 'int' from incompatible type 'svint8_t'}}
local_int8 = (svint8_t)local_int8;
local_int8 = (const svint8_t)local_int8;
local_int8 = (svint8_t)local_int16; // expected-error {{C-style cast from 'svint16_t' (aka '__SVInt16_t') to 'svint8_t' (aka '__SVInt8_t') is not allowed}}
- local_int8 = (svint8_t)0; // expected-error {{C-style cast from 'int' to 'svint8_t' (aka '__SVInt8_t') is not allowed}}
+ local_int8 = (svint8_t)0;
sel = (int)local_int8; // expected-error {{C-style cast from 'svint8_t' (aka '__SVInt8_t') to 'int' is not allowed}}
init_int8 = local_int8;
@@ -354,7 +354,7 @@ void cxx_only(int sel) {
local_int8 = static_cast<svint8_t>(local_int8);
local_int8 = static_cast<svint8_t>(local_int16); // expected-error {{static_cast from 'svint16_t' (aka '__SVInt16_t') to 'svint8_t' (aka '__SVInt8_t') is not allowed}}
- local_int8 = static_cast<svint8_t>(0); // expected-error {{static_cast from 'int' to 'svint8_t' (aka '__SVInt8_t') is not allowed}}
+ local_int8 = static_cast<svint8_t>(0);
local_int16 = static_cast<svint16_t>(local_int8); // expected-error {{static_cast from 'svint8_t' (aka '__SVInt8_t') to 'svint16_t' (aka '__SVInt16_t') is not allowed}}
sel = static_cast<int>(local_int8); // expected-error {{static_cast from 'svint8_t' (aka '__SVInt8_t') to 'int' is not allowed}}
More information about the cfe-commits
mailing list