Skip to content

Commit 80fc426

Browse files
committed
Code review feedback
- create common function isInvalidConstantBufferLeafElementType - create layout structs in the same context as the original struct - fix lookup to scan just the first non-transparent context - add test case with namespaces
1 parent bbdd56b commit 80fc426

File tree

3 files changed

+184
-69
lines changed

3 files changed

+184
-69
lines changed

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 68 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/AST/Decl.h"
1616
#include "clang/AST/DeclBase.h"
1717
#include "clang/AST/DeclCXX.h"
18+
#include "clang/AST/DeclarationName.h"
1819
#include "clang/AST/DynamicRecursiveASTVisitor.h"
1920
#include "clang/AST/Expr.h"
2021
#include "clang/AST/Type.h"
@@ -46,8 +47,8 @@
4647
using namespace clang;
4748
using RegisterType = HLSLResourceBindingAttr::RegisterType;
4849

49-
static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
50-
HLSLBufferDecl *BufDecl);
50+
static CXXRecordDecl *createHostLayoutStruct(Sema &S,
51+
CXXRecordDecl *StructDecl);
5152

5253
static RegisterType getRegisterType(ResourceClass RC) {
5354
switch (RC) {
@@ -268,6 +269,30 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
268269
return CAT != nullptr;
269270
}
270271

272+
// Returns true if the record type is an HLSL resource class
273+
static bool isResourceRecordType(const Type *Ty) {
274+
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
275+
}
276+
277+
// Returns true if the type is a leaf element type that is not valid to be included
278+
// in HLSL Buffer, such as a resource class, empty struct, zero-sized array,
279+
// or a builtin intangible type.
280+
// Returns false it is a valid leaf element type or if it is a record type that
281+
// needs to be inspected further.
282+
static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
283+
if (Ty->isRecordType()) {
284+
if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())
285+
return true;
286+
return false;
287+
}
288+
if (Ty->isConstantArrayType() &&
289+
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
290+
return true;
291+
if (Ty->isHLSLBuiltinIntangibleType())
292+
return true;
293+
return false;
294+
}
295+
271296
// Returns true if the struct contains at least one element that prevents it
272297
// from being included inside HLSL Buffer as is, such as an intangible type,
273298
// empty struct, or zero-sized array. If it does, a new implicit layout struct
@@ -279,13 +304,11 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
279304
// check fields
280305
for (const FieldDecl *Field : RD->fields()) {
281306
QualType Ty = Field->getType();
282-
if (Ty->isRecordType()) {
283-
if (requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
284-
return true;
285-
} else if (Ty->isConstantArrayType()) {
286-
if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
287-
return true;
288-
}
307+
if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr()))
308+
return true;
309+
if (Ty->isRecordType() &&
310+
requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
311+
return true;
289312
}
290313
// check bases
291314
for (const CXXBaseSpecifier &Base : RD->bases())
@@ -295,25 +318,28 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
295318
return false;
296319
}
297320

298-
static CXXRecordDecl *findRecordDecl(Sema &S, IdentifierInfo *II,
299-
DeclContext *DC) {
300-
DeclarationNameInfo NameInfo =
301-
DeclarationNameInfo(DeclarationName(II), SourceLocation());
302-
LookupResult R(S, NameInfo, Sema::LookupTagName);
303-
S.LookupName(R, S.getScopeForContext(DC));
304-
if (R.isSingleResult())
305-
return R.getAsSingle<CXXRecordDecl>();
306-
return nullptr;
321+
static CXXRecordDecl *findRecordDeclInContext(IdentifierInfo *II,
322+
DeclContext *DC) {
323+
CXXRecordDecl *RD = nullptr;
324+
for (NamedDecl *Decl :
325+
DC->getNonTransparentContext()->lookup(DeclarationName(II))) {
326+
if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) {
327+
assert(RD == nullptr &&
328+
"there should be at most 1 record by a given name in a scope");
329+
RD = FoundRD;
330+
}
331+
}
332+
return RD;
307333
}
308334

309335
// Creates a name for buffer layout struct using the provide name base.
310336
// If the name must be unique (not previously defined), a suffix is added
311337
// until a unique name is found.
312-
static IdentifierInfo *getHostLayoutStructName(Sema &S,
313-
IdentifierInfo *NameBaseII,
314-
bool MustBeUnique,
315-
DeclContext *DC) {
338+
static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
339+
bool MustBeUnique) {
316340
ASTContext &AST = S.getASTContext();
341+
342+
IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
317343
StringRef NameBase;
318344
if (NameBaseII) {
319345
NameBase = NameBaseII->getName();
@@ -333,39 +359,31 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
333359
if (suffix != 0)
334360
II = &AST.Idents.get((Name + "_" + Twine(suffix)).str(),
335361
tok::TokenKind::identifier);
336-
if (!findRecordDecl(S, II, DC))
362+
if (!findRecordDeclInContext(II, BaseDecl->getDeclContext()))
337363
return II;
338364
// declaration with that name already exists - increment suffix and try
339365
// again until unique name is found
340366
suffix++;
341367
};
342368
}
343369

