Skip to content

Commit f68ea5a

Browse files
committed
[HLSL][NFC] Move packoffset validation to separate function and calculate offsets in bytes
1 parent 4dc34b0 commit f68ea5a

File tree

2 files changed

+49
-37
lines changed

2 files changed

+49
-37
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4721,9 +4721,9 @@ def HLSLPackOffset: HLSLAnnotationAttr {
47214721
let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
47224722
let Documentation = [HLSLPackOffsetDocs];
47234723
let AdditionalMembers = [{
4724-
unsigned getOffset() {
4725-
return subcomponent * 4 + component;
4726-
}
4724+
unsigned getOffsetInBytes() {
4725+
return subcomponent * 16 + component * 4;
4726+
}
47274727
}];
47284728
}
47294729

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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
169169
static 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+
// - make sure if packoffset it used on all decls or none
206+
// - the 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

Comments
 (0)