Skip to content

Commit aa6db9b

Browse files
authored
[Sema] Report warning when mix packoffset with nonpackoffset (microsoft#6553)
Check mix packoffset elements with nonpackoffset elements in a cbuffer at Sema::ActOnFinishHLSLBuffer. Also check packoffset for aggregate type. Fixes microsoft#3724
1 parent 4242b57 commit aa6db9b

File tree

7 files changed

+128
-6
lines changed

7 files changed

+128
-6
lines changed

tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7544,6 +7544,9 @@ def err_hlsl_objectintemplateargument : Error<
75447544
"%0 is an object and cannot be used as a type parameter">;
75457545
def err_hlsl_packoffset_requires_cbuffer : Error<
75467546
"packoffset is only allowed in a constant buffer">;
7547+
def warn_hlsl_packoffset_mix : Warning<
7548+
"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">;
7549+
def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
75477550
def err_hlsl_register_semantics_conflicting : Error<
75487551
"conflicting register semantics">;
75497552
def err_hlsl_register_or_offset_bind_not_valid: Error<

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11012,6 +11012,10 @@ void hlsl::DiagnosePackingOffset(clang::Sema *self, SourceLocation loc,
1101211012
self->Diag(loc, diag::err_hlsl_register_or_offset_bind_not_valid);
1101311013
}
1101411014
}
11015+
if (hlsl::IsMatrixType(self, type) || type->isArrayType() ||
11016+
type->isStructureType()) {
11017+
self->Diag(loc, diag::err_hlsl_register_or_offset_bind_not_valid);
11018+
}
1101511019
}
1101611020
}
1101711021

@@ -14019,8 +14023,66 @@ Decl *Sema::ActOnStartHLSLBuffer(
1401914023
void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
1402014024
DXASSERT_NOMSG(Dcl != nullptr);
1402114025
DXASSERT(Dcl == HLSLBuffers.back(), "otherwise push/pop is incorrect");
14022-
dyn_cast<HLSLBufferDecl>(Dcl)->setRBraceLoc(RBrace);
14026+
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
14027+
BufDecl->setRBraceLoc(RBrace);
1402314028
HLSLBuffers.pop_back();
14029+
14030+
// Validate packoffset.
14031+
llvm::SmallVector<std::pair<VarDecl *, unsigned>, 4> PackOffsetVec;
14032+
bool HasPackOffset = false;
14033+
bool HasNonPackOffset = false;
14034+
for (auto *Field : BufDecl->decls()) {
14035+
VarDecl *Var = dyn_cast<VarDecl>(Field);
14036+
if (!Var)
14037+
continue;
14038+
14039+
unsigned Offset = UINT_MAX;
14040+
14041+
for (const hlsl::UnusualAnnotation *it : Var->getUnusualAnnotations()) {
14042+
if (it->getKind() == hlsl::UnusualAnnotation::UA_ConstantPacking) {
14043+
const hlsl::ConstantPacking *packOffset =
14044+
cast<hlsl::ConstantPacking>(it);
14045+
unsigned CBufferOffset = packOffset->Subcomponent << 2;
14046+
CBufferOffset += packOffset->ComponentOffset;
14047+
// Change to bits.
14048+
Offset = CBufferOffset << 5;
14049+
HasPackOffset = true;
14050+
}
14051+
}
14052+
PackOffsetVec.emplace_back(Var, Offset);
14053+
if (Offset == UINT_MAX) {
14054+
HasNonPackOffset = true;
14055+
}
14056+
}
14057+
14058+
if (HasPackOffset && HasNonPackOffset) {
14059+
Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
14060+
} else if (HasPackOffset) {
14061+
// Make sure no overlap in packoffset.
14062+
llvm::SmallDenseMap<VarDecl *, std::pair<unsigned, unsigned>>
14063+
PackOffsetRanges;
14064+
for (auto &Pair : PackOffsetVec) {
14065+
VarDecl *Var = Pair.first;
14066+
unsigned Size = Context.getTypeSize(Var->getType());
14067+
unsigned Begin = Pair.second;
14068+
unsigned End = Begin + Size;
14069+
for (auto &Range : PackOffsetRanges) {
14070+
VarDecl *OtherVar = Range.first;
14071+
unsigned OtherBegin = Range.second.first;
14072+
unsigned OtherEnd = Range.second.second;
14073+
if (Begin < OtherEnd && OtherBegin < Begin) {
14074+
Diag(Var->getLocation(), diag::err_hlsl_packoffset_overlap)
14075+
<< Var << OtherVar;
14076+
break;
14077+
} else if (OtherBegin < End && Begin < OtherBegin) {
14078+
Diag(Var->getLocation(), diag::err_hlsl_packoffset_overlap)
14079+
<< Var << OtherVar;
14080+
break;
14081+
}
14082+
}
14083+
PackOffsetRanges[Var] = std::make_pair(Begin, End);
14084+
}
14085+
}
1402414086
PopDeclContext();
1402514087
}
1402614088

tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.packoffset.error.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: not %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s
22

33
cbuffer MyCBuffer {
4-
float4 data1;
4+
float4 data1 : packoffset(c0);
55
float4 data2 : packoffset(c2);
66
float data3 : packoffset(c0); // error: overlap
77
float data4 : packoffset(c10.z);

tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.packoffset.hlsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ struct S {
1414
};
1515

1616
cbuffer MyCBuffer { // Offset
17-
float4 data1; // 0
17+
float4 data1 : packoffset(c0); // 0
1818
float4 data2 : packoffset(c2); // 2 * 16 = 32
1919
float data3 : packoffset(c3.y); // 3 * 16 + 1 * 4 = 52
2020
float data4 : packoffset(c3.z); // 3 * 16 + 2 * 4 = 56
21-
float data5; // 60
21+
float data5 : packoffset(c3.w); // 60
2222
float4 data6 : packoffset(c100); // 100 * 16 = 1600
2323
float2x3 data7 : packoffset(c110); // 110 * 16 = 1760
2424
S data8 : packoffset(c150); // 150 * 16 = 2400
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %dxc -E main -T lib_6_6 %s -verify
2+
3+
// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
4+
cbuffer Mix
5+
{
6+
float4 M1 : packoffset(c0);
7+
float M2;
8+
float M3 : packoffset(c1.y);
9+
}
10+
11+
// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
12+
cbuffer Mix2
13+
{
14+
float4 M4;
15+
float M5 : packoffset(c1.y);
16+
float M6 ;
17+
}
18+
19+
// expected-error@+1{{packoffset is only allowed in a constant buffer}}
20+
float4 g : packoffset(c0);
21+
22+
cbuffer IllegalOffset
23+
{
24+
// expected-error@+1{{register type is unsupported - available types are 'b', 'c', 'i', 's', 't', 'u'}}
25+
float4 i1 : packoffset(t2);
26+
// expected-error@+1{{packoffset component should indicate offset with one of x, y, z, w, r, g, b, or a}}
27+
float i2 : packoffset(c1.m);
28+
}
29+
30+
cbuffer Overlap
31+
{
32+
float4 o1 : packoffset(c0);
33+
// expected-error@+1{{packoffset overlap between 'o2', 'o1'}}
34+
float2 o2 : packoffset(c0.z);
35+
}
36+
37+
cbuffer CrossReg
38+
{
39+
// expected-error@+1{{register or offset bind not valid}}
40+
float4 c1 : packoffset(c0.y);
41+
// expected-error@+1{{register or offset bind not valid}}
42+
float2 c2 : packoffset(c1.w);
43+
}
44+
45+
struct ST {
46+
float s;
47+
};
48+
49+
cbuffer Aggregate
50+
{
51+
// expected-error@+1{{register or offset bind not valid}}
52+
ST A1 : packoffset(c0.y);
53+
// expected-error@+1{{register or offset bind not valid}}
54+
float A2[2] : packoffset(c1.w);
55+
// expected-error@+1{{register or offset bind not valid}}
56+
float2x1 m2 : packoffset(c12.z);
57+
}

tools/clang/test/SemaHLSL/packreg.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ cbuffer MyBuffer2
575575
Texture2D<float4> Texture : register(t0);
576576
Texture2D<float4> Texture_ : register(t0);
577577
sampler Sampler : register(s0);
578-
578+
// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
579579
cbuffer Parameters : register(b0)
580580
{
581581
float4 DiffuseColor : packoffset(c0) : register(c0);

tools/clang/test/SemaHLSL/semantics.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ float g_foo1 : foo;
66
float g_foo2 : foo : fubar;
77
float g_foo3 : foo : fubar : register(c3);
88
float g_foo4 : register(c4) : foo : fubar;
9-
9+
// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
1010
cbuffer CBInit : register(b2)
1111
{
1212
float g2_foo1 : foo; /* fxc-error {{X3530: cannot mix packoffset elements with nonpackoffset elements in a cbuffer}} */

0 commit comments

Comments
 (0)