344-
// Returns true if the record type is an HLSL resource class
345-
static bool isResourceRecordType(const Type *Ty) {
346-
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
347-
}
348-
349370
// Creates a field declaration of given name and type for HLSL buffer layout
350371
// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
351372
static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
352373
IdentifierInfo *II,
353-
CXXRecordDecl *LayoutStruct,
354-
HLSLBufferDecl *BufDecl) {
374+
CXXRecordDecl *LayoutStruct) {
375+
if (isInvalidConstantBufferLeafElementType(Ty))
376+
return nullptr;
377+
355378
if (Ty->isRecordType()) {
356-
if (isResourceRecordType(Ty))
357-
return nullptr;
358379
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
359380
if (requiresImplicitBufferLayoutStructure(RD)) {
360-
RD = createHostLayoutStruct(S, RD, BufDecl);
381+
RD = createHostLayoutStruct(S, RD);
361382
if (!RD)
362383
return nullptr;
363384
Ty = RD->getTypeForDecl();
364385
}
365386
}
366-
if (Ty->isConstantArrayType() &&
367-
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
368-
return nullptr;
369387

370388
QualType QT = QualType(Ty, 0);
371389
ASTContext &AST = S.getASTContext();
@@ -384,23 +402,21 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
384402
// - empty structs
385403
// - zero-sized arrays
386404
// Returns nullptr if the resulting layout struct would be empty.
387-
static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
388-
HLSLBufferDecl *BufDecl) {
405+
static CXXRecordDecl *createHostLayoutStruct(Sema &S,
406+
CXXRecordDecl *StructDecl) {
389407
assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
390408
"struct is already HLSL buffer compatible");
391409

392410
ASTContext &AST = S.getASTContext();
393411
DeclContext *DC = StructDecl->getDeclContext();
394-
IdentifierInfo *II = getHostLayoutStructName(
395-
S, StructDecl->getIdentifier(), false, BufDecl->getDeclContext());
412+
IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false);
396413

397414
// reuse existing if the layout struct if it already exists
398-
if (CXXRecordDecl *RD = findRecordDecl(S, II, DC))
415+
if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
399416
return RD;
400417

401-
CXXRecordDecl *LS =
402-
CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
403-
SourceLocation(), SourceLocation(), II);
418+
CXXRecordDecl *LS = CXXRecordDecl::Create(
419+
AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), II);
404420
LS->setImplicit(true);
405421
LS->startDefinition();
406422

@@ -410,7 +426,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
410426
CXXBaseSpecifier Base = *StructDecl->bases_begin();
411427
CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
412428
if (requiresImplicitBufferLayoutStructure(BaseDecl)) {
413-
BaseDecl = createHostLayoutStruct(S, BaseDecl, BufDecl);
429+
BaseDecl = createHostLayoutStruct(S, BaseDecl);
414430
if (BaseDecl) {
415431
TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(
416432
QualType(BaseDecl->getTypeForDecl(), 0));
@@ -427,15 +443,16 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
427443
// filter struct fields
428444
for (const FieldDecl *FD : StructDecl->fields()) {
429445
const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
430-
if (FieldDecl *NewFD = createFieldForHostLayoutStruct(
431-
S, Ty, FD->getIdentifier(), LS, BufDecl))
446+
if (FieldDecl *NewFD =
447+
createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS))
432448
LS->addDecl(NewFD);
433449
}
434450
LS->completeDefinition();
435451

436452
if (LS->field_empty() && LS->getNumBases() == 0)
437453
return nullptr;
438-
BufDecl->addDecl(LS);
454+
455+
DC->addDecl(LS);
439456
return LS;
440457
}
441458

@@ -449,8 +466,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
449466
// The layour struct will be added to the HLSLBufferDecl declarations.
450467
void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
451468
ASTContext &AST = S.getASTContext();
452-
IdentifierInfo *II = getHostLayoutStructName(S, BufDecl->getIdentifier(),
453-
true, BufDecl->getDeclContext());
469+
IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
454470

455471
CXXRecordDecl *LS =
456472
CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
@@ -463,8 +479,8 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
463479
if (!VD || VD->getStorageClass() == SC_Static)
464480
continue;
465481
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
466-
if (FieldDecl *FD = createFieldForHostLayoutStruct(
467-
S, Ty, VD->getIdentifier(), LS, BufDecl))
482+
if (FieldDecl *FD =
483+
createFieldForHostLayoutStruct(S, Ty, VD->getIdentifier(), LS))
468484
LS->addDecl(FD);
469485
}
470486
LS->completeDefinition();

clang/test/AST/HLSL/cbuffer.hlsl

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,54 +87,55 @@ cbuffer CB {
8787
B s2;
8888
// CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
8989
CTypedef s3;
90-
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
91-
// CHECK: FieldDecl {{.*}} a 'float'
9290
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 definition
9391
// CHECK: FieldDecl {{.*}} s1 'A'
9492
// CHECK: FieldDecl {{.*}} s2 '__layout_B'
9593
}
94+
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
95+
// CHECK: FieldDecl {{.*}} a 'float'
96+
9697
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_B), "");
9798
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_2), "");
9899

99100
// check that layout struct is created for D because of its base struct
100-
// CHECK: HLSLBufferDecl {{.*}} line:103:9 cbuffer CB
101+
// CHECK: HLSLBufferDecl {{.*}} line:104:9 cbuffer CB
101102
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
102103
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
103104
cbuffer CB {
104105
// CHECK: VarDecl {{.*}} s4 'D'
105106
D s4;
106-
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D definition
107-
// CHECK: public '__layout_B'
108-
// CHECK: FieldDecl {{.*}} b 'float'
109107
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 definition
110108
// CHECK: FieldDecl {{.*}} s4 '__layout_D'
111109
}
110+
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D definition
111+
// CHECK: public '__layout_B'
112+
// CHECK: FieldDecl {{.*}} b 'float'
112113
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_D), "");
113114
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_3), "");
114115

115116
// check that layout struct is created for E because because its base struct
116117
// is empty and should be eliminated, and BTypedef should reuse the previously
117118
// defined '__layout_B'
118-
// CHECK: HLSLBufferDecl {{.*}} line:121:9 cbuffer CB
119+
// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
119120
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
120121
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
121122
cbuffer CB {
122123
// CHECK: VarDecl {{.*}} s5 'E'
123124
E s5;
124125
// CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
125126
BTypedef s6;
126-
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E definition
127-
// CHECK: FieldDecl {{.*}} c 'float'
128-
// CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
129127
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_4 definition
130128
// CHECK: FieldDecl {{.*}} s5 '__layout_E'
131129
// CHECK: FieldDecl {{.*}} s6 '__layout_B'
132130
}
131+
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E definition
132+
// CHECK: FieldDecl {{.*}} c 'float'
133+
// CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
133134
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_E), "");
134135
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_4), "");
135136

136137
// check that this produces empty layout struct
137-
// CHECK: HLSLBufferDecl {{.*}} line:140:9 cbuffer CB
138+
// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
138139
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
139140
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
140141
cbuffer CB {
@@ -153,22 +154,22 @@ cbuffer CB {
153154
}
154155

155156
// check host layout struct with compatible base struct
156-
// CHECK: HLSLBufferDecl {{.*}} line:159:9 cbuffer CB
157+
// CHECK: HLSLBufferDecl {{.*}} line:160:9 cbuffer CB
157158
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
158159
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
159160
cbuffer CB {
160161
// CHECK: VarDecl {{.*}} s8 'F'
161162
F s8;
162-
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F definition
163-
// CHECK: public 'A'
164163
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 definition
165164
// CHECK: FieldDecl {{.*}} s8 '__layout_F'
166165
}
166+
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F definition
167+
// CHECK: public 'A'
167168
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_F), "");
168169
_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB_6), "");
169170

170171
// anonymous structs
171-
// CHECK: HLSLBufferDecl {{.*}} line:174:9 cbuffer CB
172+
// CHECK: HLSLBufferDecl {{.*}} line:175:9 cbuffer CB
172173
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
173174
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
174175
cbuffer CB {
@@ -181,15 +182,15 @@ cbuffer CB {
181182
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
182183
RWBuffer<float> f;
183184
} s9;
184-
// CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at {{.*}}cbuffer.hlsl:176:3
185+
// CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at {{.*}}cbuffer.hlsl:177:3
185186
// CHECK: CXXRecordDecl {{.*}} struct definition
186187
struct {
187188
// CHECK: FieldDecl {{.*}} g 'float'
188189
float g;
189190
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
190191
RWBuffer<float> f;
191192
} s10;
192-
// CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at {{.*}}cbuffer.hlsl:186:3
193+
// CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at {{.*}}cbuffer.hlsl:187:3
193194
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon definition
194195
// CHECK: FieldDecl {{.*}} e 'float'
195196
// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 definition

0 commit comments

Comments
 (0)