diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1696,7 +1696,7 @@ return; } - if (!SemaRef.getLangOpts().OpenCL) { + if (!SemaRef.getLangOpts().OpenCL && !SemaRef.getLangOpts().HLSL ) { // If the initializing element is a vector, try to copy-initialize // instead of breaking it apart (which is doomed to failure anyway). Expr *Init = IList->getInit(Index); @@ -1790,7 +1790,7 @@ InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); - // OpenCL initializers allows vectors to be constructed from vectors. + // OpenCL and HLSL initializers allow vectors to be constructed from vectors. for (unsigned i = 0; i < maxElements; ++i) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) @@ -1819,7 +1819,7 @@ } } - // OpenCL requires all elements to be initialized. + // OpenCL and HLSL require all elements to be initialized. if (numEltsInit != maxElements) { if (!VerifyOnly) SemaRef.Diag(IList->getBeginLoc(), @@ -5969,6 +5969,36 @@ assert(Args.size() >= 1 && "Zero-argument case handled above"); + // For HLSL ext vector types we allow list initialization behavior for C++ + // constructor syntax. This is accomplished by converting initialization + // arguments an InitListExpr late. + if (S.getLangOpts().HLSL && DestType->isExtVectorType() && + DestType != SourceType) { + + llvm::SmallVector InitArgs; + for (auto Arg : Args) { + if (Arg->getType()->isExtVectorType()) { + const auto *VTy = Arg->getType()->castAs(); + unsigned Elm = VTy->getNumElements(); + for (unsigned Idx = 0; Idx < Elm; ++Idx) { + InitArgs.emplace_back(new (Context) ArraySubscriptExpr( + Arg, + IntegerLiteral::Create( + Context, llvm::APInt(Context.getIntWidth(Context.IntTy), Idx), + Context.IntTy, SourceLocation()), + VTy->getElementType(), Arg->getValueKind(), Arg->getObjectKind(), + SourceLocation())); + } + } else + InitArgs.emplace_back(Arg); + } + InitListExpr *ILE = new (Context) InitListExpr( + S.getASTContext(), SourceLocation(), InitArgs, SourceLocation()); + Args[0] = ILE; + AddListInitializationStep(DestType); + return; + } + // The remaining cases all need a source type. if (Args.size() > 1) { SetFailed(FK_TooManyInitsForScalar); @@ -8129,6 +8159,11 @@ ExprResult CurInit((Expr *)nullptr); SmallVector ArrayLoopCommonExprs; + // HLSL allows vector initialization to function like list initialization, but + // use the syntax of a C++-like constructor. + bool IsHLSLVectorInit = S.getLangOpts().HLSL && DestType->isExtVectorType() && + isa(Args[0]); + // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" // initializer. @@ -8166,7 +8201,7 @@ case SK_StdInitializerList: case SK_OCLSamplerInit: case SK_OCLZeroOpaqueType: { - assert(Args.size() == 1); + assert(Args.size() == 1 || IsHLSLVectorInit); CurInit = Args[0]; if (!CurInit.get()) return ExprError(); break; diff --git a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -verify %s + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); + +[numthreads(1,1,1)] +void entry() { + float2 LilVec = float2(1.0, 2.0); + float2 BrokenVec = float2(1.0, 2.0, 3.0); // expected-error{{excess elements in vector initializer}} + float3 NormieVec = float3(LilVec, 3.0, 4.0); // expected-error{{excess elements in vector initializer}} + float3 BrokenNormie = float3(3.0, 4.0); // expected-error{{too few elements in vector initialization (expected 3 elements, have 2)}} + float3 OverwhemledNormie = float3(3.0, 4.0, 5.0, 6.0); // expected-error{{excess elements in vector initializer}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/vector-constructors.hlsl b/clang/test/SemaHLSL/BuiltIns/vector-constructors.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/vector-constructors.hlsl @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); + +[numthreads(1,1,1)] +void entry() { + float2 Vec2 = float2(1.0, 2.0); + float3 Vec3 = float3(Vec2, 3.0); + float3 Vec3b = float3(1.0, 2.0, 3.0); +} + +// For the float2 vector, we just expect a conversion from constructor +// parameters to an initialization list +// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} col:10 used Vec2 'float2':'float __attribute__((ext_vector_type(2)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} 'float2':'float __attribute__((ext_vector_type(2)))' functional cast to float2 +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} 'float2':'float __attribute__((ext_vector_type(2)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 1.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 2.000000e+00 + + +// For the float 3 things get fun... +// Here we expect accesses to the vec2 to provide the first and second +// components using ArraySubscriptExpr +// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} col:10 Vec3 'float3':'float __attribute__((ext_vector_type(3)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} 'float3':'float __attribute__((ext_vector_type(3)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} > 'float' +// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} > 'float' lvalue +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))' +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <> 'int' 0 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} > 'float' +// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} > 'float' lvalue +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))' +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <> 'int' 1 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 3.000000e+00 + +// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} col:10 Vec3b 'float3':'float __attribute__((ext_vector_type(3)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} 'float3':'float __attribute__((ext_vector_type(3)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 1.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 2.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'float' +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} 'double' 3.000000e+00