@@ -164,18 +164,20 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
164
164
return Result;
165
165
}
166
166
167
- // Calculate the size of a legacy cbuffer type based on
167
+ // Calculate the size of a legacy cbuffer type in bytes based on
168
168
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
169
169
static unsigned calculateLegacyCbufferSize (const ASTContext &Context,
170
170
QualType T) {
171
171
unsigned Size = 0 ;
172
- constexpr unsigned CBufferAlign = 128 ;
172
+ constexpr unsigned CBufferAlign = 16 ;
173
173
if (const RecordType *RT = T->getAs <RecordType>()) {
174
174
const RecordDecl *RD = RT->getDecl ();
175
175
for (const FieldDecl *Field : RD->fields ()) {
176
176
QualType Ty = Field->getType ();
177
177
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 ;
179
181
if (Ty->isAggregateType ())
180
182
FieldAlign = CBufferAlign;
181
183
Size = llvm::alignTo (Size, FieldAlign);
@@ -194,17 +196,19 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
194
196
calculateLegacyCbufferSize (Context, VT->getElementType ());
195
197
Size = ElementSize * ElementCount;
196
198
} else {
197
- Size = Context.getTypeSize (T);
199
+ Size = Context.getTypeSize (T) / 8 ;
198
200
}
199
201
return Size;
200
202
}
201
203
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) {
207
208
llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
209
+
210
+ // Make sure the packoffset annotations are either on all declarations
211
+ // or on none.
208
212
bool HasPackOffset = false ;
209
213
bool HasNonPackOffset = false ;
210
214
for (auto *Field : BufDecl->decls ()) {
@@ -219,33 +223,41 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
219
223
}
220
224
}
221
225
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;
247
252
}
248
253
}
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);
249
261
250
262
SemaRef.PopDeclContext ();
251
263
}
0 commit comments