Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14183,6 +14183,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (getLangOpts().OpenCL &&
Var->getType().getAddressSpace() == LangAS::opencl_local)
return;

// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
Expand Down
35 changes: 21 additions & 14 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,11 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
return CAT != nullptr;
}

// Returns true if the record type is an HLSL resource class
static bool isResourceRecordType(const Type *Ty) {
// Returns true if the record type is an HLSL resource class or an array of
// resource classes
static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
Ty = CAT->getArrayElementTypeNoTypeQual();
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
}

Expand All @@ -279,15 +282,15 @@ static bool isResourceRecordType(const Type *Ty) {
// array, or a builtin intangible type. Returns false it is a valid leaf element
// type or if it is a record type that needs to be inspected further.
static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
if (Ty->isRecordType()) {
if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())
return true;
return false;
}
Ty = Ty->getUnqualifiedDesugaredType();
if (isResourceRecordTypeOrArrayOf(Ty))
return true;
if (Ty->isRecordType())
return Ty->getAsCXXRecordDecl()->isEmpty();
if (Ty->isConstantArrayType() &&
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
return true;
if (Ty->isHLSLBuiltinIntangibleType())
if (Ty->isHLSLBuiltinIntangibleType() || Ty->isHLSLAttributedResourceType())
return true;
return false;
}
Expand Down Expand Up @@ -339,7 +342,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
ASTContext &AST = S.getASTContext();

IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
llvm::SmallString<64> Name("__layout_");
llvm::SmallString<64> Name("__cblayout_");
if (NameBaseII) {
Name.append(NameBaseII->getName());
} else {
Expand Down Expand Up @@ -393,7 +396,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
SourceLocation(), II, QT, TSI, nullptr, false,
InClassInitStyle::ICIS_NoInit);
Field->setAccess(AccessSpecifier::AS_private);
Field->setAccess(AccessSpecifier::AS_public);
return Field;
}

Expand All @@ -417,9 +420,11 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S,
if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
return RD;

CXXRecordDecl *LS = CXXRecordDecl::Create(
AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), II);
CXXRecordDecl *LS =
CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, DC, SourceLocation(),
SourceLocation(), II);
LS->setImplicit(true);
LS->addAttr(PackedAttr::CreateImplicit(AST));
LS->startDefinition();

// copy base struct, create HLSL Buffer compatible version if needed
Expand Down Expand Up @@ -472,14 +477,16 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);

CXXRecordDecl *LS =
CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
SourceLocation(), SourceLocation(), II);
LS->addAttr(PackedAttr::CreateImplicit(AST));
LS->setImplicit(true);
LS->startDefinition();

for (Decl *D : BufDecl->decls()) {
VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD || VD->getStorageClass() == SC_Static)
if (!VD || VD->getStorageClass() == SC_Static ||
VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
continue;
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
if (FieldDecl *FD =
Expand Down
3 changes: 0 additions & 3 deletions clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,3 @@ cbuffer A {
// AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
// AST-NEXT: VarDecl {{.*}} a 'hlsl_constant float'
// AST-NEXT: VarDecl {{.*}} b 'hlsl_constant int'
// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout_A definition
// AST: FieldDecl {{.*}} a 'float'
// AST-NEXT: FieldDecl {{.*}} b 'int'
148 changes: 84 additions & 64 deletions clang/test/AST/HLSL/cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -48,94 +48,108 @@ struct TwoFloats {
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} col:9 used a1 'hlsl_constant float'
// CHECK: VarDecl {{.*}} used a1 'hlsl_constant float'
float a1;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB definition
// CHECK: FieldDecl {{.*}} a1 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} a1 'float'
}
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB), "");

// Check that buffer layout struct does not include resources or empty types
// CHECK: HLSLBufferDecl {{.*}} line:62:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} col:9 used a2 'hlsl_constant float'
// CHECK: VarDecl {{.*}} used a2 'hlsl_constant float'
float a2;
// CHECK: VarDecl {{.*}} col:19 b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
// CHECK: VarDecl {{.*}} b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> b2;
// CHECK: VarDecl {{.*}} col:15 c2 'EmptyStruct'
// CHECK: VarDecl {{.*}} c2 'EmptyStruct'
EmptyStruct c2;
// CHECK: VarDecl {{.*}} col:9 d2 'float[0]'
// CHECK: VarDecl {{.*}} d2 'float[0]'
float d2[0];
// CHECK: VarDecl {{.*}} col:9 e2 'hlsl_constant float'
// CHECK: VarDecl {{.*}} f2 'RWBuffer<float>[2]'
RWBuffer<float> f2[2];
// CHECK: VarDecl {{.*}} g2 'groupshared float'
groupshared float g2;
// CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
float e2;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_1 definition
// CHECK: FieldDecl {{.*}} a2 'float'
// CHECK: VarDecl {{.*}} h2 '__hlsl_resource_t'
__hlsl_resource_t h2;
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} a2 'float'
// CHECK-NEXT: FieldDecl {{.*}} e2 'float'
}
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_1), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_1), "");

