https://github.com/Keenuts created https://github.com/llvm/llvm-project/pull/149363
WIP PR for the WG-HLSL semantic proposal TODO: validate DXIL packing and SPIR-V location assignment. From 8eb96a452cacee0e2284b6466351758db2bf3a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brio...@google.com> Date: Mon, 2 Jun 2025 14:33:23 +0200 Subject: [PATCH] [HLSL][SPIR-V] Add support for HLSL semantics TODO: validate DXIL packing and SPIR-V location assignment. --- clang/include/clang/AST/Attr.h | 35 ++ clang/include/clang/Basic/Attr.td | 84 ++-- clang/include/clang/Basic/AttrDocs.td | 36 +- .../clang/Basic/DiagnosticFrontendKinds.td | 11 + .../clang/Basic/DiagnosticParseKinds.td | 5 +- .../clang/Basic/DiagnosticSemaKinds.td | 4 + clang/include/clang/Parse/Parser.h | 8 + clang/include/clang/Sema/SemaHLSL.h | 23 +- clang/lib/Basic/Attributes.cpp | 7 +- clang/lib/CodeGen/CGHLSLRuntime.cpp | 401 ++++++++++++++++-- clang/lib/CodeGen/CGHLSLRuntime.h | 70 ++- clang/lib/Parse/ParseHLSL.cpp | 79 +++- clang/lib/Sema/ParsedAttr.cpp | 1 + clang/lib/Sema/SemaDeclAttr.cpp | 34 +- clang/lib/Sema/SemaHLSL.cpp | 140 ++++-- .../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 6 +- .../semantics/semantic.struct.hlsl | 72 ++++ clang/test/CodeGenHLSL/sret_output.hlsl | 21 +- ...a-attribute-supported-attributes-list.test | 1 + clang/test/ParserHLSL/semantic_parsing.hlsl | 2 +- clang/test/SemaHLSL/Semantics/groupindex.hlsl | 12 +- .../Semantics/invalid_entry_parameter.hlsl | 32 +- .../SemaHLSL/Semantics/position.ps.size.hlsl | 4 +- .../test/SemaHLSL/Semantics/position.vs.hlsl | 2 +- clang/utils/TableGen/ClangAttrEmitter.cpp | 6 + 25 files changed, 917 insertions(+), 179 deletions(-) create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 994f236337b99..ab434a6971558 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -232,6 +232,41 @@ class HLSLAnnotationAttr : public InheritableAttr { } }; +class HLSLSemanticAttr : public HLSLAnnotationAttr { + unsigned SemanticIndex : 30; + LLVM_PREFERRED_TYPE(bool) + unsigned SemanticIndexable : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned SemanticExplicitIndex : 1; + +protected: + HLSLSemanticAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, + attr::Kind AK, bool IsLateParsed, + bool InheritEvenIfAlreadyPresent, bool SemanticIndexable) + : HLSLAnnotationAttr(Context, CommonInfo, AK, IsLateParsed, + InheritEvenIfAlreadyPresent) { + this->SemanticIndexable = SemanticIndexable; + this->SemanticIndex = 0; + this->SemanticExplicitIndex = 0; + } + +public: + bool isSemanticIndexable() const { return SemanticIndexable; } + + void setSemanticIndex(unsigned SemanticIndex) { + this->SemanticIndex = SemanticIndex; + this->SemanticExplicitIndex = true; + } + + unsigned getSemanticIndex() const { return SemanticIndex; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() >= attr::FirstHLSLAnnotationAttr && + A->getKind() <= attr::LastHLSLAnnotationAttr; + } +}; + /// A parameter attribute which changes the argument-passing ABI rule /// for the parameter. class ParameterABIAttr : public InheritableParamAttr { diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 27fea7dea0a5e..e52da333c58f6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -396,7 +396,7 @@ class ClangGCC<string name, bit allowInC = 1, int version = 1> } // HLSL Annotation spellings -class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation">; +class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation"> {} class Accessor<string name, list<Spelling> spellings> { string Name = name; @@ -766,6 +766,16 @@ class DeclOrStmtAttr : InheritableAttr; /// An attribute class for HLSL Annotations. class HLSLAnnotationAttr : InheritableAttr; +class HLSLSemanticAttr<bit Indexable> : HLSLAnnotationAttr { + bit SemanticIndexable = Indexable; + int SemanticIndex = 0; + bit SemanticExplicitIndex = 0; + + let Spellings = []; + let Subjects = SubjectList<[ParmVar, Field, Function]>; + let LangOpts = [HLSL]; +} + /// 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<TargetSpec target> { @@ -4832,27 +4842,6 @@ def HLSLNumThreads: InheritableAttr { let Documentation = [NumThreadsDocs]; } -def HLSLSV_GroupThreadID: HLSLAnnotationAttr { - let Spellings = [HLSLAnnotation<"sv_groupthreadid">]; - let Subjects = SubjectList<[ParmVar, Field]>; - let LangOpts = [HLSL]; - let Documentation = [HLSLSV_GroupThreadIDDocs]; -} - -def HLSLSV_GroupID: HLSLAnnotationAttr { - let Spellings = [HLSLAnnotation<"sv_groupid">]; - let Subjects = SubjectList<[ParmVar, Field]>; - let LangOpts = [HLSL]; - let Documentation = [HLSLSV_GroupIDDocs]; -} - -def HLSLSV_GroupIndex: HLSLAnnotationAttr { - let Spellings = [HLSLAnnotation<"sv_groupindex">]; - let Subjects = SubjectList<[ParmVar, GlobalVar]>; - let LangOpts = [HLSL]; - let Documentation = [HLSLSV_GroupIndexDocs]; -} - def HLSLResourceBinding: InheritableAttr { let Spellings = [HLSLAnnotation<"register">]; let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>; @@ -4902,13 +4891,43 @@ def HLSLResourceBinding: InheritableAttr { }]; } -def HLSLSV_Position : HLSLAnnotationAttr { - let Spellings = [HLSLAnnotation<"sv_position">]; - let Subjects = SubjectList<[ParmVar, Field]>; +def HLSLUnparsedSemantic : HLSLAnnotationAttr { + let Spellings = []; + let Args = [DefaultIntArgument<"Index", 0>, + DefaultBoolArgument<"ExplicitIndex", 0>]; + let Subjects = SubjectList<[ParmVar, Field, Function]>; let LangOpts = [HLSL]; + let Documentation = [InternalOnly]; +} + +def HLSLUserSemantic : HLSLSemanticAttr</* Indexable= */ 1> { + let Documentation = [InternalOnly]; +} + +def HLSLSV_Target : HLSLSemanticAttr</* Indexable= */ 1> { + let Documentation = [HLSLSV_TargetDocs]; +} + +def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> { let Documentation = [HLSLSV_PositionDocs]; } +def HLSLSV_GroupThreadID : HLSLSemanticAttr</* Indexable= */ 0> { + let Documentation = [HLSLSV_GroupThreadIDDocs]; +} + +def HLSLSV_GroupID : HLSLSemanticAttr</* Indexable= */ 0> { + let Documentation = [HLSLSV_GroupIDDocs]; +} + +def HLSLSV_GroupIndex : HLSLSemanticAttr</* Indexable= */ 0> { + let Documentation = [HLSLSV_GroupIndexDocs]; +} + +def HLSLSV_DispatchThreadID : HLSLSemanticAttr</* Indexable= */ 0> { + let Documentation = [HLSLSV_DispatchThreadIDDocs]; +} + def HLSLPackOffset: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"packoffset">]; let LangOpts = [HLSL]; @@ -4921,13 +4940,6 @@ def HLSLPackOffset: HLSLAnnotationAttr { }]; } -def HLSLSV_DispatchThreadID: HLSLAnnotationAttr { - let Spellings = [HLSLAnnotation<"sv_dispatchthreadid">]; - let Subjects = SubjectList<[ParmVar, Field]>; - let LangOpts = [HLSL]; - let Documentation = [HLSLSV_DispatchThreadIDDocs]; -} - def HLSLShader : InheritableAttr { let Spellings = [Microsoft<"shader">]; let Subjects = SubjectList<[HLSLEntry]>; @@ -5031,6 +5043,14 @@ def HLSLVkConstantId : InheritableAttr { let Documentation = [VkConstantIdDocs]; } +def HLSLVkLocation : HLSLAnnotationAttr { + let Spellings = [CXX11<"vk", "location">]; + let Args = [IntArgument<"Location">]; + let Subjects = SubjectList<[ParmVar, Field, Function], ErrorDiag>; + let LangOpts = [HLSL]; + let Documentation = [HLSLVkLocationDocs]; +} + def RandomizeLayout : InheritableAttr { let Spellings = [GCC<"randomize_layout">]; let Subjects = SubjectList<[Record]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 43442f177ab7b..5db40e361e989 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8462,6 +8462,16 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo }]; } +def HLSLSV_PositionDocs : Documentation { + let Category = DocCatFunction; + let Content = [{TODO}]; +} + +def HLSLSV_TargetDocs : Documentation { + let Category = DocCatFunction; + let Content = [{TODO}]; +} + def HLSLSV_GroupIDDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -8544,20 +8554,6 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo }]; } -def HLSLSV_PositionDocs : Documentation { - let Category = DocCatFunction; - 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 = [{ @@ -8617,6 +8613,18 @@ https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md }]; } +def HLSLVkLocationDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +Attribute used for specifying the location number for the stage input/output +variables. Allowed on function parameters, function returns, and struct +fields. This parameter has no effect when used outside of an entrypoint +parameter/parameter field/return value. + +This attribute maps to the 'Location' SPIR-V decoration. + }]; +} + def AnnotateTypeDocs : Documentation { let Category = DocCatType; let Heading = "annotate_type"; diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a8db27490f06..a170dc43bacd0 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -393,6 +393,17 @@ def warn_hlsl_langstd_minimal : "recommend using %1 instead">, InGroup<HLSLDXCCompat>; +def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">; + +def err_hlsl_semantic_indexing_not_supported + : Error<"semantic %0 does not allow indexing">; + +def err_hlsl_semantic_missing : Error<"semantic annotations must be present " + "for all input and outputs of an entry " + "function or patch constant function">; + +def note_hlsl_semantic_used_here : Note<"%0 used here">; + // ClangIR frontend errors def err_cir_to_cir_transform_failed : Error< "CIR-to-CIR transformation failed">, DefaultFatal; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 6c30da376dafb..2963d317335ac 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1842,9 +1842,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">; def err_expected_semantic_identifier : Error< "expected HLSL Semantic identifier">; -def err_invalid_declaration_in_hlsl_buffer : Error< - "invalid declaration inside %select{tbuffer|cbuffer}0">; -def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">; +def err_invalid_declaration_in_hlsl_buffer + : Error<"invalid declaration inside %select{tbuffer|cbuffer}0">; def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hlsl attribute, use %0 instead">; def ext_hlsl_access_specifiers : ExtWarn< "access specifiers are a clang HLSL extension">, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f2f2152b8bbbe..7d7fcb93d626e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12982,6 +12982,9 @@ def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier def err_hlsl_missing_semantic_annotation : Error< "semantic annotations must be present for all parameters of an entry " "function or patch constant function">; +def err_hlsl_unknown_semantic : Error<"unknown HLSL semantic %0">; +def err_hlsl_semantic_output_not_supported + : Error<"semantic %0 does not support output">; def err_hlsl_init_priority_unsupported : Error< "initializer priorities are not supported in HLSL">; @@ -13430,4 +13433,5 @@ def err_acc_device_type_multiple_archs // AMDGCN builtins diagnostics def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">; def note_amdgcn_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">; + } // end of sema component. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index a47e23ffbd357..b9accdc7aa10b 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5164,6 +5164,14 @@ class Parser : public CodeCompletionHandler { ParseHLSLAnnotations(Attrs, EndLoc); } + struct ParsedSemantic { + StringRef Name; + unsigned Index; + bool Explicit; + }; + + ParsedSemantic ParseHLSLSemantic(); + void ParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr, bool CouldBeBitField = false); diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 7d7eae4db532c..c54c96302d908 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -110,6 +110,7 @@ class SemaHLSL : public SemaBase { bool ActOnUninitializedVarDecl(VarDecl *D); void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU); void CheckEntryPoint(FunctionDecl *FD); + bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D); void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, const HLSLAnnotationAttr *AnnotationAttr); void DiagnoseAttrStageMismatch( @@ -140,17 +141,31 @@ class SemaHLSL : public SemaBase { void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL); - void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); - void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); - void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); - void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL); + // void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); + // void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); + // void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); void handleShaderAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); void handleParamModifierAttr(Decl *D, const ParsedAttr &AL); bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL); + template <typename T> + T *createSemanticAttr(const ParsedAttr &AL, + std::optional<unsigned> Location) { + T *Attr = ::new (getASTContext()) T(getASTContext(), AL); + if (Attr->isSemanticIndexable()) + Attr->setSemanticIndex(Location ? *Location : 0); + return Attr; + // FIXME + } + + void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, + std::optional<unsigned> Index); + void handleSemanticAttr(Decl *D, const ParsedAttr &AL); + void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL); + void handleVkLocationAttr(Decl *D, const ParsedAttr &AL); bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); QualType ProcessResourceTypeAttributes(QualType Wrapped); diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index 004e5209a44a7..9e31097c5f557 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -189,7 +189,12 @@ AttributeCommonInfo::Kind AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, const IdentifierInfo *ScopeName, Syntax SyntaxUsed) { - return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); + AttributeCommonInfo::Kind Kind = + ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); + if (SyntaxUsed == AS_HLSLAnnotation && + Kind == AttributeCommonInfo::Kind::UnknownAttribute) + return AttributeCommonInfo::Kind::AT_HLSLUnparsedSemantic; + return Kind; } AttributeCommonInfo::AttrArgsInfo diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 3103f1798e14e..c7cdbe9f93444 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -22,6 +22,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h" #include "llvm/IR/Constants.h" @@ -337,6 +338,16 @@ void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes( WaveSizeAttr->getPreferred()); Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr); } + + if (HLSLVkLocationAttr *LocationAttr = FD->getAttr<HLSLVkLocationAttr>()) { + // const StringRef NumThreadsKindStr = "hlsl.numthreads"; + // std::string NumThreadsStr = + // formatv("{0},{1},{2}", NumThreadsAttr->getX(), + // NumThreadsAttr->getY(), + // NumThreadsAttr->getZ()); + // Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr); + } + // HLSL entry functions are materialized for module functions with // HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called // later in the compiler-flow for such module functions is not aware of and @@ -371,6 +382,17 @@ static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, GV->addMetadata("spirv.Decorations", *Decoration); } +static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) { + LLVMContext &Ctx = GV->getContext(); + IRBuilder<> B(GV->getContext()); + MDNode *Operands = + MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)), + ConstantAsMetadata::get(B.getInt32(Location))}); + MDNode *Decoration = MDNode::get(Ctx, {Operands}); + GV->addMetadata("spirv.Decorations", *Decoration); +} + +#if 0 static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID) { @@ -383,38 +405,325 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return B.CreateLoad(Ty, GV); } +#endif -llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, - const ParmVarDecl &D, - llvm::Type *Ty) { - assert(D.hasAttrs() && "Entry parameter missing annotation attribute!"); - if (D.hasAttr<HLSLSV_GroupIndexAttr>()) { +static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, + llvm::Type *Ty, unsigned Location, + StringRef Name = "") { + auto *GV = new llvm::GlobalVariable( + M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 7, /* isExternallyInitialized= */ true); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + addLocationDecoration(GV, Location); + return B.CreateLoad(Ty, GV); +} + +llvm::Value * +CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + SemanticInfo &ActiveSemantic) { + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(ActiveSemantic.Index)); + unsigned Location = SPIRVLastAssignedSemanticLocation; + + // DXC completely ignores the semantic/index pair. Location are assigned from + // the first semantic to the last. + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + SPIRVLastAssignedSemanticLocation += ElementCount; + + return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location, + VariableName.str()); +} + +llvm::Value * +CGHLSLRuntime::emitUserSemanticLoad(IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + assert(nullptr != dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic)); + + uint32_t Location = ActiveSemantic.Index; + if (HLSLVkLocationAttr *LocationAttr = Decl->getAttr<HLSLVkLocationAttr>()) + Location = LocationAttr->getLocation(); + + llvm::Value *SemanticValue = + emitSPIRVUserSemanticLoad(B, Type, ActiveSemantic); + + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + ActiveSemantic.Index += ElementCount; + + // Mark the semantic/index pair as active and detect collisions. + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + for (unsigned I = 0; I < ElementCount; I++) { + Twine VariableName = BaseName.concat(Twine(Location + I)); + auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str()); + if (!Inserted) { + CGM.getDiags().Report(Decl->getInnerLocStart(), + diag::err_hlsl_semantic_index_overlap) + << VariableName.str(); + return nullptr; + } + } + + return SemanticValue; +} + +llvm::Value * +CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + +#define CHECK_NO_INDEXING(Info) \ + if ((Info).Index != 0) { \ + CGM.getDiags().Report(Decl->getInnerLocStart(), \ + diag::err_hlsl_semantic_indexing_not_supported) \ + << (Info).Semantic; \ + return nullptr; \ + } + + if (HLSLSV_GroupIndexAttr *S = + dyn_cast<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) { + CHECK_NO_INDEXING(ActiveSemantic) llvm::Function *GroupIndex = CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic()); return B.CreateCall(FunctionCallee(GroupIndex)); } - if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) { + + if (HLSLSV_DispatchThreadIDAttr *S = + dyn_cast<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) { + CHECK_NO_INDEXING(ActiveSemantic) llvm::Function *ThreadIDIntrinsic = CGM.getIntrinsic(getThreadIdIntrinsic()); - return buildVectorInput(B, ThreadIDIntrinsic, Ty); + return buildVectorInput(B, ThreadIDIntrinsic, Type); } - if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) { + + if (HLSLSV_GroupThreadIDAttr *S = + dyn_cast<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) { + CHECK_NO_INDEXING(ActiveSemantic) llvm::Function *GroupThreadIDIntrinsic = CGM.getIntrinsic(getGroupThreadIdIntrinsic()); - return buildVectorInput(B, GroupThreadIDIntrinsic, Ty); + return buildVectorInput(B, GroupThreadIDIntrinsic, Type); } - if (D.hasAttr<HLSLSV_GroupIDAttr>()) { + + if (HLSLSV_GroupIDAttr *S = + dyn_cast<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) { + CHECK_NO_INDEXING(ActiveSemantic) llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); - return buildVectorInput(B, GroupIDIntrinsic, Ty); + return buildVectorInput(B, GroupIDIntrinsic, Type); + } + +#undef CHECK_NO_INDEXING + + if (HLSLSV_PositionAttr *S = + dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) + return emitSPIRVUserSemanticLoad(B, Type, ActiveSemantic); + + llvm_unreachable("non-handled system semantic. FIXME."); +} + +llvm::Value * +CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + + if (!ActiveSemantic.Semantic) { + ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>(); + if (!ActiveSemantic.Semantic) { + CGM.getDiags().Report(Decl->getInnerLocStart(), + diag::err_hlsl_semantic_missing); + return nullptr; + } + ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); } - if (D.hasAttr<HLSLSV_PositionAttr>()) { - if (getArch() == llvm::Triple::spirv) - return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position", - /* BuiltIn::Position */ 0); - llvm_unreachable("SV_Position semantic not implemented for this target."); + + if (auto *UserSemantic = + dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic)) + return emitUserSemanticLoad(B, Type, Decl, ActiveSemantic); + return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic); +} + +llvm::Value * +CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + const llvm::StructType *ST = cast<StructType>(Type); + const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl(); + + assert(std::distance(RD->field_begin(), RD->field_end()) == + ST->getNumElements()); + + if (!ActiveSemantic.Semantic) { + ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>(); + ActiveSemantic.Index = ActiveSemantic.Semantic + ? ActiveSemantic.Semantic->getSemanticIndex() + : 0; } - assert(false && "Unhandled parameter attribute"); - return nullptr; + + llvm::Value *Aggregate = llvm::PoisonValue::get(Type); + auto FieldDecl = RD->field_begin(); + for (unsigned I = 0; I < ST->getNumElements(); ++I) { + SemanticInfo Info = ActiveSemantic; + llvm::Value *ChildValue = + handleSemanticLoad(B, ST->getElementType(I), *FieldDecl, Info); + if (!ChildValue) { + CGM.getDiags().Report(Decl->getInnerLocStart(), + diag::note_hlsl_semantic_used_here) + << Decl; + return nullptr; + } + + Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I); + ++FieldDecl; + } + + return Aggregate; +} + +llvm::Value * +CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + + if (Type->isStructTy()) + return handleStructSemanticLoad(B, Type, Decl, ActiveSemantic); + return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic); +} + +static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M, + llvm::Value *Value, unsigned Location, + StringRef Name = "") { + auto *GV = new llvm::GlobalVariable( + M, Value->getType(), /* isConstant= */ false, + llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 8, /* isExternallyInitialized= */ false); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + addLocationDecoration(GV, Location); + B.CreateStore(Value, GV); +} + +void CGHLSLRuntime::emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, + llvm::Value *Source, + SemanticInfo &ActiveSemantic) { + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(ActiveSemantic.Index)); + unsigned Location = SPIRVLastAssignedSemanticLocation; + + // DXC completely ignores the semantic/index pair. Location are assigned from + // the first semantic to the last. + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType()); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + SPIRVLastAssignedSemanticLocation += ElementCount; + + createSPIRVLocationStore(B, CGM.getModule(), Source, Location, + VariableName.str()); +} + +void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + assert(nullptr != dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic)); + + uint32_t Location = ActiveSemantic.Index; + if (HLSLVkLocationAttr *LocationAttr = Decl->getAttr<HLSLVkLocationAttr>()) + Location = LocationAttr->getLocation(); + + emitSPIRVUserSemanticStore(B, Source, ActiveSemantic); + + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType()); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + ActiveSemantic.Index += ElementCount; + + // Mark the semantic/index pair as active and detect collisions. + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + for (unsigned I = 0; I < ElementCount; I++) { + Twine VariableName = BaseName.concat(Twine(Location + I)); + auto [_, Inserted] = ActiveOutputSemantics.insert(VariableName.str()); + if (!Inserted) { + CGM.getDiags().Report(Decl->getInnerLocStart(), + diag::err_hlsl_semantic_index_overlap) + << VariableName.str(); + return; + } + } +} + +void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + + if (HLSLSV_TargetAttr *S = + dyn_cast<HLSLSV_TargetAttr>(ActiveSemantic.Semantic)) + emitSPIRVUserSemanticStore(B, Source, ActiveSemantic); + else + llvm_unreachable("non-handled system semantic. FIXME."); +} + +void CGHLSLRuntime::handleScalarSemanticStore(IRBuilder<> &B, + llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + + if (!ActiveSemantic.Semantic) { + ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>(); + if (!ActiveSemantic.Semantic) { + CGM.getDiags().Report(Decl->getInnerLocStart(), + diag::err_hlsl_semantic_missing); + return; + } + ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); + } + + if (auto *UserSemantic = + dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic)) + emitUserSemanticStore(B, Source, Decl, ActiveSemantic); + else + emitSystemSemanticStore(B, Source, Decl, ActiveSemantic); +} + +void CGHLSLRuntime::handleStructSemanticStore(IRBuilder<> &B, + llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + + const llvm::StructType *ST = cast<StructType>(Source->getType()); + + const clang::RecordDecl *RD = nullptr; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl)) + RD = FD->getDeclaredReturnType()->getAsRecordDecl(); + else + RD = Decl->getType()->getAsRecordDecl(); + assert(RD); + + assert(std::distance(RD->field_begin(), RD->field_end()) == + ST->getNumElements()); + + if (!ActiveSemantic.Semantic) { + ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>(); + ActiveSemantic.Index = ActiveSemantic.Semantic + ? ActiveSemantic.Semantic->getSemanticIndex() + : 0; + } + + auto FieldDecl = RD->field_begin(); + for (unsigned I = 0; I < ST->getNumElements(); ++I) { + llvm::Value *Extract = B.CreateExtractValue(Source, I); + SemanticInfo Info = ActiveSemantic; + handleSemanticStore(B, Extract, *FieldDecl, Info); + ++FieldDecl; + } +} + +void CGHLSLRuntime::handleSemanticStore(IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic) { + if (Source->getType()->isStructTy()) + handleStructSemanticStore(B, Source, Decl, ActiveSemantic); + else + handleScalarSemanticStore(B, Source, Decl, ActiveSemantic); } void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, @@ -437,7 +746,6 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn); IRBuilder<> B(BB); - llvm::SmallVector<Value *> Args; SmallVector<OperandBundleDef, 1> OB; if (CGM.shouldEmitConvergenceTokens()) { @@ -448,25 +756,64 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, OB.emplace_back("convergencectrl", bundleArgs); } - // FIXME: support struct parameters where semantics are on members. - // See: https://github.com/llvm/llvm-project/issues/57874 + std::unordered_map<const DeclaratorDecl *, llvm::Value *> OutputSemantic; + + llvm::SmallVector<Value *> Args; unsigned SRetOffset = 0; for (const auto &Param : Fn->args()) { + if (Param.hasStructRetAttr()) { - // FIXME: support output. - // See: https://github.com/llvm/llvm-project/issues/57874 SRetOffset = 1; - Args.emplace_back(PoisonValue::get(Param.getType())); + llvm::Type *VarType = Param.getParamStructRetType(); + llvm::Value *Var = B.CreateAlloca(VarType); + Args.push_back(Var); + OutputSemantic.emplace(FD, Var); continue; } + const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset); - Args.push_back(emitInputSemantic(B, *PD, Param.getType())); + llvm::Value *SemanticValue = nullptr; + if (HLSLParamModifierAttr *MA = PD->getAttr<HLSLParamModifierAttr>()) { + if (MA->isOut()) { + llvm::Type *VarType = CGM.getTypes().ConvertType( + cast<clang::ReferenceType>(PD->getType())->getPointeeType()); + llvm::Value *Var = B.CreateAlloca(VarType); + SemanticValue = Var; + OutputSemantic.emplace(PD, Var); + } else + llvm_unreachable("Not handled yet"); + } else { + llvm::Type *ParamType = + Param.hasByValAttr() ? Param.getParamByValType() : Param.getType(); + SemanticInfo ActiveSemantic = {nullptr, 0}; + SemanticValue = handleSemanticLoad(B, ParamType, PD, ActiveSemantic); + if (!SemanticValue) + return; + if (Param.hasByValAttr()) { + llvm::Value *Var = B.CreateAlloca(Param.getParamByValType()); + B.CreateStore(SemanticValue, Var); + SemanticValue = Var; + } + } + Args.push_back(SemanticValue); } CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB); CI->setCallingConv(Fn->getCallingConv()); - // FIXME: Handle codegen for return type semantics. - // See: https://github.com/llvm/llvm-project/issues/57875 + + if (Fn->getReturnType() != CGM.VoidTy) + OutputSemantic.emplace(FD, CI); + + for (auto &[Decl, Source] : OutputSemantic) { + llvm::Value *SourceValue = nullptr; + if (AllocaInst *AI = dyn_cast<AllocaInst>(Source)) + SourceValue = B.CreateLoad(AI->getAllocatedType(), Source); + else + SourceValue = Source; + SemanticInfo ActiveSemantic = {nullptr, 0}; + handleSemanticStore(B, SourceValue, Decl, ActiveSemantic); + } + B.CreateRetVoid(); // Add and identify root signature to function, if applicable diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 89d2aff85d913..484f903bb9fbb 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -21,6 +21,8 @@ #include "llvm/IR/IntrinsicsDirectX.h" #include "llvm/IR/IntrinsicsSPIRV.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/HLSLRuntime.h" @@ -29,6 +31,7 @@ #include "llvm/Frontend/HLSL/HLSLResource.h" #include <optional> +#include <unordered_set> #include <vector> // A function generator macro for picking the right intrinsic @@ -133,8 +136,67 @@ class CGHLSLRuntime { protected: CodeGenModule &CGM; - llvm::Value *emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D, - llvm::Type *Ty); + void collectInputSemantic(llvm::IRBuilder<> &B, const DeclaratorDecl *D, + llvm::Type *Type, + SmallVectorImpl<llvm::Value *> &Inputs); + + struct SPIRVState { + uint32_t NextLocation; + }; + + struct SemanticInfo { + clang::HLSLSemanticAttr *Semantic; + uint32_t Index; + }; + + llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + SemanticInfo &ActiveSemantic); + + llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + /// + + void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + SemanticInfo &ActiveSemantic); + + void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + void handleScalarSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + void handleStructSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + void handleSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value, + const clang::DeclaratorDecl *Decl, + SemanticInfo &ActiveSemantic); + + /// public: CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {} @@ -172,6 +234,10 @@ class CGHLSLRuntime { llvm::Triple::ArchType getArch(); llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes; + + std::unordered_set<std::string> ActiveInputSemantics; + std::unordered_set<std::string> ActiveOutputSemantics; + unsigned SPIRVLastAssignedSemanticLocation = 0; }; } // namespace CodeGen diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index e6caa81b309ca..72e1cc9eff63f 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -118,6 +118,48 @@ static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, Slot = new (Ctx) IdentifierLoc(ArgLoc, PP.getIdentifierInfo(FixedArg)); } +Parser::ParsedSemantic Parser::ParseHLSLSemantic() { + assert(Tok.is(tok::identifier) && "Not a HLSL Annotation"); + + // Semantic pattern: [A-Za-z_]+[0-9]* + // The first part is the semantic name, the second is the optional + // semantic index. + bool Invalid = false; + SmallString<256> Buffer; + Buffer.resize(Tok.getLength() + 1); + StringRef Identifier = PP.getSpelling(Tok, Buffer); + if (Invalid) { + // FIXME: fix error message. + Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); + return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false}; + } + + unsigned I = 0; + for (; I < Identifier.size() && !isDigit(Identifier[I]); ++I) + continue; + StringRef SemanticName = Identifier.take_front(I); + + if (SemanticName.size() == 0) { + // FIXME: fix error message. + Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); + return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false}; + } + + unsigned Index = 0; + bool Explicit = I < Identifier.size(); + for (; I < Identifier.size() && isDigit(Identifier[I]); ++I) + Index = Index * 10 + Identifier[I] - '0'; + + // The attribute has letters after the index. + if (I != Identifier.size()) { + // FIXME: fix error message. + Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); + return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false}; + } + + return {SemanticName, Index, Explicit}; +} + void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation *EndLoc, bool CouldBeBitField) { @@ -141,11 +183,15 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, return; } + ParsedAttr::Kind AttrKind = + ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation); + Parser::ParsedSemantic Semantic; + if (AttrKind == ParsedAttr::AT_HLSLUnparsedSemantic) + Semantic = ParseHLSLSemantic(); + SourceLocation Loc = ConsumeToken(); if (EndLoc) *EndLoc = Tok.getLocation(); - ParsedAttr::Kind AttrKind = - ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation); ArgsVector ArgExprs; switch (AttrKind) { @@ -282,19 +328,30 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, return; } } break; - case ParsedAttr::UnknownAttribute: - Diag(Loc, diag::err_unknown_hlsl_semantic) << II; - return; - case ParsedAttr::AT_HLSLSV_GroupThreadID: - case ParsedAttr::AT_HLSLSV_GroupID: - case ParsedAttr::AT_HLSLSV_GroupIndex: - case ParsedAttr::AT_HLSLSV_DispatchThreadID: - case ParsedAttr::AT_HLSLSV_Position: + case ParsedAttr::UnknownAttribute: { + break; + } + case ParsedAttr::AT_HLSLUnparsedSemantic: { + ASTContext &Ctx = Actions.getASTContext(); + ArgExprs.push_back(IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getTypeSize(Ctx.IntTy), Semantic.Index), Ctx.IntTy, + SourceLocation())); + ArgExprs.push_back(IntegerLiteral::Create( + Ctx, llvm::APInt(1, Semantic.Explicit), Ctx.BoolTy, SourceLocation())); + II = PP.getIdentifierInfo(Semantic.Name.upper()); break; - default: + } + // case ParsedAttr::AT_HLSLSV_GroupThreadID: + // case ParsedAttr::AT_HLSLSV_GroupID: + // case ParsedAttr::AT_HLSLSV_GroupIndex: + // case ParsedAttr::AT_HLSLSV_DispatchThreadID: + case ParsedAttr::AT_HLSLVkLocation: + break; + default: { llvm_unreachable("invalid HLSL Annotation"); break; } + } Attrs.addNew(II, Loc, AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation()); diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 294f88eae931c..e7c10d198f144 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -103,6 +103,7 @@ namespace { } // namespace const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { + // If we have a ParsedAttrInfo for this ParsedAttr then return that. if ((size_t)A.getParsedKind() < std::size(AttrInfoMap)) return *AttrInfoMap[A.getParsedKind()]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index eba29e609cb05..5597a3f7510bb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6938,6 +6938,7 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) { static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, const Sema::ProcessDeclAttributeOptions &Options) { + if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) return; @@ -7584,30 +7585,27 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLWaveSize: S.HLSL().handleWaveSizeAttr(D, AL); break; - case ParsedAttr::AT_HLSLSV_Position: - S.HLSL().handleSV_PositionAttr(D, AL); - break; case ParsedAttr::AT_HLSLVkExtBuiltinInput: S.HLSL().handleVkExtBuiltinInputAttr(D, AL); break; case ParsedAttr::AT_HLSLVkConstantId: S.HLSL().handleVkConstantIdAttr(D, AL); break; - case ParsedAttr::AT_HLSLSV_GroupThreadID: - S.HLSL().handleSV_GroupThreadIDAttr(D, AL); - break; - case ParsedAttr::AT_HLSLSV_GroupID: - S.HLSL().handleSV_GroupIDAttr(D, AL); - break; - case ParsedAttr::AT_HLSLSV_GroupIndex: - handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL); - break; + // case ParsedAttr::AT_HLSLSV_GroupThreadID: + // S.HLSL().handleSV_GroupThreadIDAttr(D, AL); + // break; + // case ParsedAttr::AT_HLSLSV_GroupID: + // S.HLSL().handleSV_GroupIDAttr(D, AL); + // break; + // case ParsedAttr::AT_HLSLSV_GroupIndex: + // handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL); + // break; + // case ParsedAttr::AT_HLSLSV_DispatchThreadID: + // S.HLSL().handleSV_DispatchThreadIDAttr(D, AL); + // break; case ParsedAttr::AT_HLSLGroupSharedAddressSpace: handleSimpleAttribute<HLSLGroupSharedAddressSpaceAttr>(S, D, AL); break; - case ParsedAttr::AT_HLSLSV_DispatchThreadID: - S.HLSL().handleSV_DispatchThreadIDAttr(D, AL); - break; case ParsedAttr::AT_HLSLPackOffset: S.HLSL().handlePackOffsetAttr(D, AL); break; @@ -7620,6 +7618,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLParamModifier: S.HLSL().handleParamModifierAttr(D, AL); break; + case ParsedAttr::AT_HLSLVkLocation: + S.HLSL().handleVkLocationAttr(D, AL); + break; + case ParsedAttr::AT_HLSLUnparsedSemantic: + S.HLSL().handleSemanticAttr(D, AL); + break; case ParsedAttr::AT_AbiTag: handleAbiTagAttr(S, D, AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index b5975c2e5782e..49e99b861c117 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -744,6 +744,28 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { } } +bool SemaHLSL::isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D) { + const auto *AnnotationAttr = D->getAttr<HLSLAnnotationAttr>(); + if (AnnotationAttr) { + CheckSemanticAnnotation(FD, D, AnnotationAttr); + return true; + } + + const Type *T = + D->getType() + ->getUnqualifiedDesugaredType(); //.getDesugaredType(getASTContext()); + const RecordType *RT = dyn_cast<RecordType>(T); + if (!RT) + return false; + + const RecordDecl *RD = RT->getDecl(); + for (FieldDecl *Field : RD->fields()) { + if (!isSemanticValid(FD, Field)) + return false; + } + return true; +} + void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>(); assert(ShaderAttr && "Entry point has no shader attribute"); @@ -805,15 +827,17 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { } for (ParmVarDecl *Param : FD->parameters()) { - if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) { - CheckSemanticAnnotation(FD, Param, AnnotationAttr); - } else { + if (!isSemanticValid(FD, Param)) { // FIXME: Handle struct parameters where annotations are on struct fields. // See: https://github.com/llvm/llvm-project/issues/57875 Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); } + // if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) { + // CheckSemanticAnnotation(FD, Param, AnnotationAttr); + // } else { + // } } // FIXME: Verify return type semantic annotation. } @@ -834,13 +858,23 @@ void SemaHLSL::CheckSemanticAnnotation( return; DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute}); break; + case attr::HLSLVkLocation: + if (ST == llvm::Triple::Pixel || ST == llvm::Triple::Vertex) + return; + DiagnoseAttrStageMismatch(AnnotationAttr, ST, + {llvm::Triple::Pixel, llvm::Triple::Vertex}); + break; case attr::HLSLSV_Position: - // TODO(#143523): allow use on other shader types & output once the overall - // semantic logic is implemented. if (ST == llvm::Triple::Pixel) return; DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel}); break; + case attr::HLSLSV_Target: + case attr::HLSLUserSemantic: + // FIXME: handle system & stage mismatch. + // DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel, + // llvm::Triple::Vertex}); + return; default: llvm_unreachable("Unknown HLSLAnnotationAttr"); } @@ -1379,18 +1413,8 @@ bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) { return true; } -void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { - auto *VD = cast<ValueDecl>(D); - if (!diagnoseInputIDType(VD->getType(), AL)) - return; - - D->addAttr(::new (getASTContext()) - HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); -} - bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) { const auto *VT = T->getAs<VectorType>(); - if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) { Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "float/float1/float2/float3/float4"; @@ -1400,29 +1424,70 @@ bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) { return true; } -void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) { - auto *VD = cast<ValueDecl>(D); - if (!diagnosePositionType(VD->getType(), AL)) - return; +void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, + std::optional<unsigned> Index) { + StringRef SemanticName = AL.getAttrName()->getName(); - D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL)); -} - -void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) { auto *VD = cast<ValueDecl>(D); - if (!diagnoseInputIDType(VD->getType(), AL)) - return; - - D->addAttr(::new (getASTContext()) - HLSLSV_GroupThreadIDAttr(getASTContext(), AL)); + QualType ValueType = VD->getType(); + if (auto *FD = dyn_cast<FunctionDecl>(D)) + ValueType = FD->getReturnType(); + + bool IsOutput = false; + if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) { + if (MA->isOut()) { + IsOutput = true; + ValueType = cast<ReferenceType>(ValueType)->getPointeeType(); + } + } + +#define CHECK_OUTPUT_FORBIDDEN(AL) \ + if (IsOutput) { \ + Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; \ + } + + if (SemanticName == "SV_DISPATCHTHREADID") { + diagnoseInputIDType(ValueType, AL); + CHECK_OUTPUT_FORBIDDEN(AL); + D->addAttr(createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(AL, Index)); + } else if (SemanticName == "SV_GROUPINDEX") { + // diagnoseInputIDType(ValueType, AL); + CHECK_OUTPUT_FORBIDDEN(AL); + D->addAttr(createSemanticAttr<HLSLSV_GroupIndexAttr>(AL, Index)); + } else if (SemanticName == "SV_GROUPTHREADID") { + diagnoseInputIDType(ValueType, AL); + CHECK_OUTPUT_FORBIDDEN(AL); + D->addAttr(createSemanticAttr<HLSLSV_GroupThreadIDAttr>(AL, Index)); + } else if (SemanticName == "SV_GROUPID") { + diagnoseInputIDType(ValueType, AL); + CHECK_OUTPUT_FORBIDDEN(AL); + D->addAttr(createSemanticAttr<HLSLSV_GroupIDAttr>(AL, Index)); + } else if (SemanticName == "SV_TARGET" || SemanticName == "SV_POSITION") { + const auto *VT = ValueType->getAs<VectorType>(); + if (!ValueType->hasFloatingRepresentation() || + (VT && VT->getNumElements() > 4)) + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "float/float1/float2/float3/float4"; + if (SemanticName == "SV_POSITION") + D->addAttr(createSemanticAttr<HLSLSV_PositionAttr>(AL, Index)); + else + D->addAttr(createSemanticAttr<HLSLSV_TargetAttr>(AL, Index)); + } else + Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; } -void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) { - auto *VD = cast<ValueDecl>(D); - if (!diagnoseInputIDType(VD->getType(), AL)) - return; +void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { + uint32_t IndexValue, ExplicitIndex; + SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue); + SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex); + assert(IndexValue > 0 ? ExplicitIndex : true); + std::optional<unsigned> Index = + ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt; - D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL)); + if (AL.getAttrName()->getName().starts_with("SV_")) + diagnoseSystemSemanticAttr(D, AL, Index); + else + D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, Index)); } void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { @@ -1646,6 +1711,15 @@ bool SemaHLSL::handleResourceTypeAttr(QualType T, const ParsedAttr &AL) { return true; } +void SemaHLSL::handleVkLocationAttr(Decl *D, const ParsedAttr &AL) { + uint32_t Location; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location)) + return; + + D->addAttr(::new (getASTContext()) + HLSLVkLocationAttr(getASTContext(), AL, Location)); +} + // Combines all resource type attributes and creates HLSLAttributedResourceType. QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) { if (!HLSLResourcesTypeAttrs.size()) diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl index bdba38e028edd..3834b77b67964 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: @sv_position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 +// CHECK: @SV_POSITION0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 // CHECK: define void @main() {{.*}} { -float4 main(float4 p : SV_Position) { - // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @sv_position, align 16 +float4 main(float4 p : SV_Position) : SV_TARGET { + // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_POSITION0, align 16 // CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]]) return p; } diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl new file mode 100644 index 0000000000000..56e65d8067b1f --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv + +// Make sure SV_DispatchThreadID translated into dx.thread.id. + +struct S0 { + uint Idx : SV_DispatchThreadID; +}; + +// CHECK: define void @main0() +// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK: %[[#TMP:]] = insertvalue %struct.S0 poison, i32 %[[#ID:]], 0 +// CHECK: %[[#ARG:]] = alloca %struct.S0, align 8 +// CHECK: store %struct.S0 %[[#TMP]], ptr %[[#ARG]], align 4 +// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main0(S0 p) {} + +struct S1 { + uint a : SV_DispatchThreadID; + uint3 b : SV_GroupThreadID; +}; + +// CHECK: define void @main1() +// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK: %[[#S1A_:]] = insertvalue %struct.S1 poison, i32 %[[#ID:]], 0 +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2) +// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2 +// CHECK: %[[#S1AB:]] = insertvalue %struct.S1 %[[#S1A_]], <3 x i32> %[[#ID_XYZ:]], 1 +// CHECK: %[[#ARG:]] = alloca %struct.S1, align 8 +// CHECK: store %struct.S1 %[[#S1AB]], ptr %[[#ARG]], align 1 +// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main1(S1 p) {} + +struct S2C { + uint3 b : SV_GroupThreadID; +}; + +struct S2 { + uint a : SV_DispatchThreadID; + S2C child; +}; + +// CHECK: define void @main2() +// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK: %[[#S2A_:]] = insertvalue %struct.S2 poison, i32 %[[#ID:]], 0 + +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2) +// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2 +// CHECK: %[[#S2C:]] = insertvalue %struct.S2C poison, <3 x i32> %[[#ID_XYZ:]], 0 + +// CHECK: %[[#S2AB:]] = insertvalue %struct.S2 %[[#S2A_]], %struct.S2C %[[#S2V:]], 1 +// CHECK: %[[#ARG:]] = alloca %struct.S2, align 8 +// CHECK: store %struct.S2 %[[#S2AB]], ptr %[[#ARG]], align 1 +// CHECK-DXIL: call void @{{.*}}main2{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main2{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main2(S2 p) {} diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl b/clang/test/CodeGenHLSL/sret_output.hlsl index eefc9dabab517..05cebe16cb77f 100644 --- a/clang/test/CodeGenHLSL/sret_output.hlsl +++ b/clang/test/CodeGenHLSL/sret_output.hlsl @@ -1,21 +1,26 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// FIXME: add semantic to a. -// See https://github.com/llvm/llvm-project/issues/57874 +// CHECK: @SV_TARGET0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !0 + struct S { - float a; + float4 a : SV_Target; }; -// Make sure sret parameter is generated. // CHECK:define internal void @_Z7ps_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result) -// FIXME: change it to real value instead of poison value once semantic is add to a. -// Make sure the function with sret is called. -// CHECK:call void @_Z7ps_mainv(ptr poison) +// CHECK: %a = getelementptr inbounds nuw %struct.S, ptr %agg.result, i32 0, i32 0 +// CHECK: store <4 x float> zeroinitializer, ptr %a, align 1 + +// CHECK: %[[#VAR:]] = alloca %struct.S, align 16 +// CHECK: call void @_Z7ps_mainv(ptr %[[#VAR]]) +// CHECK: %[[#L1:]] = load %struct.S, ptr %[[#VAR]], align 16 +// CHECK: %[[#L2:]] = extractvalue %struct.S %[[#L1]], 0 +// CHECK: store <4 x float> %[[#L2]], ptr addrspace(8) @SV_TARGET0, align 16 + [shader("pixel")] S ps_main() { S s; - s.a = 0; + s.a = float4(0.f); return s; }; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 41d00dae3f69a..9aae4d0a85925 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -86,6 +86,7 @@ // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) +// CHECK-NEXT: HLSLVkLocation (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_field, SubjectMatchRule_function) // CHECK-NEXT: Hot (SubjectMatchRule_function) // CHECK-NEXT: HybridPatchable (SubjectMatchRule_function) // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance) diff --git a/clang/test/ParserHLSL/semantic_parsing.hlsl b/clang/test/ParserHLSL/semantic_parsing.hlsl index 34df1805c5a95..1301c84e0211b 100644 --- a/clang/test/ParserHLSL/semantic_parsing.hlsl +++ b/clang/test/ParserHLSL/semantic_parsing.hlsl @@ -3,5 +3,5 @@ // expected-error@+1 {{expected HLSL Semantic identifier}} void Entry(int GI : ) { } -// expected-error@+1 {{unknown HLSL semantic 'SV_IWantAPony'}} +// expected-error@+1 {{unknown HLSL semantic 'SV_IWANTAPONY'}} void Pony(int GI : SV_IWantAPony) { } diff --git a/clang/test/SemaHLSL/Semantics/groupindex.hlsl b/clang/test/SemaHLSL/Semantics/groupindex.hlsl index a33e060c82906..8acdee8e85989 100644 --- a/clang/test/SemaHLSL/Semantics/groupindex.hlsl +++ b/clang/test/SemaHLSL/Semantics/groupindex.hlsl @@ -4,26 +4,26 @@ [shader("compute")][numthreads(32,1,1)] void compute(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'pixel' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'pixel' shaders}} [shader("pixel")] void pixel(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'vertex' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'vertex' shaders}} [shader("vertex")] void vertex(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'geometry' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'geometry' shaders}} [shader("geometry")] void geometry(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'domain' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'domain' shaders}} [shader("domain")] void domain(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'amplification' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'amplification' shaders}} [shader("amplification")][numthreads(32,1,1)] void amplification(int GI : SV_GroupIndex) {} -// expected-error@+2 {{attribute 'SV_GroupIndex' is unsupported in 'mesh' shaders}} +// expected-error@+2 {{attribute 'SV_GROUPINDEX' is unsupported in 'mesh' shaders}} [shader("mesh")][numthreads(32,1,1)] void mesh(int GI : SV_GroupIndex) {} diff --git a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl index 1bb4ee5182d62..18bae5ee322df 100644 --- a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -ast-dump -verify -o - %s [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_DispatchThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_DISPATCHTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain(float ID : SV_DispatchThreadID) { } @@ -11,71 +11,71 @@ struct ST { float b; }; [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_DispatchThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_DISPATCHTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain2(ST ID : SV_DispatchThreadID) { } void foo() { -// expected-warning@+1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_DISPATCHTHREADID' attribute only applies to parameters, non-static data members, and functions}} uint V : SV_DispatchThreadID; } struct ST2 { -// expected-warning@+1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_DISPATCHTHREADID' attribute only applies to parameters, non-static data members, and functions}} static uint X : SV_DispatchThreadID; uint s : SV_DispatchThreadID; }; [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_GroupID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_GROUPID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain_GID(float ID : SV_GroupID) { } [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_GroupID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_GROUPID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain2_GID(ST GID : SV_GroupID) { } void foo_GID() { -// expected-warning@+1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_GROUPID' attribute only applies to parameters, non-static data members, and functions}} uint GIS : SV_GroupID; } struct ST2_GID { -// expected-warning@+1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_GROUPID' attribute only applies to parameters, non-static data members, and functions}} static uint GID : SV_GroupID; uint s_gid : SV_GroupID; }; [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_GROUPTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain_GThreadID(float ID : SV_GroupThreadID) { } [numthreads(8,8,1)] -// expected-error@+1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +// expected-error@+1 {{attribute 'SV_GROUPTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}} void CSMain2_GThreadID(ST GID : SV_GroupThreadID) { } void foo_GThreadID() { -// expected-warning@+1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_GROUPTHREADID' attribute only applies to parameters, non-static data members, and functions}} uint GThreadIS : SV_GroupThreadID; } struct ST2_GThreadID { -// expected-warning@+1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}} +// expected-warning@+1 {{'SV_GROUPTHREADID' attribute only applies to parameters, non-static data members, and functions}} static uint GThreadID : SV_GroupThreadID; uint s_gthreadid : SV_GroupThreadID; }; [shader("vertex")] -// expected-error@+4 {{attribute 'SV_GroupIndex' is unsupported in 'vertex' shaders, requires compute}} -// expected-error@+3 {{attribute 'SV_DispatchThreadID' is unsupported in 'vertex' shaders, requires compute}} -// expected-error@+2 {{attribute 'SV_GroupID' is unsupported in 'vertex' shaders, requires compute}} -// expected-error@+1 {{attribute 'SV_GroupThreadID' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+4 {{attribute 'SV_GROUPINDEX' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+3 {{attribute 'SV_DISPATCHTHREADID' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+2 {{attribute 'SV_GROUPID' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+1 {{attribute 'SV_GROUPTHREADID' is unsupported in 'vertex' shaders, requires compute}} void vs_main(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID, uint GThreadID : SV_GroupThreadID) {} diff --git a/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl index 124d401a9990c..b57ce4e325ca2 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected // RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected -// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} +// expected-error@+1 {{attribute 'SV_POSITION' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} void main(vector<float, 5> a : SV_Position) { } -// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} +// expected-error@+1 {{attribute 'SV_POSITION' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} void main(int2 a : SV_Position) { } diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl index 19f781fa3757c..e5e8da2484d93 100644 --- a/clang/test/SemaHLSL/Semantics/position.vs.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify -// expected-error@+1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}} +// expected-error@+1 {{attribute 'SV_POSITION' is unsupported in 'vertex' shaders, requires pixel}} float4 main(float4 a : SV_Position) { return a; } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index dfeb6b1b1ec19..81984effaf84f 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2725,12 +2725,15 @@ 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) @@ -3054,6 +3057,9 @@ 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) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits