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
