[clang] [HLSL] reenable add packoffset in AST (PR #91474)
Xiang Li via cfe-commits
cfe-commits at lists.llvm.org
Wed May 8 07:14:08 PDT 2024
https://github.com/python3kgae updated https://github.com/llvm/llvm-project/pull/91474
>From 251bbfbd77f9fa968a3fe76156e216f27eeb973f Mon Sep 17 00:00:00 2001
From: Xiang Li <python3kgae at outlook.com>
Date: Wed, 8 May 2024 09:48:30 -0400
Subject: [PATCH 1/2] Revert "Revert "[HLSL] Support packoffset attribute in
AST (#89836)""
This reverts commit 5809281176c75712752fe152c160ce964993726e.
---
clang/include/clang/Basic/Attr.td | 12 ++
clang/include/clang/Basic/AttrDocs.td | 20 +++
clang/include/clang/Basic/DiagnosticGroups.td | 3 +
.../clang/Basic/DiagnosticParseKinds.td | 2 +
.../clang/Basic/DiagnosticSemaKinds.td | 5 +
clang/lib/Parse/ParseHLSL.cpp | 88 +++++++++++++
clang/lib/Sema/SemaDeclAttr.cpp | 52 ++++++++
clang/lib/Sema/SemaHLSL.cpp | 80 ++++++++++++
clang/test/AST/HLSL/packoffset.hlsl | 100 ++++++++++++++
clang/test/SemaHLSL/packoffset-invalid.hlsl | 122 ++++++++++++++++++
10 files changed, 484 insertions(+)
create mode 100644 clang/test/AST/HLSL/packoffset.hlsl
create mode 100644 clang/test/SemaHLSL/packoffset-invalid.hlsl
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 0225598cbbe8a..52552ba488560 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4415,6 +4415,18 @@ def HLSLResourceBinding: InheritableAttr {
let Documentation = [HLSLResourceBindingDocs];
}
+def HLSLPackOffset: HLSLAnnotationAttr {
+ let Spellings = [HLSLAnnotation<"packoffset">];
+ let LangOpts = [HLSL];
+ let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
+ let Documentation = [HLSLPackOffsetDocs];
+ let AdditionalMembers = [{
+ unsigned getOffset() {
+ return subcomponent * 4 + component;
+ }
+ }];
+}
+
def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_DispatchThreadID">];
let Subjects = SubjectList<[ParmVar, Field]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 8e6faabfae647..f351822ac74bd 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -7408,6 +7408,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}
+def HLSLPackOffsetDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The packoffset attribute is used to change the layout of a cbuffer.
+Attribute spelling in HLSL is: ``packoffset( c[Subcomponent][.component] )``.
+A subcomponent is a register number, which is an integer. A component is in the form of [.xyzw].
+
+Examples:
+
+.. code-block:: c++
+
+ cbuffer A {
+ float3 a : packoffset(c0.y);
+ float4 b : packoffset(c4);
+ }
+
+The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset
+ }];
+}
+
def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 60f87da2a7387..2beb1d45124b4 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1507,6 +1507,9 @@ def BranchProtection : DiagGroup<"branch-protection">;
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;
+// Warning for mix packoffset and non-packoffset.
+def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;
+
// Warnings for DXIL validation
def DXILValidation : DiagGroup<"dxil-validation">;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index fdffb35ea0d95..bc9d7cacc50b7 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1754,5 +1754,7 @@ def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hls
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;
+def err_hlsl_unsupported_component : Error<"invalid component '%0' used; expected 'x', 'y', 'z', or 'w'">;
+def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier '%0' for packoffset, expected 'c'">;
} // end of Parser diagnostics
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9317ae675c72b..d6863f90edb6e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12184,6 +12184,11 @@ def err_hlsl_init_priority_unsupported : Error<
def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
+def warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
+ InGroup<HLSLMixPackOffset>;
+def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
+def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross register boundary">;
+def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index f4cbece31f181..e9c8d6dca7bf5 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -183,6 +183,94 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
return;
}
} break;
+ case ParsedAttr::AT_HLSLPackOffset: {
+ // Parse 'packoffset( c[Subcomponent][.component] )'.
+ // Check '('.
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ // Check c[Subcomponent] as an identifier.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef OffsetStr = Tok.getIdentifierInfo()->getName();
+ SourceLocation SubComponentLoc = Tok.getLocation();
+ if (OffsetStr[0] != 'c') {
+ Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)
+ << OffsetStr;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ OffsetStr = OffsetStr.substr(1);
+ unsigned SubComponent = 0;
+ if (!OffsetStr.empty()) {
+ // Make sure SubComponent is a number.
+ if (OffsetStr.getAsInteger(10, SubComponent)) {
+ Diag(SubComponentLoc.getLocWithOffset(1),
+ diag::err_hlsl_unsupported_register_number);
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ }
+ unsigned Component = 0;
+ ConsumeToken(); // consume identifier.
+ SourceLocation ComponentLoc;
+ if (Tok.is(tok::period)) {
+ ConsumeToken(); // consume period.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef ComponentStr = Tok.getIdentifierInfo()->getName();
+ ComponentLoc = Tok.getLocation();
+ ConsumeToken(); // consume identifier.
+ // Make sure Component is a single character.
+ if (ComponentStr.size() != 1) {
+ Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
+ << ComponentStr;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ switch (ComponentStr[0]) {
+ case 'x':
+ case 'r':
+ Component = 0;
+ break;
+ case 'y':
+ case 'g':
+ Component = 1;
+ break;
+ case 'z':
+ case 'b':
+ Component = 2;
+ break;
+ case 'w':
+ case 'a':
+ Component = 3;
+ break;
+ default:
+ Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
+ << ComponentStr;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ }
+ ASTContext &Ctx = Actions.getASTContext();
+ QualType SizeTy = Ctx.getSizeType();
+ uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
+ ArgExprs.push_back(IntegerLiteral::Create(
+ Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));
+ ArgExprs.push_back(IntegerLiteral::Create(
+ Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ } break;
case ParsedAttr::UnknownAttribute:
Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
return;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 6ca42856459f7..6d957ac09e1c3 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7309,6 +7309,55 @@ static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
}
+static void handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
+ << AL << "shader constant in a constant buffer";
+ return;
+ }
+
+ uint32_t SubComponent;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), SubComponent))
+ return;
+ uint32_t Component;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Component))
+ return;
+
+ QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
+ // Check if T is an array or struct type.
+ // TODO: mark matrix type as aggregate type.
+ bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
+
+ // Check Component is valid for T.
+ if (Component) {
+ unsigned Size = S.getASTContext().getTypeSize(T);
+ if (IsAggregateTy || Size > 128) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
+ return;
+ } else {
+ // Make sure Component + sizeof(T) <= 4.
+ if ((Component * 32 + Size) > 128) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
+ return;
+ }
+ QualType EltTy = T;
+ if (const auto *VT = T->getAs<VectorType>())
+ EltTy = VT->getElementType();
+ unsigned Align = S.getASTContext().getTypeAlign(EltTy);
+ if (Align > 32 && Component == 1) {
+ // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
+ // So we only need to check Component 1 here.
+ S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
+ << Align << EltTy;
+ return;
+ }
+ }
+ }
+
+ D->addAttr(::new (S.Context)
+ HLSLPackOffsetAttr(S.Context, AL, SubComponent, Component));
+}
+
static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation ArgLoc;
@@ -9730,6 +9779,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLPackOffset:
+ handleHLSLPackOffsetAttr(S, D, AL);
+ break;
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index bb9e37f18d370..6a12c417e2f3a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -39,9 +39,89 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}
+// Calculate the size of a legacy cbuffer type based on
+// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
+static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
+ QualType T) {
+ unsigned Size = 0;
+ constexpr unsigned CBufferAlign = 128;
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ for (const FieldDecl *Field : RD->fields()) {
+ QualType Ty = Field->getType();
+ unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
+ unsigned FieldAlign = 32;
+ if (Ty->isAggregateType())
+ FieldAlign = CBufferAlign;
+ Size = llvm::alignTo(Size, FieldAlign);
+ Size += FieldSize;
+ }
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ if (unsigned ElementCount = AT->getSize().getZExtValue()) {
+ unsigned ElementSize =
+ calculateLegacyCbufferSize(Context, AT->getElementType());
+ unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
+ Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
+ }
+ } else if (const VectorType *VT = T->getAs<VectorType>()) {
+ unsigned ElementCount = VT->getNumElements();
+ unsigned ElementSize =
+ calculateLegacyCbufferSize(Context, VT->getElementType());
+ Size = ElementSize * ElementCount;
+ } else {
+ Size = Context.getTypeSize(T);
+ }
+ return Size;
+}
+
void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
BufDecl->setRBraceLoc(RBrace);
+
+ // Validate packoffset.
+ llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
+ bool HasPackOffset = false;
+ bool HasNonPackOffset = false;
+ for (auto *Field : BufDecl->decls()) {
+ VarDecl *Var = dyn_cast<VarDecl>(Field);
+ if (!Var)
+ continue;
+ if (Field->hasAttr<HLSLPackOffsetAttr>()) {
+ PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
+ HasPackOffset = true;
+ } else {
+ HasNonPackOffset = true;
+ }
+ }
+
+ if (HasPackOffset && HasNonPackOffset)
+ Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
+
+ if (HasPackOffset) {
+ ASTContext &Context = getASTContext();
+ // Make sure no overlap in packoffset.
+ // Sort PackOffsetVec by offset.
+ std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
+ [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
+ const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
+ return LHS.second->getOffset() < RHS.second->getOffset();
+ });
+
+ for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
+ VarDecl *Var = PackOffsetVec[i].first;
+ HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
+ unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
+ unsigned Begin = Attr->getOffset() * 32;
+ unsigned End = Begin + Size;
+ unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
+ if (End > NextBegin) {
+ VarDecl *NextVar = PackOffsetVec[i + 1].first;
+ Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
+ << NextVar << Var;
+ }
+ }
+ }
+
SemaRef.PopDeclContext();
}
diff --git a/clang/test/AST/HLSL/packoffset.hlsl b/clang/test/AST/HLSL/packoffset.hlsl
new file mode 100644
index 0000000000000..9cfd88eeec330
--- /dev/null
+++ b/clang/test/AST/HLSL/packoffset.hlsl
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.3-library -S -finclude-default-header -ast-dump -x hlsl %s | FileCheck %s
+
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer A
+cbuffer A
+{
+ // CHECK-NEXT: VarDecl {{.*}} A1 'float4'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
+ float4 A1 : packoffset(c);
+ // CHECK-NEXT: VarDecl {{.*}} col:11 A2 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
+ float A2 : packoffset(c1);
+ // CHECK-NEXT: VarDecl {{.*}} col:11 A3 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 1
+ float A3 : packoffset(c1.y);
+}
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer B
+cbuffer B
+{
+ // CHECK: VarDecl {{.*}} B0 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
+ float B0 : packoffset(c0.g);
+ // CHECK-NEXT: VarDecl {{.*}} B1 'double'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
+ double B1 : packoffset(c0.b);
+ // CHECK-NEXT: VarDecl {{.*}} B2 'half'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
+ half B2 : packoffset(c0.r);
+}
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer C
+cbuffer C
+{
+ // CHECK: VarDecl {{.*}} C0 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1
+ float C0 : packoffset(c0.y);
+ // CHECK-NEXT: VarDecl {{.*}} C1 'float2'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2
+ float2 C1 : packoffset(c0.z);
+ // CHECK-NEXT: VarDecl {{.*}} C2 'half'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0
+ half C2 : packoffset(c0.x);
+}
+
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer D
+cbuffer D
+{
+ // CHECK: VarDecl {{.*}} D0 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
+ float D0 : packoffset(c0.y);
+ // CHECK-NEXT: VarDecl {{.*}} D1 'float[2]'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
+ float D1[2] : packoffset(c1.x);
+ // CHECK-NEXT: VarDecl {{.*}} D2 'half3'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 1
+ half3 D2 : packoffset(c2.y);
+ // CHECK-NEXT: VarDecl {{.*}} D3 'double'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
+ double D3 : packoffset(c0.z);
+}
+
+struct ST {
+ float a;
+ float2 b;
+ half c;
+};
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer S
+cbuffer S {
+ // CHECK: VarDecl {{.*}} S0 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
+ float S0 : packoffset(c0.y);
+ // CHECK: VarDecl {{.*}} S1 'ST'
+ // CHECK: HLSLPackOffsetAttr {{.*}} 1 0
+ ST S1 : packoffset(c1);
+ // CHECK: VarDecl {{.*}} S2 'double2'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 0
+ double2 S2 : packoffset(c2);
+}
+
+struct ST2 {
+ float s0;
+ ST s1;
+ half s2;
+};
+
+// CHECK: HLSLBufferDecl {{.*}} cbuffer S2
+cbuffer S2 {
+ // CHECK: VarDecl {{.*}} S20 'float'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 3
+ float S20 : packoffset(c0.a);
+ // CHECK: VarDecl {{.*}} S21 'ST2'
+ // CHECK: HLSLPackOffsetAttr {{.*}} 1 0
+ ST2 S21 : packoffset(c1);
+ // CHECK: VarDecl {{.*}} S22 'half'
+ // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 3 1
+ half S22 : packoffset(c3.y);
+}
diff --git a/clang/test/SemaHLSL/packoffset-invalid.hlsl b/clang/test/SemaHLSL/packoffset-invalid.hlsl
new file mode 100644
index 0000000000000..c5983f6fd7e07
--- /dev/null
+++ b/clang/test/SemaHLSL/packoffset-invalid.hlsl
@@ -0,0 +1,122 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -verify %s
+
+// expected-warning at +1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
+cbuffer Mix
+{
+ float4 M1 : packoffset(c0);
+ float M2;
+ float M3 : packoffset(c1.y);
+}
+
+// expected-warning at +1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
+cbuffer Mix2
+{
+ float4 M4;
+ float M5 : packoffset(c1.y);
+ float M6 ;
+}
+
+// expected-error at +1{{attribute 'packoffset' only applies to shader constant in a constant buffer}}
+float4 g : packoffset(c0);
+
+cbuffer IllegalOffset
+{
+ // expected-error at +1{{invalid resource class specifier 't2' for packoffset, expected 'c'}}
+ float4 i1 : packoffset(t2);
+ // expected-error at +1{{invalid component 'm' used; expected 'x', 'y', 'z', or 'w'}}
+ float i2 : packoffset(c1.m);
+}
+
+cbuffer Overlap
+{
+ float4 o1 : packoffset(c0);
+ // expected-error at +1{{packoffset overlap between 'o2', 'o1'}}
+ float2 o2 : packoffset(c0.z);
+}
+
+cbuffer CrossReg
+{
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ float4 c1 : packoffset(c0.y);
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ float2 c2 : packoffset(c1.w);
+}
+
+struct ST {
+ float s;
+};
+
+cbuffer Aggregate
+{
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ ST A1 : packoffset(c0.y);
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ float A2[2] : packoffset(c1.w);
+}
+
+cbuffer Double {
+ // expected-error at +1{{packoffset at 'y' not match alignment 64 required by 'double'}}
+ double d : packoffset(c.y);
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ double2 d2 : packoffset(c.z);
+ // expected-error at +1{{packoffset cannot cross register boundary}}
+ double3 d3 : packoffset(c.z);
+}
+
+cbuffer ParsingFail {
+// expected-error at +1{{expected identifier}}
+float pf0 : packoffset();
+// expected-error at +1{{expected identifier}}
+float pf1 : packoffset((c0));
+// expected-error at +1{{expected ')'}}
+float pf2 : packoffset(c0, x);
+// expected-error at +1{{invalid component 'X' used}}
+float pf3 : packoffset(c.X);
+// expected-error at +1{{expected '(' after ''}}
+float pf4 : packoffset;
+// expected-error at +1{{expected identifier}}
+float pf5 : packoffset(;
+// expected-error at +1{{expected '(' after '}}
+float pf6 : packoffset);
+// expected-error at +1{{expected '(' after '}}
+float pf7 : packoffset c0.x;
+
+// expected-error at +1{{invalid component 'xy' used}}
+float pf8 : packoffset(c0.xy);
+// expected-error at +1{{invalid component 'rg' used}}
+float pf9 : packoffset(c0.rg);
+// expected-error at +1{{invalid component 'yes' used}}
+float pf10 : packoffset(c0.yes);
+// expected-error at +1{{invalid component 'woo'}}
+float pf11 : packoffset(c0.woo);
+// expected-error at +1{{invalid component 'xr' used}}
+float pf12 : packoffset(c0.xr);
+}
+
+struct ST2 {
+ float a;
+ float2 b;
+};
+
+cbuffer S {
+ float S0 : packoffset(c0.y);
+ ST2 S1[2] : packoffset(c1);
+ // expected-error at +1{{packoffset overlap between 'S2', 'S1'}}
+ half2 S2 : packoffset(c1.w);
+ half2 S3 : packoffset(c2.w);
+}
+
+struct ST23 {
+ float s0;
+ ST2 s1;
+};
+
+cbuffer S2 {
+ float S20 : packoffset(c0.y);
+ ST2 S21 : packoffset(c1);
+ half2 S22 : packoffset(c2.w);
+ double S23[2] : packoffset(c3);
+ // expected-error at +1{{packoffset overlap between 'S24', 'S23'}}
+ float S24 : packoffset(c3.z);
+ float S25 : packoffset(c4.z);
+}
>From 163dd417eb333a089d0396a34ee5c9de59a979c4 Mon Sep 17 00:00:00 2001
From: Xiang Li <python3kgae at outlook.com>
Date: Wed, 8 May 2024 10:07:45 -0400
Subject: [PATCH 2/2] Add -fnative-half-type for half type.
---
clang/test/AST/HLSL/packoffset.hlsl | 2 +-
clang/test/SemaHLSL/packoffset-invalid.hlsl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/AST/HLSL/packoffset.hlsl b/clang/test/AST/HLSL/packoffset.hlsl
index 9cfd88eeec330..060288c2f7f76 100644
--- a/clang/test/AST/HLSL/packoffset.hlsl
+++ b/clang/test/AST/HLSL/packoffset.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.3-library -S -finclude-default-header -ast-dump -x hlsl %s | FileCheck %s
+// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.3-library -S -finclude-default-header -fnative-half-type -ast-dump -x hlsl %s | FileCheck %s
// CHECK: HLSLBufferDecl {{.*}} cbuffer A
diff --git a/clang/test/SemaHLSL/packoffset-invalid.hlsl b/clang/test/SemaHLSL/packoffset-invalid.hlsl
index c5983f6fd7e07..526a511edf1f2 100644
--- a/clang/test/SemaHLSL/packoffset-invalid.hlsl
+++ b/clang/test/SemaHLSL/packoffset-invalid.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -verify %s
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -fnative-half-type -verify %s
// expected-warning at +1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
cbuffer Mix
More information about the cfe-commits
mailing list