beanz updated this revision to Diff 437670. beanz added a comment. Updates based on feedback from @aaron.ballman.
Thank you for all the test suggestions, it caught an extra-odd AST generation. Fix included :). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D127802/new/ https://reviews.llvm.org/D127802 Files: clang/lib/Sema/SemaInit.cpp clang/test/AST/HLSL/vector-constructors.hlsl clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
Index: clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl =================================================================== --- /dev/null +++ clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl @@ -0,0 +1,22 @@ +// 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))); + +struct S { float f; }; +struct S2 { float f; int i; }; + +[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}} + + // These _should_ work in HLSL but aren't yet supported. + S s; + float2 GettingStrange = float2(s, s); // expected-error{{no viable conversion from 'S' to 'float'}} expected-error{{no viable conversion from 'S' to 'float'}} + S2 s2; + float2 EvenStranger = float2(s2); // expected-error{{no viable conversion from 'S2' to 'float'}} expected-error{{too few elements in vector initialization (expected 2 elements, have 1)}} +} Index: clang/test/AST/HLSL/vector-constructors.hlsl =================================================================== --- /dev/null +++ clang/test/AST/HLSL/vector-constructors.hlsl @@ -0,0 +1,143 @@ +// 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:3, col:32> col:10 used Vec2 'float2':'float __attribute__((ext_vector_type(2)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:17, col:32> 'float2':'float __attribute__((ext_vector_type(2)))' functional cast to float2 <NoOp> +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:24, col:29> 'float2':'float __attribute__((ext_vector_type(2)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:24> 'double' 1.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:29> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:29> '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:3, col:33> col:10 Vec3 'float3':'float __attribute__((ext_vector_type(3)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:17, col:33> 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp> +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:24, col:30> 'float3':'float __attribute__((ext_vector_type(3)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' <LValueToRValue> +// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' lvalue +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> '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]+}} <<invalid sloc>> 'int' 0 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' <LValueToRValue> +// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' lvalue +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> '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]+}} <<invalid sloc>> 'int' 1 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:30> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:30> 'double' 3.000000e+00 + +// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:3, col:38> col:10 Vec3b 'float3':'float __attribute__((ext_vector_type(3)))' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:18, col:38> 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp> +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:25, col:35> 'float3':'float __attribute__((ext_vector_type(3)))' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:25> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:25> 'double' 1.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:30> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:30> 'double' 2.000000e+00 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:35> 'float' <FloatingCast> +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:35> 'double' 3.000000e+00 + +// The tests above verify pretty explictily that the Initialization lists are +// being constructed as expected. The next tests are bit sparser for brevity. + + float f = 1.0f, g = 2.0f; + float2 foo0 = float2(f, g); // Non-literal + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:54:3, col:29> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' lvalue Var 0x{{[0-9a-fA-F]+}} 'f' 'float' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' lvalue Var 0x{{[0-9a-fA-F]+}} 'g' 'float' + + int i = 1, j = 2; + float2 foo1 = float2(1, 2); // Integer literals + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:66:3, col:29> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <IntegralToFloating> +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:24> 'int' 1 +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <IntegralToFloating> +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:27> 'int' 2 + + float2 foo2 = float2(i, j); // Integer non-literal + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:77:3, col:29> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <IntegralToFloating> +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'i' 'int' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <IntegralToFloating> +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'j' 'int' + + struct S { float f; } s; + float2 foo4 = float2(s.f, s.f); + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:91:3, col:33> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, col:26> 'float' <LValueToRValue> +// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:24, col:26> 'float' lvalue .f 0x{{[0-9a-fA-F]+}} +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:29, col:31> 'float' <LValueToRValue> +// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:29, col:31> 'float' lvalue .f 0x{{[0-9a-fA-F]+}} +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:29> 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S' + + struct T { + operator float() const { return 1.0f; } + } t; + float2 foo5 = float2(t, t); // user-defined cast operator + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:107:3, col:29> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <UserDefinedConversion> +// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' +// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:24> '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}} +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'const T' lvalue <NoOp> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T' +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <UserDefinedConversion> +// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' +// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:27> '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}} +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'const T' lvalue <NoOp> +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T' + + typedef float2 second_level_of_typedefs; + second_level_of_typedefs foo6 = float2(1.0f, 2.0f); + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:125:3, col:53> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:42> 'float' 1.000000e+00 +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:48> 'float' 2.000000e+00 + + float2 foo7 = second_level_of_typedefs(1.0f, 2.0f); + +// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:134:3, col:53> +// CHECK-NEXT: VarDecl +// CHECK-NEXT: CXXFunctionalCastExpr +// CHECK-NEXT: InitListExpr +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:42> 'float' 1.000000e+00 +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:48> 'float' 2.000000e+00 + +} Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ 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,37 @@ 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() && + (SourceType.isNull() || + !Context.hasSameUnqualifiedType(SourceType, DestType))) { + + llvm::SmallVector<Expr *> InitArgs; + for (auto Arg : Args) { + if (Arg->getType()->isExtVectorType()) { + const auto *VTy = Arg->getType()->castAs<ExtVectorType>(); + 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 +8160,11 @@ ExprResult CurInit((Expr *)nullptr); SmallVector<Expr*, 4> 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<InitListExpr>(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 +8202,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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits