From 0afad1cbf750b50c8e7d3193d069709a05713a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 29 Oct 2025 15:32:36 +0100 Subject: [PATCH] [HLSL] Rework semantic handling as attributes Previously, we had 2 level of attributes: - HLSLUnparsedSemantic - N attributes, one for each known system semantic. The first was assigned during parsing, and carried no other meaning than "there is a semantic token". It was then converted to one of the N attributes later during Sema. Those attributes also carried informations like "is indexable" or "is index explicit". This had a few issues: - there was no difference between a semantic attribute applied to a decl, and the effective semantic in the entrypoint use context. - having the indexable bit was not useful. - semantic constraints checks were split between .td files and sema. Also, existing implementation had effective attributes attached to the type decl or parameters, meaning struct decl reuse across entrypoints of in a nested type was not supported, even if legal in HLSL. This PR tried to simplifies semantic attribute by having 3 attributes: - HLSLUnpasedSemantic - HLSLParsedSemantic - HLSLAppliedSemantic Initial parsing emits an `HLSLUnparsedSemantic`. We simply say "here is an HLSL semantic token", but we don't do any semantic check. Then, Sema does initial validation and transforms an UnparseSemantic into a ParsedSemantic. This validates a system semantic is known, or that the associated type is valid (like uint3 for a ThreadIndex). Then, once we parse an actual shader entrypoint, we can know how semantics are used in a real context. This step emits a list of AppliedSemantic. Those are the actual semantic in use for this specific entrypoint. Those attributes are attached to each entrypoint parameter, as a flat list matching the semantic structure flattening HLSL defines. At this stage of sema, index collision or other stage compabitility checkes are carried. This allows codegen to simply iterate over this list and emit the proper DXIL or SPIR-V codegen. --- clang/include/clang/AST/Attr.h | 39 +---- clang/include/clang/Basic/Attr.td | 44 ++--- clang/include/clang/Basic/AttrDocs.td | 61 ------- clang/include/clang/Sema/SemaHLSL.h | 29 ++-- clang/lib/CodeGen/CGHLSLRuntime.cpp | 85 +++++---- clang/lib/CodeGen/CGHLSLRuntime.h | 28 +-- clang/lib/Sema/SemaHLSL.cpp | 163 +++++++++--------- .../semantics/DispatchThreadID-noindex.hlsl | 2 +- .../semantics/SV_GroupID-noindex.hlsl | 7 +- .../semantics/SV_GroupThreadID-noindex.hlsl | 2 +- .../CodeGenHLSL/semantics/semantic.array.hlsl | 10 +- .../hlsl_annotations_on_struct_members.hlsl | 2 +- .../SemaHLSL/Semantics/entry_parameter.hlsl | 17 +- .../test/SemaHLSL/Semantics/position.ps.hlsl | 5 +- .../Semantics/position.ps.struct.hlsl | 9 +- .../Semantics/position.ps.struct.reuse.hlsl | 26 +++ .../SemaHLSL/Semantics/semantics-valid.hlsl | 51 +++--- .../Semantics/valid_entry_parameter.hlsl | 30 ++-- clang/test/TableGen/HLSLAttribute-errors.td | 2 +- clang/utils/TableGen/ClangAttrEmitter.cpp | 18 +- 20 files changed, 269 insertions(+), 361 deletions(-) create mode 100644 clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 14d7caa0e16d7..e36184f232f8a 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -233,44 +233,19 @@ class HLSLAnnotationAttr : public InheritableAttr { } }; -class HLSLSemanticAttr : public HLSLAnnotationAttr { - unsigned SemanticIndex = 0; - LLVM_PREFERRED_TYPE(bool) - unsigned SemanticIndexable : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned SemanticExplicitIndex : 1; - - Decl *TargetDecl = nullptr; - +class HLSLSemanticBaseAttr : public HLSLAnnotationAttr { protected: - HLSLSemanticAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, - attr::Kind AK, bool IsLateParsed, - bool InheritEvenIfAlreadyPresent, bool SemanticIndexable) + HLSLSemanticBaseAttr(ASTContext &Context, + const AttributeCommonInfo &CommonInfo, attr::Kind AK, + bool IsLateParsed, bool InheritEvenIfAlreadyPresent) : HLSLAnnotationAttr(Context, CommonInfo, AK, IsLateParsed, - InheritEvenIfAlreadyPresent) { - this->SemanticIndexable = SemanticIndexable; - this->SemanticExplicitIndex = false; - } + InheritEvenIfAlreadyPresent) {} public: - bool isSemanticIndexable() const { return SemanticIndexable; } - - void setSemanticIndex(unsigned SemanticIndex) { - this->SemanticIndex = SemanticIndex; - this->SemanticExplicitIndex = true; - } - - unsigned getSemanticIndex() const { return SemanticIndex; } - - bool isSemanticIndexExplicit() const { return SemanticExplicitIndex; } - - void setTargetDecl(Decl *D) { TargetDecl = D; } - Decl *getTargetDecl() const { return TargetDecl; } - // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { - return A->getKind() >= attr::FirstHLSLSemanticAttr && - A->getKind() <= attr::LastHLSLSemanticAttr; + return A->getKind() >= attr::FirstHLSLSemanticBaseAttr && + A->getKind() <= attr::LastHLSLSemanticBaseAttr; } }; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 1013bfc575747..9081897bbf147 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -779,18 +779,6 @@ class DeclOrStmtAttr : InheritableAttr; /// An attribute class for HLSL Annotations. class HLSLAnnotationAttr : InheritableAttr; -class HLSLSemanticAttr : HLSLAnnotationAttr { - bit SemanticIndexable = Indexable; - int SemanticIndex = 0; - bit SemanticExplicitIndex = 0; - - let Spellings = []; - let Subjects = SubjectList<[ParmVar, Field, Function]>; - let LangOpts = [HLSL]; - let Args = [DeclArgument, IntArgument<"SemanticIndex">, - BoolArgument<"SemanticExplicitIndex">]; -} - /// A target-specific attribute. This class is meant to be used as a mixin /// with InheritableAttr or Attr depending on the attribute's needs. class TargetSpecificAttr { @@ -5017,28 +5005,30 @@ def HLSLUnparsedSemantic : HLSLAnnotationAttr { let Documentation = [InternalOnly]; } -def HLSLUserSemantic : HLSLSemanticAttr { - let Documentation = [InternalOnly]; -} +class HLSLSemanticBaseAttr : HLSLAnnotationAttr { + int SemanticIndex = 0; -def HLSLSV_Position : HLSLSemanticAttr { - let Documentation = [HLSLSV_PositionDocs]; + let Spellings = []; + let Subjects = SubjectList<[ParmVar, Field, Function]>; + let LangOpts = [HLSL]; } -def HLSLSV_GroupThreadID : HLSLSemanticAttr { - let Documentation = [HLSLSV_GroupThreadIDDocs]; -} +def HLSLParsedSemantic : HLSLSemanticBaseAttr { + let Spellings = []; + let Subjects = SubjectList<[ParmVar, Field, Function]>; + let LangOpts = [HLSL]; + let Documentation = [InternalOnly]; -def HLSLSV_GroupID : HLSLSemanticAttr { - let Documentation = [HLSLSV_GroupIDDocs]; + let Args = [StringArgument<"SemanticName">, IntArgument<"SemanticIndex">]; } -def HLSLSV_GroupIndex : HLSLSemanticAttr { - let Documentation = [HLSLSV_GroupIndexDocs]; -} +def HLSLAppliedSemantic : HLSLSemanticBaseAttr { + let Spellings = []; + let Subjects = SubjectList<[ParmVar, Field, Function]>; + let LangOpts = [HLSL]; + let Documentation = [InternalOnly]; -def HLSLSV_DispatchThreadID : HLSLSemanticAttr { - let Documentation = [HLSLSV_DispatchThreadIDDocs]; + let Args = [StringArgument<"SemanticName">, IntArgument<"SemanticIndex">]; } def HLSLPackOffset: HLSLAnnotationAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 1be9a96aa44de..e064e69ce6ece 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8672,38 +8672,6 @@ randomized. }]; } -def HLSLSV_GroupThreadIDDocs : Documentation { - let Category = DocHLSLSemantics; - let Content = [{ -The ``SV_GroupThreadID`` semantic, when applied to an input parameter, specifies which -individual thread within a thread group is executing in. This attribute is -only supported in compute shaders. - -The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupthreadid - }]; -} - -def HLSLSV_GroupIDDocs : Documentation { - let Category = DocHLSLSemantics; - let Content = [{ -The ``SV_GroupID`` semantic, when applied to an input parameter, specifies which -thread group a shader is executing in. This attribute is only supported in compute shaders. - -The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupid - }]; -} - -def HLSLSV_GroupIndexDocs : Documentation { - let Category = DocHLSLSemantics; - let Content = [{ -The ``SV_GroupIndex`` semantic, when applied to an input parameter, specifies a -data binding to map the group index to the specified parameter. This attribute -is only supported in compute shaders. - -The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupindex - }]; -} - def HLSLResourceBindingDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -8750,35 +8718,6 @@ The full documentation is available here: https://learn.microsoft.com/en-us/wind }]; } -def HLSLSV_DispatchThreadIDDocs : Documentation { - let Category = DocHLSLSemantics; - let Content = [{ -The ``SV_DispatchThreadID`` semantic, when applied to an input parameter, -specifies a data binding to map the global thread offset within the Dispatch -call (per dimension of the group) to the specified parameter. -When applied to a field of a struct, the data binding is specified to the field -when the struct is used as a parameter type. -The semantic on the field is ignored when not used as a parameter. -This attribute is only supported in compute shaders. - -The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-dispatchthreadid - }]; -} - -def HLSLSV_PositionDocs : Documentation { - let Category = DocHLSLSemantics; - let Content = [{ -The ``SV_Position`` semantic, when applied to an input parameter in a pixel -shader, contains the location of the pixel center (x, y) in screen space. -This semantic can be applied to the parameter, or a field in a struct used -as an input parameter. -This attribute is supported as an input in pixel, hull, domain and mesh shaders. -This attribute is supported as an output in vertex, geometry and domain shaders. - -The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics - }]; -} - def HLSLGroupSharedAddressSpaceDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 28b03ac4c4676..86da323892f98 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -178,18 +178,11 @@ class SemaHLSL : public SemaBase { bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL); template - T *createSemanticAttr(const AttributeCommonInfo &ACI, NamedDecl *TargetDecl, + T *createSemanticAttr(const AttributeCommonInfo &ACI, std::optional Location) { - T *Attr = - ::new (getASTContext()) T(getASTContext(), ACI, TargetDecl, - Location.value_or(0), Location.has_value()); - - if (!Attr->isSemanticIndexable() && Location.has_value()) { - Diag(Attr->getLocation(), diag::err_hlsl_semantic_indexing_not_supported) - << Attr->getAttrName()->getName(); - return nullptr; - } - return Attr; + return ::new (getASTContext()) + T(getASTContext(), ACI, ACI.getAttrName()->getName(), + Location.value_or(0)); } void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, @@ -247,7 +240,7 @@ class SemaHLSL : public SemaBase { IdentifierInfo *RootSigOverrideIdent = nullptr; struct SemanticInfo { - HLSLSemanticAttr *Semantic; + HLSLParsedSemanticAttr *Semantic; std::optional Index; }; @@ -257,14 +250,14 @@ class SemaHLSL : public SemaBase { const RecordType *RT); void checkSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, - const HLSLSemanticAttr *SemanticAttr); - HLSLSemanticAttr *createSemantic(const SemanticInfo &Semantic, - DeclaratorDecl *TargetDecl); - bool determineActiveSemanticOnScalar(FunctionDecl *FD, DeclaratorDecl *D, + const HLSLAppliedSemanticAttr *SemanticAttr); + bool determineActiveSemanticOnScalar(FunctionDecl *FD, + DeclaratorDecl *OutputDecl, + DeclaratorDecl *D, SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics); - bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic, + bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *OutputDecl, + DeclaratorDecl *D, SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics); void processExplicitBindingsOnDecl(VarDecl *D); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index e392a12044a39..d40ba2539cd00 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -587,7 +587,7 @@ static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, llvm::Value * CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, - HLSLSemanticAttr *Semantic, + HLSLAppliedSemanticAttr *Semantic, std::optional Index) { Twine BaseName = Twine(Semantic->getAttrName()->getName()); Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); @@ -605,7 +605,7 @@ CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, llvm::Value * CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, - HLSLSemanticAttr *Semantic, + HLSLAppliedSemanticAttr *Semantic, std::optional Index) { Twine BaseName = Twine(Semantic->getAttrName()->getName()); Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); @@ -625,7 +625,7 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, - HLSLSemanticAttr *Semantic, std::optional Index) { + HLSLAppliedSemanticAttr *Semantic, std::optional Index) { if (CGM.getTarget().getTriple().isSPIRV()) return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index); @@ -637,14 +637,16 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, - Attr *Semantic, std::optional Index) { - if (isa(Semantic)) { + HLSLSemanticBaseAttr *Semantic, std::optional Index) { + + std::string SemanticName = Semantic->getAttrName()->getName().upper(); + if (SemanticName == "SV_GROUPINDEX") { llvm::Function *GroupIndex = CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic()); return B.CreateCall(FunctionCallee(GroupIndex)); } - if (isa(Semantic)) { + if (SemanticName == "SV_DISPATCHTHREADID") { llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic(); llvm::Function *ThreadIDIntrinsic = llvm::Intrinsic::isOverloaded(IntrinID) @@ -653,7 +655,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( return buildVectorInput(B, ThreadIDIntrinsic, Type); } - if (isa(Semantic)) { + if (SemanticName == "SV_GROUPTHREADID") { llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic(); llvm::Function *GroupThreadIDIntrinsic = llvm::Intrinsic::isOverloaded(IntrinID) @@ -662,7 +664,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( return buildVectorInput(B, GroupThreadIDIntrinsic, Type); } - if (isa(Semantic)) { + if (SemanticName == "SV_GROUPID") { llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic(); llvm::Function *GroupIDIntrinsic = llvm::Intrinsic::isOverloaded(IntrinID) @@ -671,44 +673,31 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( return buildVectorInput(B, GroupIDIntrinsic, Type); } - if (HLSLSV_PositionAttr *S = dyn_cast(Semantic)) { + if (SemanticName == "SV_POSITION") { if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel) return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, - S->getAttrName()->getName(), + Semantic->getAttrName()->getName(), /* BuiltIn::FragCoord */ 15); } llvm_unreachable("non-handled system semantic. FIXME."); } -llvm::Value * -CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, - llvm::Type *Type, - const clang::DeclaratorDecl *Decl) { - - HLSLSemanticAttr *Semantic = nullptr; - for (HLSLSemanticAttr *Item : FD->specific_attrs()) { - if (Item->getTargetDecl() == Decl) { - Semantic = Item; - break; - } - } - // Sema must create one attribute per scalar field. - assert(Semantic); - - std::optional Index = std::nullopt; - if (Semantic->isSemanticIndexExplicit()) - Index = Semantic->getSemanticIndex(); +llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) { - if (isa(Semantic)) - return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); - return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index); + std::optional Index = Semantic->getSemanticIndex(); + if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_")) + return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index); + return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); } -llvm::Value * -CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, - llvm::Type *Type, - const clang::DeclaratorDecl *Decl) { +llvm::Value *CGHLSLRuntime::handleStructSemanticLoad( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator &begin, + specific_attr_iterator end) { const llvm::StructType *ST = cast(Type); const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl(); @@ -718,8 +707,8 @@ CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Aggregate = llvm::PoisonValue::get(Type); auto FieldDecl = RD->field_begin(); for (unsigned I = 0; I < ST->getNumElements(); ++I) { - llvm::Value *ChildValue = - handleSemanticLoad(B, FD, ST->getElementType(I), *FieldDecl); + llvm::Value *ChildValue = handleSemanticLoad(B, FD, ST->getElementType(I), + *FieldDecl, begin, end); assert(ChildValue); Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I); ++FieldDecl; @@ -728,13 +717,18 @@ CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, return Aggregate; } -llvm::Value * -CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, - llvm::Type *Type, - const clang::DeclaratorDecl *Decl) { +llvm::Value *CGHLSLRuntime::handleSemanticLoad( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator &begin, + specific_attr_iterator end) { + assert(end != begin); if (Type->isStructTy()) - return handleStructSemanticLoad(B, FD, Type, Decl); - return handleScalarSemanticLoad(B, FD, Type, Decl); + return handleStructSemanticLoad(B, FD, Type, Decl, begin, end); + + HLSLAppliedSemanticAttr *Attr = *begin; + ++begin; + return handleScalarSemanticLoad(B, FD, Type, Decl, Attr); } void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, @@ -781,6 +775,8 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, } const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset); + auto AttrBegin = PD->specific_attr_begin(); + auto AttrEnd = PD->specific_attr_end(); llvm::Value *SemanticValue = nullptr; if ([[maybe_unused]] HLSLParamModifierAttr *MA = PD->getAttr()) { @@ -788,7 +784,8 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, } else { llvm::Type *ParamType = Param.hasByValAttr() ? Param.getParamByValType() : Param.getType(); - SemanticValue = handleSemanticLoad(B, FD, ParamType, PD); + SemanticValue = + handleSemanticLoad(B, FD, ParamType, PD, AttrBegin, AttrEnd); if (!SemanticValue) return; if (Param.hasByValAttr()) { diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 9d31714ab8606..1c844f8c218ef 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -146,22 +146,26 @@ class CGHLSLRuntime { llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, - Attr *Semantic, + HLSLSemanticBaseAttr *Semantic, std::optional Index); llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, - const clang::DeclaratorDecl *Decl); + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic); - llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, - const FunctionDecl *FD, - llvm::Type *Type, - const clang::DeclaratorDecl *Decl); + llvm::Value *handleStructSemanticLoad( + llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator &begin, + specific_attr_iterator end); - llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, - llvm::Type *Type, - const clang::DeclaratorDecl *Decl); + llvm::Value * + handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, + llvm::Type *Type, const clang::DeclaratorDecl *Decl, + specific_attr_iterator &begin, + specific_attr_iterator end); public: CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {} @@ -205,14 +209,14 @@ class CGHLSLRuntime { HLSLResourceBindingAttr *RBA); llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, - HLSLSemanticAttr *Semantic, + HLSLAppliedSemanticAttr *Semantic, std::optional Index); llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, - HLSLSemanticAttr *Semantic, + HLSLAppliedSemanticAttr *Semantic, std::optional Index); llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, - HLSLSemanticAttr *Semantic, + HLSLAppliedSemanticAttr *Semantic, std::optional Index); llvm::Triple::ArchType getArch(); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index a06c57b15c585..70673a52bf830 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -771,44 +771,12 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { } } -HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info, - DeclaratorDecl *TargetDecl) { - std::string SemanticName = Info.Semantic->getAttrName()->getName().upper(); - - if (dyn_cast(Info.Semantic)) - return createSemanticAttr(*Info.Semantic, TargetDecl, - Info.Index); - - if (SemanticName == "SV_DISPATCHTHREADID") { - return createSemanticAttr( - *Info.Semantic, TargetDecl, Info.Index); - } else if (SemanticName == "SV_GROUPINDEX") { - return createSemanticAttr(*Info.Semantic, TargetDecl, - Info.Index); - } else if (SemanticName == "SV_GROUPTHREADID") { - return createSemanticAttr(*Info.Semantic, - TargetDecl, Info.Index); - } else if (SemanticName == "SV_GROUPID") { - return createSemanticAttr(*Info.Semantic, TargetDecl, - Info.Index); - } else if (SemanticName == "SV_POSITION") { - return createSemanticAttr(*Info.Semantic, TargetDecl, - Info.Index); - } else - Diag(Info.Semantic->getLoc(), diag::err_hlsl_unknown_semantic) - << *Info.Semantic; - - return nullptr; -} - bool SemaHLSL::determineActiveSemanticOnScalar( - FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, - llvm::StringSet<> &ActiveInputSemantics) { - + FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, + SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) { if (ActiveSemantic.Semantic == nullptr) { - ActiveSemantic.Semantic = D->getAttr(); - if (ActiveSemantic.Semantic && - ActiveSemantic.Semantic->isSemanticIndexExplicit()) + ActiveSemantic.Semantic = D->getAttr(); + if (ActiveSemantic.Semantic) ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); } @@ -817,12 +785,15 @@ bool SemaHLSL::determineActiveSemanticOnScalar( return false; } - auto *A = createSemantic(ActiveSemantic, D); + auto *A = ::new (getASTContext()) + HLSLAppliedSemanticAttr(getASTContext(), *ActiveSemantic.Semantic, + ActiveSemantic.Semantic->getAttrName()->getName(), + ActiveSemantic.Index.value_or(0)); if (!A) return false; checkSemanticAnnotation(FD, D, A); - FD->addAttr(A); + OutputDecl->addAttr(A); unsigned Location = ActiveSemantic.Index.value_or(0); @@ -846,25 +817,25 @@ bool SemaHLSL::determineActiveSemanticOnScalar( } bool SemaHLSL::determineActiveSemantic( - FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, - llvm::StringSet<> &ActiveInputSemantics) { + FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, + SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) { if (ActiveSemantic.Semantic == nullptr) { - ActiveSemantic.Semantic = D->getAttr(); - if (ActiveSemantic.Semantic && - ActiveSemantic.Semantic->isSemanticIndexExplicit()) + ActiveSemantic.Semantic = D->getAttr(); + if (ActiveSemantic.Semantic) ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); } const Type *T = D->getType()->getUnqualifiedDesugaredType(); const RecordType *RT = dyn_cast(T); if (!RT) - return determineActiveSemanticOnScalar(FD, D, ActiveSemantic, + return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic, ActiveInputSemantics); const RecordDecl *RD = RT->getDecl(); for (FieldDecl *Field : RD->fields()) { SemanticInfo Info = ActiveSemantic; - if (!determineActiveSemantic(FD, Field, Info, ActiveInputSemantics)) { + if (!determineActiveSemantic(FD, OutputDecl, Field, Info, + ActiveInputSemantics)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -940,10 +911,11 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { llvm::StringSet<> ActiveInputSemantics; for (ParmVarDecl *Param : FD->parameters()) { SemanticInfo ActiveSemantic; - ActiveSemantic.Semantic = nullptr; - ActiveSemantic.Index = std::nullopt; + ActiveSemantic.Semantic = Param->getAttr(); + if (ActiveSemantic.Semantic) + ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); - if (!determineActiveSemantic(FD, Param, ActiveSemantic, + if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic, ActiveInputSemantics)) { Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); @@ -952,34 +924,44 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { // FIXME: Verify return type semantic annotation. } -void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint, - const Decl *Param, - const HLSLSemanticAttr *SemanticAttr) { +void SemaHLSL::checkSemanticAnnotation( + FunctionDecl *EntryPoint, const Decl *Param, + const HLSLAppliedSemanticAttr *SemanticAttr) { auto *ShaderAttr = EntryPoint->getAttr(); assert(ShaderAttr && "Entry point has no shader attribute"); llvm::Triple::EnvironmentType ST = ShaderAttr->getType(); - switch (SemanticAttr->getKind()) { - case attr::HLSLSV_DispatchThreadID: - case attr::HLSLSV_GroupIndex: - case attr::HLSLSV_GroupThreadID: - case attr::HLSLSV_GroupID: - if (ST == llvm::Triple::Compute) - return; - DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute}); - break; - case attr::HLSLSV_Position: + auto SemanticName = SemanticAttr->getSemanticName().upper(); + if (SemanticName == "SV_DISPATCHTHREADID" || + SemanticName == "SV_GROUPINDEX" || SemanticName == "SV_GROUPTHREADID" || + SemanticName == "SV_GROUPID") { + + if (ST != llvm::Triple::Compute) + DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute}); + + if (SemanticAttr->getSemanticIndex() != 0) { + Twine PrettyName = + std::string("'") + SemanticAttr->getSemanticName() + "'"; + Diag(SemanticAttr->getLoc(), + diag::err_hlsl_semantic_indexing_not_supported) + << PrettyName.str(); + } + return; + } + + if (SemanticName == "SV_POSITION") { // TODO(#143523): allow use on other shader types & output once the overall // semantic logic is implemented. if (ST == llvm::Triple::Pixel) return; DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel}); - break; - case attr::HLSLUserSemantic: return; - default: - llvm_unreachable("Unknown SemanticAttr"); } + + // FIXME: catch-all for non-implemented system semantics reaching this + // location. + if (SemanticAttr->getAttrName()->getName().starts_with_insensitive("SV_")) + llvm_unreachable("Unknown SemanticAttr"); } void SemaHLSL::DiagnoseAttrStageMismatch( @@ -1748,41 +1730,56 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, } } - Attr *Attribute = nullptr; if (SemanticName == "SV_DISPATCHTHREADID") { diagnoseInputIDType(ValueType, AL); if (IsOutput) Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; - Attribute = - createSemanticAttr(AL, nullptr, Index); - } else if (SemanticName == "SV_GROUPINDEX") { + if (Index.has_value()) + Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL; + D->addAttr(createSemanticAttr(AL, Index)); + return; + } + + if (SemanticName == "SV_GROUPINDEX") { if (IsOutput) Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; - Attribute = createSemanticAttr(AL, nullptr, Index); - } else if (SemanticName == "SV_GROUPTHREADID") { + if (Index.has_value()) + Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL; + D->addAttr(createSemanticAttr(AL, Index)); + return; + } + + if (SemanticName == "SV_GROUPTHREADID") { diagnoseInputIDType(ValueType, AL); if (IsOutput) Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; - Attribute = - createSemanticAttr(AL, nullptr, Index); - } else if (SemanticName == "SV_GROUPID") { + if (Index.has_value()) + Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL; + D->addAttr(createSemanticAttr(AL, Index)); + return; + } + + if (SemanticName == "SV_GROUPID") { diagnoseInputIDType(ValueType, AL); if (IsOutput) Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; - Attribute = createSemanticAttr(AL, nullptr, Index); - } else if (SemanticName == "SV_POSITION") { + if (Index.has_value()) + Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL; + D->addAttr(createSemanticAttr(AL, Index)); + return; + } + + if (SemanticName == "SV_POSITION") { const auto *VT = ValueType->getAs(); if (!ValueType->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "float/float1/float2/float3/float4"; - Attribute = createSemanticAttr(AL, nullptr, Index); - } else - Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; - - if (!Attribute) + D->addAttr(createSemanticAttr(AL, Index)); return; - D->addAttr(Attribute); + } + + Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; } void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { @@ -1796,7 +1793,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { if (AL.getAttrName()->getName().starts_with_insensitive("SV_")) diagnoseSystemSemanticAttr(D, AL, Index); else - D->addAttr(createSemanticAttr(AL, nullptr, Index)); + D->addAttr(createSemanticAttr(AL, Index)); } void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { diff --git a/clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl b/clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl index 9ed545762ec94..b41bb0b0e8995 100644 --- a/clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl +++ b/clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl @@ -4,5 +4,5 @@ [shader("compute")] [numthreads(8,8,1)] void foo(uint Idx : SV_DispatchThreadID1) { - // expected-error@-1 {{semantic SV_DispatchThreadID does not allow indexing}} + // expected-error@-1 {{semantic 'SV_DispatchThreadID' does not allow indexing}} } diff --git a/clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl b/clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl index 8fa0b07a36027..795e880fba0fd 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl @@ -4,6 +4,11 @@ [shader("compute")] [numthreads(8,8,1)] void foo(uint Idx : SV_GroupID1) { - // expected-error@-1 {{semantic SV_GroupID does not allow indexing}} + // expected-error@-1 {{semantic 'SV_GroupID' does not allow indexing}} } +[shader("compute")] +[numthreads(8,8,1)] +void bar(uint Idx : SV_GROUPID1) { + // expected-error@-1 {{semantic 'SV_GROUPID' does not allow indexing}} +} diff --git a/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl b/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl index da72e85d2600e..1fd5ae4ff488e 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl @@ -4,5 +4,5 @@ [shader("compute")] [numthreads(8,8,1)] void foo(uint Idx : SV_GroupThreadID1) { - // expected-error@-1 {{semantic SV_GroupThreadID does not allow indexing}} + // expected-error@-1 {{semantic 'SV_GroupThreadID' does not allow indexing}} } diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl index b2cb3dad9f0ce..f57ac607db5bd 100644 --- a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl +++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl @@ -13,14 +13,14 @@ struct S0 { // CHECK: define void @main0() // CHECK-DXIL: %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) -// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0 -// CHECK-DXIL: %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) -// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1 +// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0 +// CHECK-DXIL: %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1 // CHECK-SPIRV: %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 16 // CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0 -// CHECK-SPIRV: %[[#A2:]] = load <4 x float>, ptr addrspace(7) @A2, align 16 -// CHECK-SPIRV: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A2]], 1 +// CHECK-SPIRV: %[[#A01:]] = load <4 x float>, ptr addrspace(7) @A2, align 16 +// CHECK-SPIRV: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A01]], 1 // CHECK: %[[#ARG:]] = alloca %struct.S0, align 16 // CHECK: store %struct.S0 %[[#TMP1]], ptr %[[#ARG]], align 16 diff --git a/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl b/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl index 5b228d039345e..a52c01d772a72 100644 --- a/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl +++ b/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl @@ -6,7 +6,7 @@ struct Eg9{ // CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} col:8 implicit struct Eg9 // CHECK: FieldDecl 0x{{[0-9a-f]+}} col:16 referenced a 'unsigned int' - // CHECK: -HLSLSV_DispatchThreadIDAttr 0x{{[0-9a-f]+}} + // CHECK: -HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 unsigned int a : SV_DispatchThreadID; }; Eg9 e9; diff --git a/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl index bcc94f0632d64..91dbf9c74ad60 100644 --- a/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl @@ -4,16 +4,15 @@ void CSMain(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID, uint GThreadID : SV_GroupThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain 'void (int, uint, uint, uint)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 GI 'int' -// CHECK-NEXT: HLSLSV_GroupIndexAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupIndex" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupIndex" 0 // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:42 ID 'uint' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:73 GID 'uint' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:96 GThreadID 'uint' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr - -// CHECK: HLSLSV_GroupIndexAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> ParmVar 0x{{[0-9a-fA-F]+}} 'GI' 'int' 0 -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> ParmVar 0x{{[0-9a-fA-F]+}} 'ID' 'uint':'unsigned int' 0 -// CHECK-NEXT: HLSLSV_GroupIDAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> ParmVar 0x{{[0-9a-fA-F]+}} 'GID' 'uint':'unsigned int' 0 -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> ParmVar 0x{{[0-9a-fA-F]+}} 'GThreadID' 'uint':'unsigned int' 0 +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 } diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl index 27a8e4a0e2662..7adf2a51f01c8 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -4,7 +4,6 @@ float4 main(float4 a : SV_Position2) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 'float4':'vector' -// CHECK-NEXT: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> - -// CHECK: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> ParmVar 0x{{[0-9a-fA-F]+}} 'a' 'float4':'vector' 2 SemanticExplicitIndex +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 } diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl index 9f57231bea0c1..3186aadf19946 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl @@ -3,17 +3,16 @@ struct S { float4 f0 : SV_Position; // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f0 'float4':'vector' -// CHECK: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <<>> 0 +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 0 float4 f1 : SV_Position3; // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f1 'float4':'vector' -// CHECK: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <<>> 3 SemanticExplicitIndex +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 3 }; // FIXME(Keenuts): add mandatory output semantic once those are implemented. float4 main(S s) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (S)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 s 'S' - -// CHECK: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> Field 0x{{[0-9a-fA-F]+}} 'f0' 'float4':'vector' 0 -// CHECK: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> Field 0x{{[0-9a-fA-F]+}} 'f1' 'float4':'vector' 3 SemanticExplicitIndex +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 3 } diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl new file mode 100644 index 0000000000000..f12ac4df0c450 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s + +struct A { + float4 x : A; +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 x 'float4':'vector' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 +}; + +struct Top { + A f0 : B; +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f0 'A' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "B" 0 + A f1 : C; +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f1 'A' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "C" 0 +}; + + +// FIXME(Keenuts): add mandatory output semantic once those are implemented. +float4 main(Top s : D) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (Top)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 s 'Top' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "D" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 1 +} diff --git a/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl index 1e6bae4fcbca5..6d1ce27f6741f 100644 --- a/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl +++ b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl @@ -1,33 +1,34 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -hlsl-entry CSMain -x hlsl -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -ast-dump -o - %s | FileCheck %s struct s_fields { float a : semantic_a; float b : semantic_b; -// CHECK: |-CXXRecordDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-3]]:8 struct s_fields definition -// CHECK: | |-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 a 'float' -// CHECK: | | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} -// CHECK: | `-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 b 'float' -// CHECK: | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} +// CHECK: CXXRecordDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-3]]:8 struct s_fields definition +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 a 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "semantic_a" 0 +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 b 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "semantic_b" 0 }; float fn_foo1(float a : a, float b : b) : sem_ret { return 1.0f; } -// CHECK: |-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo1 'float (float, float)' -// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' -// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> -// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' -// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> -// CHECK-NEXT: | |-CompoundStmt {{.*}} <{{.*}}> -// CHECK-NEXT: | | `-ReturnStmt {{.*}} <{{.*}}> -// CHECK-NEXT: | | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 -// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK: FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo1 'float (float, float)' +// CHECK-NEXT: ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "a" 0 +// CHECK-NEXT: ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "b" 0 +// CHECK-NEXT: CompoundStmt {{.*}} <{{.*}}> +// CHECK-NEXT: ReturnStmt {{.*}} <{{.*}}> +// CHECK-NEXT: FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} <{{.*}}> "sem_ret" 0 + float fn_foo2(float a : a, float b : b) : sem_ret : also_ret { return 1.0f; } -// CHECK: `-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo2 'float (float, float)' -// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' -// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> -// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' -// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> -// CHECK-NEXT: |-CompoundStmt {{.*}} <{{.*}}> -// CHECK-NEXT: | `-ReturnStmt {{.*}} <{{.*}}> -// CHECK-NEXT: | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 -// CHECK-NEXT: |-HLSLUserSemanticAttr {{.*}} <{{.*}}> -// CHECK-NEXT: `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK: FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo2 'float (float, float)' +// CHECK-NEXT: ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "a" 0 +// CHECK-NEXT: ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "b" 0 +// CHECK-NEXT: CompoundStmt {{.*}} <{{.*}}> +// CHECK-NEXT: ReturnStmt {{.*}} <{{.*}}> +// CHECK-NEXT: FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} <{{.*}}> "sem_ret" 0 +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} <{{.*}}> "also_ret" 0 diff --git a/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl index a2203692b582b..6bb9ae8dd1bb0 100644 --- a/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl @@ -4,91 +4,91 @@ void CSMain(uint ID : SV_DispatchThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain 'void (uint)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:18 ID 'uint' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 } [numthreads(8,8,1)] void CSMain1(uint2 ID : SV_DispatchThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain1 'void (uint2)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 ID 'uint2' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 } [numthreads(8,8,1)] void CSMain2(uint3 ID : SV_DispatchThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain2 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 ID 'uint3' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 } [numthreads(8,8,1)] void CSMain3(uint3 : SV_DispatchThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain3 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 'uint3' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadID" 0 } [numthreads(8,8,1)] void CSMain4(uint3 : SV_DispatchThreadId) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain4 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 'uint3' -// CHECK-NEXT: HLSLSV_DispatchThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_DispatchThreadId" 0 } [numthreads(8,8,1)] void CSMain_GID(uint ID : SV_GroupID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain_GID 'void (uint)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:22 ID 'uint' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 } [numthreads(8,8,1)] void CSMain1_GID(uint2 ID : SV_GroupID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain1_GID 'void (uint2)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:24 ID 'uint2' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 } [numthreads(8,8,1)] void CSMain2_GID(uint3 ID : SV_GroupID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain2_GID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:24 ID 'uint3' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 } [numthreads(8,8,1)] void CSMain3_GID(uint3 : SV_GroupID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain3_GID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:24 'uint3' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupID" 0 } [numthreads(8,8,1)] void CSMain4_GID(uint3 : Sv_GroupId) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain4_GID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:24 'uint3' -// CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "Sv_GroupId" 0 } [numthreads(8,8,1)] void CSMain_GThreadID(uint ID : SV_GroupThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain_GThreadID 'void (uint)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:28 ID 'uint' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 } [numthreads(8,8,1)] void CSMain1_GThreadID(uint2 ID : SV_GroupThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain1_GThreadID 'void (uint2)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 ID 'uint2' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 } [numthreads(8,8,1)] void CSMain2_GThreadID(uint3 ID : SV_GroupThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain2_GThreadID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 ID 'uint3' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 } [numthreads(8,8,1)] void CSMain3_GThreadID(uint3 : SV_GroupThreadID) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain3_GThreadID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 'uint3' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_GroupThreadID" 0 } [numthreads(8,8,1)] void CSMain4_GThreadID(uint3 : sv_GroupThreadid) { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain4_GThreadID 'void (uint3)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 'uint3' -// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "sv_GroupThreadid" 0 } diff --git a/clang/test/TableGen/HLSLAttribute-errors.td b/clang/test/TableGen/HLSLAttribute-errors.td index fc9473dcc1fb4..6680762cc6e30 100644 --- a/clang/test/TableGen/HLSLAttribute-errors.td +++ b/clang/test/TableGen/HLSLAttribute-errors.td @@ -7,5 +7,5 @@ def HLSLSV_FAKE: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"SV_Fake">]; let Subjects = SubjectList<[ParmVar, Field]>; let LangOpts = [HLSL]; - let Documentation = [HLSLSV_GroupThreadIDDocs]; + let Documentation = []; } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 183952af590e1..e49dcb9b70b0f 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2725,15 +2725,12 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, assert(!Supers.empty() && "Forgot to specify a superclass for the attr"); std::string SuperName; bool Inheritable = false; - bool HLSLSemantic = false; for (const Record *R : reverse(Supers)) { if (R->getName() != "TargetSpecificAttr" && R->getName() != "DeclOrTypeAttr" && SuperName.empty()) SuperName = R->getName().str(); if (R->getName() == "InheritableAttr") Inheritable = true; - if (R->getName() == "HLSLSemanticAttr") - HLSLSemantic = true; } if (Header) @@ -3057,8 +3054,6 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, << (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true" : "false"); } - if (HLSLSemantic) - OS << ", " << (R.getValueAsBit("SemanticIndexable") ? "true" : "false"); OS << ")\n"; for (auto const &ai : Args) { @@ -3078,17 +3073,6 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, OS << " {\n"; - // The generator puts the arguments for each attribute in the child class, - // even if those are set in the inherited attribute class (in the TD - // file). This means I cannot access those from the parent class, and have - // to do this weirdness. Maybe the generator should be changed to - // arguments are put in the class they are declared in inside the TD file? - if (HLSLSemantic) { - OS << " if (SemanticExplicitIndex)\n"; - OS << " setSemanticIndex(SemanticIndex);\n"; - OS << " setTargetDecl(Target);\n"; - } - for (auto const &ai : Args) { if (!shouldEmitArg(ai)) continue; @@ -3287,7 +3271,7 @@ static const AttrClassDescriptor AttrClassDescriptors[] = { {"INHERITABLE_PARAM_OR_STMT_ATTR", "InheritableParamOrStmtAttr"}, {"PARAMETER_ABI_ATTR", "ParameterABIAttr"}, {"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}, - {"HLSL_SEMANTIC_ATTR", "HLSLSemanticAttr"}}; + {"HLSL_SEMANTIC_ATTR", "HLSLSemanticBaseAttr"}}; static void emitDefaultDefine(raw_ostream &OS, StringRef name, const char *superName) {