https://github.com/python3kgae created https://github.com/llvm/llvm-project/pull/91474
Fix the test fail caused by missing -fnative-half-type. For #57914 >From 5809281176c75712752fe152c160ce964993726e Mon Sep 17 00:00:00 2001 From: Xiang Li <python3k...@outlook.com> Date: Wed, 8 May 2024 09:46:44 -0400 Subject: [PATCH 1/3] Revert "[HLSL] Support packoffset attribute in AST (#89836)" This reverts commit c5509fedc5757fffece385d9d068e36b26793ade. --- 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 deletions(-) delete mode 100644 clang/test/AST/HLSL/packoffset.hlsl delete 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 52552ba488560..0225598cbbe8a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4415,18 +4415,6 @@ 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 f351822ac74bd..8e6faabfae647 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7408,26 +7408,6 @@ 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 2beb1d45124b4..60f87da2a7387 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1507,9 +1507,6 @@ 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 bc9d7cacc50b7..fdffb35ea0d95 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1754,7 +1754,5 @@ 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 d6863f90edb6e..9317ae675c72b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12184,11 +12184,6 @@ 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 e9c8d6dca7bf5..f4cbece31f181 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -183,94 +183,6 @@ 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 6d957ac09e1c3..6ca42856459f7 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7309,55 +7309,6 @@ 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; @@ -9779,9 +9730,6 @@ 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 6a12c417e2f3a..bb9e37f18d370 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,89 +39,9 @@ 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 deleted file mode 100644 index 9cfd88eeec330..0000000000000 --- a/clang/test/AST/HLSL/packoffset.hlsl +++ /dev/null @@ -1,100 +0,0 @@ -// 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 deleted file mode 100644 index c5983f6fd7e07..0000000000000 --- a/clang/test/SemaHLSL/packoffset-invalid.hlsl +++ /dev/null @@ -1,122 +0,0 @@ -// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -verify %s - -// expected-warning@+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@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}} -cbuffer Mix2 -{ - float4 M4; - float M5 : packoffset(c1.y); - float M6 ; -} - -// expected-error@+1{{attribute 'packoffset' only applies to shader constant in a constant buffer}} -float4 g : packoffset(c0); - -cbuffer IllegalOffset -{ - // expected-error@+1{{invalid resource class specifier 't2' for packoffset, expected 'c'}} - float4 i1 : packoffset(t2); - // expected-error@+1{{invalid component 'm' used; expected 'x', 'y', 'z', or 'w'}} - float i2 : packoffset(c1.m); -} - -cbuffer Overlap -{ - float4 o1 : packoffset(c0); - // expected-error@+1{{packoffset overlap between 'o2', 'o1'}} - float2 o2 : packoffset(c0.z); -} - -cbuffer CrossReg -{ - // expected-error@+1{{packoffset cannot cross register boundary}} - float4 c1 : packoffset(c0.y); - // expected-error@+1{{packoffset cannot cross register boundary}} - float2 c2 : packoffset(c1.w); -} - -struct ST { - float s; -}; - -cbuffer Aggregate -{ - // expected-error@+1{{packoffset cannot cross register boundary}} - ST A1 : packoffset(c0.y); - // expected-error@+1{{packoffset cannot cross register boundary}} - float A2[2] : packoffset(c1.w); -} - -cbuffer Double { - // expected-error@+1{{packoffset at 'y' not match alignment 64 required by 'double'}} - double d : packoffset(c.y); - // expected-error@+1{{packoffset cannot cross register boundary}} - double2 d2 : packoffset(c.z); - // expected-error@+1{{packoffset cannot cross register boundary}} - double3 d3 : packoffset(c.z); -} - -cbuffer ParsingFail { -// expected-error@+1{{expected identifier}} -float pf0 : packoffset(); -// expected-error@+1{{expected identifier}} -float pf1 : packoffset((c0)); -// expected-error@+1{{expected ')'}} -float pf2 : packoffset(c0, x); -// expected-error@+1{{invalid component 'X' used}} -float pf3 : packoffset(c.X); -// expected-error@+1{{expected '(' after ''}} -float pf4 : packoffset; -// expected-error@+1{{expected identifier}} -float pf5 : packoffset(; -// expected-error@+1{{expected '(' after '}} -float pf6 : packoffset); -// expected-error@+1{{expected '(' after '}} -float pf7 : packoffset c0.x; - -// expected-error@+1{{invalid component 'xy' used}} -float pf8 : packoffset(c0.xy); -// expected-error@+1{{invalid component 'rg' used}} -float pf9 : packoffset(c0.rg); -// expected-error@+1{{invalid component 'yes' used}} -float pf10 : packoffset(c0.yes); -// expected-error@+1{{invalid component 'woo'}} -float pf11 : packoffset(c0.woo); -// expected-error@+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@+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@+1{{packoffset overlap between 'S24', 'S23'}} - float S24 : packoffset(c3.z); - float S25 : packoffset(c4.z); -} >From 3003b3a8562b3a7378af00ebeee6f0394c3f8522 Mon Sep 17 00:00:00 2001 From: Xiang Li <python3k...@outlook.com> Date: Wed, 8 May 2024 09:48:30 -0400 Subject: [PATCH 2/3] 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@+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@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}} +cbuffer Mix2 +{ + float4 M4; + float M5 : packoffset(c1.y); + float M6 ; +} + +// expected-error@+1{{attribute 'packoffset' only applies to shader constant in a constant buffer}} +float4 g : packoffset(c0); + +cbuffer IllegalOffset +{ + // expected-error@+1{{invalid resource class specifier 't2' for packoffset, expected 'c'}} + float4 i1 : packoffset(t2); + // expected-error@+1{{invalid component 'm' used; expected 'x', 'y', 'z', or 'w'}} + float i2 : packoffset(c1.m); +} + +cbuffer Overlap +{ + float4 o1 : packoffset(c0); + // expected-error@+1{{packoffset overlap between 'o2', 'o1'}} + float2 o2 : packoffset(c0.z); +} + +cbuffer CrossReg +{ + // expected-error@+1{{packoffset cannot cross register boundary}} + float4 c1 : packoffset(c0.y); + // expected-error@+1{{packoffset cannot cross register boundary}} + float2 c2 : packoffset(c1.w); +} + +struct ST { + float s; +}; + +cbuffer Aggregate +{ + // expected-error@+1{{packoffset cannot cross register boundary}} + ST A1 : packoffset(c0.y); + // expected-error@+1{{packoffset cannot cross register boundary}} + float A2[2] : packoffset(c1.w); +} + +cbuffer Double { + // expected-error@+1{{packoffset at 'y' not match alignment 64 required by 'double'}} + double d : packoffset(c.y); + // expected-error@+1{{packoffset cannot cross register boundary}} + double2 d2 : packoffset(c.z); + // expected-error@+1{{packoffset cannot cross register boundary}} + double3 d3 : packoffset(c.z); +} + +cbuffer ParsingFail { +// expected-error@+1{{expected identifier}} +float pf0 : packoffset(); +// expected-error@+1{{expected identifier}} +float pf1 : packoffset((c0)); +// expected-error@+1{{expected ')'}} +float pf2 : packoffset(c0, x); +// expected-error@+1{{invalid component 'X' used}} +float pf3 : packoffset(c.X); +// expected-error@+1{{expected '(' after ''}} +float pf4 : packoffset; +// expected-error@+1{{expected identifier}} +float pf5 : packoffset(; +// expected-error@+1{{expected '(' after '}} +float pf6 : packoffset); +// expected-error@+1{{expected '(' after '}} +float pf7 : packoffset c0.x; + +// expected-error@+1{{invalid component 'xy' used}} +float pf8 : packoffset(c0.xy); +// expected-error@+1{{invalid component 'rg' used}} +float pf9 : packoffset(c0.rg); +// expected-error@+1{{invalid component 'yes' used}} +float pf10 : packoffset(c0.yes); +// expected-error@+1{{invalid component 'woo'}} +float pf11 : packoffset(c0.woo); +// expected-error@+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@+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@+1{{packoffset overlap between 'S24', 'S23'}} + float S24 : packoffset(c3.z); + float S25 : packoffset(c4.z); +} >From 688a2585a81ddff49391de57772005c0b711d577 Mon Sep 17 00:00:00 2001 From: Xiang Li <python3k...@outlook.com> Date: Wed, 8 May 2024 10:07:45 -0400 Subject: [PATCH 3/3] 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@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}} cbuffer Mix _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits