@@ -164,18 +164,20 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
164164 return Result;
165165}
166166
167- // Calculate the size of a legacy cbuffer type based on
167+ // Calculate the size of a legacy cbuffer type in bytes based on
168168// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
169169static unsigned calculateLegacyCbufferSize (const ASTContext &Context,
170170 QualType T) {
171171 unsigned Size = 0 ;
172- constexpr unsigned CBufferAlign = 128 ;
172+ constexpr unsigned CBufferAlign = 16 ;
173173 if (const RecordType *RT = T->getAs <RecordType>()) {
174174 const RecordDecl *RD = RT->getDecl ();
175175 for (const FieldDecl *Field : RD->fields ()) {
176176 QualType Ty = Field->getType ();
177177 unsigned FieldSize = calculateLegacyCbufferSize (Context, Ty);
178- unsigned FieldAlign = 32 ;
178+ // FIXME: This is not the correct alignment, it does not work for 16-bit
179+ // types. See llvm/llvm-project#119641.
180+ unsigned FieldAlign = 4 ;
179181 if (Ty->isAggregateType ())
180182 FieldAlign = CBufferAlign;
181183 Size = llvm::alignTo (Size, FieldAlign);
@@ -194,17 +196,19 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
194196 calculateLegacyCbufferSize (Context, VT->getElementType ());
195197 Size = ElementSize * ElementCount;
196198 } else {
197- Size = Context.getTypeSize (T);
199+ Size = Context.getTypeSize (T) / 8 ;
198200 }
199201 return Size;
200202}
201203
202- void SemaHLSL::ActOnFinishBuffer (Decl *Dcl, SourceLocation RBrace) {
203- auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
204- BufDecl->setRBraceLoc (RBrace);
205-
206- // Validate packoffset.
204+ // Validate packoffset:
205+ // - if packoffset it used it must be set on all declarations inside the buffer
206+ // - packoffset ranges must not overlap
207+ static void validatePackoffset (Sema &S, HLSLBufferDecl *BufDecl) {
207208 llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
209+
210+ // Make sure the packoffset annotations are either on all declarations
211+ // or on none.
208212 bool HasPackOffset = false ;
209213 bool HasNonPackOffset = false ;
210214 for (auto *Field : BufDecl->decls ()) {
@@ -219,33 +223,41 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
219223 }
220224 }
221225
222- if (HasPackOffset && HasNonPackOffset)
223- Diag (BufDecl->getLocation (), diag::warn_hlsl_packoffset_mix);
224-
225- if (HasPackOffset) {
226- ASTContext &Context = getASTContext ();
227- // Make sure no overlap in packoffset.
228- // Sort PackOffsetVec by offset.
229- std::sort (PackOffsetVec.begin (), PackOffsetVec.end (),
230- [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
231- const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
232- return LHS.second ->getOffset () < RHS.second ->getOffset ();
233- });
234-
235- for (unsigned i = 0 ; i < PackOffsetVec.size () - 1 ; i++) {
236- VarDecl *Var = PackOffsetVec[i].first ;
237- HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second ;
238- unsigned Size = calculateLegacyCbufferSize (Context, Var->getType ());
239- unsigned Begin = Attr->getOffset () * 32 ;
240- unsigned End = Begin + Size;
241- unsigned NextBegin = PackOffsetVec[i + 1 ].second ->getOffset () * 32 ;
242- if (End > NextBegin) {
243- VarDecl *NextVar = PackOffsetVec[i + 1 ].first ;
244- Diag (NextVar->getLocation (), diag::err_hlsl_packoffset_overlap)
245- << NextVar << Var;
246- }
226+ if (!HasPackOffset)
227+ return ;
228+
229+ if (HasNonPackOffset)
230+ S.Diag (BufDecl->getLocation (), diag::warn_hlsl_packoffset_mix);
231+
232+ // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
233+ // and compare adjacent values.
234+ ASTContext &Context = S.getASTContext ();
235+ std::sort (PackOffsetVec.begin (), PackOffsetVec.end (),
236+ [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
237+ const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
238+ return LHS.second ->getOffsetInBytes () <
239+ RHS.second ->getOffsetInBytes ();
240+ });
241+ for (unsigned i = 0 ; i < PackOffsetVec.size () - 1 ; i++) {
242+ VarDecl *Var = PackOffsetVec[i].first ;
243+ HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second ;
244+ unsigned Size = calculateLegacyCbufferSize (Context, Var->getType ());
245+ unsigned Begin = Attr->getOffsetInBytes ();
246+ unsigned End = Begin + Size;
247+ unsigned NextBegin = PackOffsetVec[i + 1 ].second ->getOffsetInBytes ();
248+ if (End > NextBegin) {
249+ VarDecl *NextVar = PackOffsetVec[i + 1 ].first ;
250+ S.Diag (NextVar->getLocation (), diag::err_hlsl_packoffset_overlap)
251+ << NextVar << Var;
247252 }
248253 }
254+ }
255+
256+ void SemaHLSL::ActOnFinishBuffer (Decl *Dcl, SourceLocation RBrace) {
257+ auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
258+ BufDecl->setRBraceLoc (RBrace);
259+
260+ validatePackoffset (SemaRef, BufDecl);
249261
250262 SemaRef.PopDeclContext ();
251263}
0 commit comments