99// ===----------------------------------------------------------------------===//
1010
1111#include " clang/Sema/SemaHLSL.h"
12+ #include " clang/AST/ASTConsumer.h"
1213#include " clang/AST/ASTContext.h"
1314#include " clang/AST/Attr.h"
1415#include " clang/AST/Attrs.inc"
@@ -172,6 +173,23 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
172173 return Result;
173174}
174175
176+ static unsigned calculateLegacyCbufferFieldAlign (const ASTContext &Context,
177+ QualType T) {
178+ // Arrays and Structs are always aligned to new buffer rows
179+ if (T->isArrayType () || T->isStructureType ())
180+ return 16 ;
181+
182+ // Vectors are aligned to the type they contain
183+ if (const VectorType *VT = T->getAs <VectorType>())
184+ return calculateLegacyCbufferFieldAlign (Context, VT->getElementType ());
185+
186+ assert (Context.getTypeSize (T) <= 64 &&
187+ " Scalar bit widths larger than 64 not supported" );
188+
189+ // Scalar types are aligned to their byte width
190+ return Context.getTypeSize (T) / 8 ;
191+ }
192+
175193// Calculate the size of a legacy cbuffer type in bytes based on
176194// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
177195static unsigned calculateLegacyCbufferSize (const ASTContext &Context,
@@ -183,11 +201,15 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
183201 for (const FieldDecl *Field : RD->fields ()) {
184202 QualType Ty = Field->getType ();
185203 unsigned FieldSize = calculateLegacyCbufferSize (Context, Ty);
186- // FIXME: This is not the correct alignment, it does not work for 16-bit
187- // types. See llvm/llvm-project#119641.
188- unsigned FieldAlign = 4 ;
189- if (Ty->isAggregateType ())
204+ unsigned FieldAlign = calculateLegacyCbufferFieldAlign (Context, Ty);
205+
206+ // If the field crosses the row boundary after alignment it drops to the
207+ // next row
208+ unsigned AlignSize = llvm::alignTo (Size, FieldAlign);
209+ if ((AlignSize % CBufferAlign) + FieldSize > CBufferAlign) {
190210 FieldAlign = CBufferAlign;
211+ }
212+
191213 Size = llvm::alignTo (Size, FieldAlign);
192214 Size += FieldSize;
193215 }
@@ -225,7 +247,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
225247 // or on none.
226248 bool HasPackOffset = false ;
227249 bool HasNonPackOffset = false ;
228- for (auto *Field : BufDecl->decls ()) {
250+ for (auto *Field : BufDecl->buffer_decls ()) {
229251 VarDecl *Var = dyn_cast<VarDecl>(Field);
230252 if (!Var)
231253 continue ;
@@ -492,7 +514,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
492514 LS->setImplicit (true );
493515 LS->startDefinition ();
494516
495- for (Decl *D : BufDecl->decls ()) {
517+ for (Decl *D : BufDecl->buffer_decls ()) {
496518 VarDecl *VD = dyn_cast<VarDecl>(D);
497519 if (!VD || VD->getStorageClass () == SC_Static ||
498520 VD->getType ().getAddressSpace () == LangAS::hlsl_groupshared)
@@ -1928,7 +1950,22 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
19281950
19291951} // namespace
19301952
1931- void SemaHLSL::DiagnoseAvailabilityViolations (TranslationUnitDecl *TU) {
1953+ void SemaHLSL::ActOnEndOfTranslationUnit (TranslationUnitDecl *TU) {
1954+ // process default CBuffer - create buffer layout struct and invoke codegenCGH
1955+ if (!DefaultCBufferDecls.empty ()) {
1956+ HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer (
1957+ SemaRef.getASTContext (), SemaRef.getCurLexicalContext (),
1958+ DefaultCBufferDecls);
1959+ SemaRef.getCurLexicalContext ()->addDecl (DefaultCBuffer);
1960+ createHostLayoutStructForBuffer (SemaRef, DefaultCBuffer);
1961+
1962+ DeclGroupRef DG (DefaultCBuffer);
1963+ SemaRef.Consumer .HandleTopLevelDecl (DG);
1964+ }
1965+ diagnoseAvailabilityViolations (TU);
1966+ }
1967+
1968+ void SemaHLSL::diagnoseAvailabilityViolations (TranslationUnitDecl *TU) {
19321969 // Skip running the diagnostics scan if the diagnostic mode is
19331970 // strict (-fhlsl-strict-availability) and the target shader stage is known
19341971 // because all relevant diagnostics were already emitted in the
@@ -2991,6 +3028,14 @@ QualType SemaHLSL::getInoutParameterType(QualType Ty) {
29913028 return Ty;
29923029}
29933030
3031+ static bool IsDefaultBufferConstantDecl (VarDecl *VD) {
3032+ QualType QT = VD->getType ();
3033+ return VD->getDeclContext ()->isTranslationUnit () &&
3034+ QT.getAddressSpace () == LangAS::Default &&
3035+ VD->getStorageClass () != SC_Static &&
3036+ !isInvalidConstantBufferLeafElementType (QT.getTypePtr ());
3037+ }
3038+
29943039void SemaHLSL::ActOnVariableDeclarator (VarDecl *VD) {
29953040 if (VD->hasGlobalStorage ()) {
29963041 // make sure the declaration has a complete type
@@ -3002,7 +3047,18 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
30023047 return ;
30033048 }
30043049
3005- // find all resources on decl
3050+ // Global variables outside a cbuffer block that are not a resource, static,
3051+ // groupshared, or an empty array or struct belong to the default constant
3052+ // buffer $Globals (to be created at the end of the translation unit).
3053+ if (IsDefaultBufferConstantDecl (VD)) {
3054+ // update address space to hlsl_constant
3055+ QualType NewTy = getASTContext ().getAddrSpaceQualType (
3056+ VD->getType (), LangAS::hlsl_constant);
3057+ VD->setType (NewTy);
3058+ DefaultCBufferDecls.push_back (VD);
3059+ }
3060+
3061+ // find all resources bindings on decl
30063062 if (VD->getType ()->isHLSLIntangibleType ())
30073063 collectResourceBindingsOnVarDecl (VD);
30083064
0 commit comments