https://github.com/pawosm-arm updated 
https://github.com/llvm/llvm-project/pull/205432

>From e7b3e6bc952a521cc4a4a91bca1f4f69fee2431f Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <[email protected]>
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 vi8x8var;
}
```

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                | 28 +++++++-
 clang/lib/Sema/SemaOverload.cpp            |  9 +++
 clang/test/CodeGen/sizeless-splat-init.cpp | 81 ++++++++++++++++++++++
 clang/test/SemaCXX/sizeless-1.cpp          |  6 +-
 5 files changed, 122 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..61c353375ff4c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -1484,8 +1484,32 @@ 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()) {
+      if (!VerifyOnly) {
+        if (SemaRef.Context.getLangOpts().CPlusPlus) {
+          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);
+        } else {
+          PartialDiagnostic PDiag =
+              SemaRef.PDiag(diag::err_typecheck_convert_incompatible)
+              << DeclType << expr->getType() << AssignmentAction::Initializing
+              << expr->getSourceRange() << 0U;
+          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..f8cd3d9378512 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() && !S.getLangOpts().HLSL) {
+    // Vector splat from any arithmetic type to a sizeless vector.
+    if (FromType->isArithmeticType()) {
+      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}}
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to