[clang] 9f499d9 - [HLSL] Support HLSL vector initializers
Chris Bieneman via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 21 10:33:55 PDT 2022
Author: Chris Bieneman
Date: 2022-06-21T12:33:42-05:00
New Revision: 9f499d9d73edfc818978c64eb24b8d2d34995d76
URL: https://github.com/llvm/llvm-project/commit/9f499d9d73edfc818978c64eb24b8d2d34995d76
DIFF: https://github.com/llvm/llvm-project/commit/9f499d9d73edfc818978c64eb24b8d2d34995d76.diff
LOG: [HLSL] Support HLSL vector initializers
In HLSL vectors are ext_vectors in all respects except that they
support a constructor style syntax for initializing vectors. This
change adds a translation of vector constructor arguments into
initializer lists.
This supports two oddities of HLSL syntax:
(1) HLSL vectors support constructor syntax
(2) HLSL vectors are expanded to constituate components in constructors
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D127802
Added:
clang/test/AST/HLSL/vector-constructors.hlsl
clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
Modified:
clang/lib/Sema/SemaInit.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index c7e068046d7fd..f4cd45ad6c922 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -1696,7 +1696,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
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 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
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 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
}
- // 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 @@ void InitializationSequence::InitializeFrom(Sema &S,
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 InitializationSequence::Perform(Sema &S,
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 @@ ExprResult InitializationSequence::Perform(Sema &S,
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/AST/HLSL/vector-constructors.hlsl b/clang/test/AST/HLSL/vector-constructors.hlsl
new file mode 100644
index 0000000000000..7861d5209b5d3
--- /dev/null
+++ b/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
+
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
new file mode 100644
index 0000000000000..73b5a192793e0
--- /dev/null
+++ b/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)}}
+}
More information about the cfe-commits
mailing list