// Check that layout struct is created for B and the empty struct C is removed
// CHECK: HLSLBufferDecl {{.*}} line:83:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} col:5 used s1 'hlsl_constant A'
// CHECK: VarDecl {{.*}} used s1 'hlsl_constant A'
A s1;
// CHECK: VarDecl {{.*}} col:5 s2 'hlsl_constant B'
// CHECK: VarDecl {{.*}} s2 'hlsl_constant B'
B s2;
// CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C'
// CHECK: VarDecl {{.*}} s3 'CTypedef':'C'
CTypedef s3;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 definition
// CHECK: FieldDecl {{.*}} s1 'A'
// CHECK: FieldDecl {{.*}} s2 '__layout_B'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_2 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} s1 'A'
// CHECK-NEXT: FieldDecl {{.*}} s2 '__cblayout_B'
}
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
// CHECK: FieldDecl {{.*}} a 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_B definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} a 'float'

_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_B), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_2), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_B), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_2), "");

// check that layout struct is created for D because of its base struct
// CHECK: HLSLBufferDecl {{.*}} line:104:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} s4 'hlsl_constant D'
D s4;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 definition
// CHECK: FieldDecl {{.*}} s4 '__layout_D'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_3 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} s4 '__cblayout_D'
}
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D definition
// CHECK: public '__layout_B'
// CHECK: FieldDecl {{.*}} b 'float'
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_D), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_3), "");
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_D definition
// CHECK: public '__cblayout_B'
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} b 'float'
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_D), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_3), "");

// check that layout struct is created for E because because its base struct
// is empty and should be eliminated, and BTypedef should reuse the previously
// defined '__layout_B'
// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
// defined '__cblayout_B'
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} s5 'hlsl_constant E'
E s5;
// CHECK: VarDecl {{.*}} s6 'hlsl_constant BTypedef':'hlsl_constant B'
BTypedef s6;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_4 definition
// CHECK: FieldDecl {{.*}} s5 '__layout_E'
// CHECK: FieldDecl {{.*}} s6 '__layout_B'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_4 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} s5 '__cblayout_E'
// CHECK-NEXT: FieldDecl {{.*}} s6 '__cblayout_B'
}
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E definition
// CHECK: FieldDecl {{.*}} c 'float'
// CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_E), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_4), "");
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_E definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} c 'float'
// CHECK-NOT: CXXRecordDecl {{.*}} struct __cblayout_B definition
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_E), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_4), "");

// check that this produces empty layout struct
// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
Expand All @@ -149,27 +163,30 @@ cbuffer CB {
RWBuffer<float> Buf;
// CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
EmptyArrayTypedef ea;
// CHECK: CXXRecordDecl {{.*}} implicit class __layout_CB_5 definition
// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_CB_5 definition
// CHECK: PackedAttr
// CHECK-NOT: FieldDecl
}

// check host layout struct with compatible base struct
// CHECK: HLSLBufferDecl {{.*}} line:160:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} s8 'hlsl_constant F'
F s8;
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 definition
// CHECK: FieldDecl {{.*}} s8 '__layout_F'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_6 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} s8 '__cblayout_F'
}
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F definition
// CHECK: public 'A'
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_F), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB_6), "");
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_F definition
// CHECK: public 'A'
// CHECK: PackedAttr
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_F), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB_6), "");

// anonymous structs
// CHECK: HLSLBufferDecl {{.*}} line:175:9 cbuffer CB
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
Expand All @@ -182,26 +199,29 @@ cbuffer CB {
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s9;
// CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:177:3
// CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 8]]:3
// CHECK: CXXRecordDecl {{.*}} struct definition
struct {
// CHECK: FieldDecl {{.*}} g 'float'
float g;
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s10;
// CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:187:3
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon definition
// CHECK: FieldDecl {{.*}} e 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 definition
// CHECK: FieldDecl {{.*}} g 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_7 definition
// CHECK: FieldDecl {{.*}} s9 '__layout_anon'
// CHECK: FieldDecl {{.*}} s10 '__layout_anon_1'
// CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 6]]:3
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} e 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon_1 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} g 'float'
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_7 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} s9 '__cblayout_anon'
// CHECK-NEXT: FieldDecl {{.*}} s10 '__cblayout_anon_1'
}
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon_1), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_7), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon_1), "");
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_7), "");

// Add uses for the constant buffer declarations so they are not optimized away
export float foo() {
Expand Down
Loading