[clang] 1f0003f - Reapply "[HLSL] Rewrite semantics parsing" (#157718) (#158044)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 11 08:01:56 PDT 2025


Author: Nathan Gauër
Date: 2025-09-11T17:01:52+02:00
New Revision: 1f0003f1debe6e48de54c520485904929790c888

URL: https://github.com/llvm/llvm-project/commit/1f0003f1debe6e48de54c520485904929790c888
DIFF: https://github.com/llvm/llvm-project/commit/1f0003f1debe6e48de54c520485904929790c888.diff

LOG: Reapply "[HLSL] Rewrite semantics parsing" (#157718) (#158044)

This is a re-land of #152537 now that #157841 is merged.

Added: 
    clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl
    clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl
    clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl
    clang/test/CodeGenHLSL/semantics/missing.hlsl
    clang/test/ParserHLSL/semantic_parsing_define.hlsl

Modified: 
    clang/include/clang/AST/Attr.h
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/DiagnosticFrontendKinds.td
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/SemaHLSL.h
    clang/lib/Basic/Attributes.cpp
    clang/lib/CodeGen/CGHLSLRuntime.cpp
    clang/lib/CodeGen/CGHLSLRuntime.h
    clang/lib/Parse/ParseHLSL.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaHLSL.cpp
    clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
    clang/test/ParserHLSL/semantic_parsing.hlsl
    clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
    clang/utils/TableGen/ClangAttrEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 994f236337b99..fe388b9fa045e 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -232,6 +232,40 @@ 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;
+
+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->SemanticExplicitIndex = false;
+  }
+
+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::FirstHLSLSemanticAttr &&
+           A->getKind() <= attr::LastHLSLSemanticAttr;
+  }
+};
+
 /// 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 1e48fa5a390f7..cdaed4a176735 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -779,6 +779,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> {
@@ -4890,27 +4900,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 HLSLVkBinding : InheritableAttr {
   let Spellings = [CXX11<"vk", "binding">];
   let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
@@ -4969,13 +4958,35 @@ 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 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];
@@ -4988,13 +4999,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]>;

diff  --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 15447558cf952..2fd2ae434d7c5 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -400,6 +400,10 @@ def warn_hlsl_langstd_minimal :
           "recommend using %1 instead">,
   InGroup<HLSLDXCCompat>;
 
+def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
+                                      "for all input and outputs of an entry "
+                                      "function or patch constant function">;
+
 // 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 bc7a6e231d93c..968a7c5b0dc8e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1860,9 +1860,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 ecdbeb0687cac..b0e669cd3560d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13121,6 +13121,11 @@ 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_semantic_indexing_not_supported
+    : Error<"semantic %0 does not allow indexing">;
 def err_hlsl_init_priority_unsupported : Error<
   "initializer priorities are not supported in HLSL">;
 

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index a9a87fb586fc2..30edd303e1824 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -5188,6 +5188,14 @@ class Parser : public CodeCompletionHandler {
       ParseHLSLAnnotations(Attrs, EndLoc);
   }
 
+  struct ParsedSemantic {
+    StringRef Name = "";
+    unsigned Index = 0;
+    bool Explicit = false;
+  };
+
+  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 4bad26e7a09a7..b5ddca0fe2ca5 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -17,6 +17,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/SemaBase.h"
 #include "llvm/ADT/SmallVector.h"
@@ -129,6 +130,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(
@@ -168,16 +170,31 @@ class SemaHLSL : public SemaBase {
   void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
   void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
   void handleVkBindingAttr(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 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);
+    else if (Location.has_value()) {
+      Diag(Attr->getLocation(), diag::err_hlsl_semantic_indexing_not_supported)
+          << Attr->getAttrName()->getName();
+      return nullptr;
+    }
+
+    return Attr;
+  }
+
+  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);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

diff  --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 81b186f844b8a..5878a4e3f83a4 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 4c8ece972f754..afee1198e0988 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -23,6 +23,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
@@ -565,47 +566,78 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
   return B.CreateLoad(Ty, GV);
 }
 
-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>()) {
+llvm::Value *
+CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+                                      const clang::DeclaratorDecl *Decl,
+                                      SemanticInfo &ActiveSemantic) {
+  if (isa<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) {
     llvm::Function *GroupIndex =
         CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
     return B.CreateCall(FunctionCallee(GroupIndex));
   }
-  if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
+
+  if (isa<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) {
     llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
     llvm::Function *ThreadIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
             ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
             : CGM.getIntrinsic(IntrinID);
-    return buildVectorInput(B, ThreadIDIntrinsic, Ty);
+    return buildVectorInput(B, ThreadIDIntrinsic, Type);
   }
-  if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) {
+
+  if (isa<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) {
     llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
     llvm::Function *GroupThreadIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
             ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
             : CGM.getIntrinsic(IntrinID);
-    return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
+    return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
   }
-  if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
+
+  if (isa<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) {
     llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
     llvm::Function *GroupIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
             ? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
             : CGM.getIntrinsic(IntrinID);
-    return buildVectorInput(B, GroupIDIntrinsic, Ty);
+    return buildVectorInput(B, GroupIDIntrinsic, Type);
   }
-  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 (HLSLSV_PositionAttr *S =
+          dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) {
+    if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
+      return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
+                                    S->getAttrName()->getName(),
+                                    /* BuiltIn::FragCoord */ 15);
   }
-  assert(false && "Unhandled parameter attribute");
-  return nullptr;
+
+  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();
+  }
+
+  return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
+}
+
+llvm::Value *
+CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+                                  const clang::DeclaratorDecl *Decl,
+                                  SemanticInfo &ActiveSemantic) {
+  assert(!Type->isStructTy());
+  return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
 }
 
 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
@@ -650,8 +682,10 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
       Args.emplace_back(PoisonValue::get(Param.getType()));
       continue;
     }
+
     const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
-    Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
+    SemanticInfo ActiveSemantic = {nullptr, 0};
+    Args.push_back(handleSemanticLoad(B, Param.getType(), PD, ActiveSemantic));
   }
 
   CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);

diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0948fefe7685e..370f3d5c5d30d 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"
 
@@ -138,8 +140,26 @@ 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 SemanticInfo {
+    clang::HLSLSemanticAttr *Semantic;
+    uint32_t Index;
+  };
+
+  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 *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+                                  const clang::DeclaratorDecl *Decl,
+                                  SemanticInfo &ActiveSemantic);
 
 public:
   CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}

diff  --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index f243b0cb95eae..51f2aef869649 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -118,6 +118,46 @@ 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_]([A-Za-z_0-9]*[A-Za-z_])?[0-9]*
+  // The first part is the semantic name, the second is the optional
+  // semantic index. The semantic index is the number at the end of
+  // the semantic, including leading zeroes. Digits located before
+  // the last letter are part of the semantic name.
+  bool Invalid = false;
+  SmallString<256> Buffer;
+  Buffer.resize(Tok.getLength() + 1);
+  StringRef Identifier = PP.getSpelling(Tok, Buffer);
+  if (Invalid) {
+    Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
+    return {};
+  }
+
+  assert(Identifier.size() > 0);
+  // Determine the start of the semantic index.
+  unsigned IndexIndex = Identifier.find_last_not_of("0123456789") + 1;
+
+  // ParseHLSLSemantic being called on an indentifier, the first
+  // character cannot be a digit. This error should be handled by
+  // the caller. We can assert here.
+  StringRef SemanticName = Identifier.take_front(IndexIndex);
+  assert(SemanticName.size() > 0);
+
+  unsigned Index = 0;
+  bool Explicit = false;
+  if (IndexIndex != Identifier.size()) {
+    Explicit = true;
+    [[maybe_unused]] bool Failure =
+        Identifier.substr(IndexIndex).getAsInteger(10, Index);
+    // Given the logic above, this should never fail.
+    assert(!Failure);
+  }
+
+  return {SemanticName, Index, Explicit};
+}
+
 void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
                                   SourceLocation *EndLoc,
                                   bool CouldBeBitField) {
@@ -141,11 +181,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,14 +326,17 @@ 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::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);
+    break;
+  }
+  case ParsedAttr::UnknownAttribute: // FIXME: maybe this is obsolete?
     break;
   default:
     llvm_unreachable("invalid HLSL Annotation");

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index cb2c132cca978..44906456f3371 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7465,9 +7465,6 @@ 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;
@@ -7477,21 +7474,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_HLSLVkBinding:
     S.HLSL().handleVkBindingAttr(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_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;
@@ -7504,6 +7489,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_HLSLParamModifier:
     S.HLSL().handleParamModifierAttr(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 6062f81d0aed3..0af38472b0fec 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -769,6 +769,26 @@ 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();
+  const RecordType *RT = dyn_cast<RecordType>(T);
+  if (!RT)
+    return false;
+
+  const RecordDecl *RD = RT->getOriginalDecl();
+  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");
@@ -832,11 +852,7 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
   }
 
   for (ParmVarDecl *Param : FD->parameters()) {
-    if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
-      CheckSemanticAnnotation(FD, Param, AnnotationAttr);
-    } else {
-      // FIXME: Handle struct parameters where annotations are on struct fields.
-      // See: https://github.com/llvm/llvm-project/issues/57875
+    if (!isSemanticValid(FD, Param)) {
       Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
       Diag(Param->getLocation(), diag::note_previous_decl) << Param;
       FD->setInvalidDecl();
@@ -1595,18 +1611,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";
@@ -1616,29 +1622,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;
-
-  D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL));
-}
+void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
+                                          std::optional<unsigned> Index) {
+  std::string SemanticName = AL.getAttrName()->getName().upper();
 
-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();
+    }
+  }
 
-void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) {
-  auto *VD = cast<ValueDecl>(D);
-  if (!diagnoseInputIDType(VD->getType(), 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<HLSLSV_DispatchThreadIDAttr>(AL, Index);
+  } else if (SemanticName == "SV_GROUPINDEX") {
+    if (IsOutput)
+      Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
+    Attribute = createSemanticAttr<HLSLSV_GroupIndexAttr>(AL, Index);
+  } else if (SemanticName == "SV_GROUPTHREADID") {
+    diagnoseInputIDType(ValueType, AL);
+    if (IsOutput)
+      Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
+    Attribute = createSemanticAttr<HLSLSV_GroupThreadIDAttr>(AL, Index);
+  } else if (SemanticName == "SV_GROUPID") {
+    diagnoseInputIDType(ValueType, AL);
+    if (IsOutput)
+      Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
+    Attribute = createSemanticAttr<HLSLSV_GroupIDAttr>(AL, Index);
+  } else if (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";
+    Attribute = createSemanticAttr<HLSLSV_PositionAttr>(AL, Index);
+  } else
+    Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
+
+  if (!Attribute)
     return;
+  D->addAttr(Attribute);
+}
 
-  D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL));
+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;
+
+  if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
+    diagnoseSystemSemanticAttr(D, AL, Index);
+  else
+    Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
 }
 
 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
new file mode 100644
index 0000000000000..9ed545762ec94
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/DispatchThreadID-noindex.hlsl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+
+[shader("compute")]
+[numthreads(8,8,1)]
+void foo(uint Idx : SV_DispatchThreadID1) {
+  // expected-error at -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
new file mode 100644
index 0000000000000..8fa0b07a36027
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_GroupID-noindex.hlsl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+
+[shader("compute")]
+[numthreads(8,8,1)]
+void foo(uint Idx : SV_GroupID1) {
+  // expected-error at -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
new file mode 100644
index 0000000000000..da72e85d2600e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID-noindex.hlsl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify -verify-ignore-unexpected=note,error
+
+[shader("compute")]
+[numthreads(8,8,1)]
+void foo(uint Idx : SV_GroupThreadID1) {
+  // expected-error at -1 {{semantic SV_GroupThreadID does not allow indexing}}
+}

diff  --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index bdba38e028edd..1bba87ea07141 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_Position = 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
+  // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, 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/missing.hlsl b/clang/test/CodeGenHLSL/semantics/missing.hlsl
new file mode 100644
index 0000000000000..3ba725e49c2c0
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/missing.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify -verify-ignore-unexpected=note
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify -verify-ignore-unexpected=note
+
+[numthreads(1,1,1)]
+void main(unsigned GI) {
+  // expected-error at -1 {{semantic annotations must be present for all parameters of an entry function or patch constant function}}
+}

diff  --git a/clang/test/ParserHLSL/semantic_parsing.hlsl b/clang/test/ParserHLSL/semantic_parsing.hlsl
index 34df1805c5a95..726deadb7c44c 100644
--- a/clang/test/ParserHLSL/semantic_parsing.hlsl
+++ b/clang/test/ParserHLSL/semantic_parsing.hlsl
@@ -1,7 +1,41 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -o - %s -verify
 
 // expected-error at +1 {{expected HLSL Semantic identifier}}
 void Entry(int GI : ) { }
 
 // expected-error at +1 {{unknown HLSL semantic 'SV_IWantAPony'}}
 void Pony(int GI : SV_IWantAPony) { }
+
+// expected-error at +3 {{expected HLSL Semantic identifier}}
+// expected-error at +2 {{expected ')'}}
+// expected-note at +1 {{to match this '('}}
+void SuperPony(int GI : 0) { }
+
+// expected-error at +1 {{unknown HLSL semantic '_'}}
+void MegaPony(int GI : _) { }
+
+// expected-error at +1 {{unknown HLSL semantic 'A0A'}}
+void CoolPony(int GI : A0A0) { }
+
+// expected-error at +1 {{unknown HLSL semantic 'A_'}}
+void NicePony(int GI : A_0) { }
+
+// expected-error at +1 {{unknown HLSL semantic 'A'}}
+void CutePony(int GI : A00) { }
+
+// expected-error at +3 {{unknown HLSL semantic 'A'}}
+// expected-error at +2 {{expected ')'}}
+// expected-note at +1 {{to match this '('}}
+void DoublePony(int GI : A00 B) { }
+
+// expected-error at +1 {{unknown HLSL semantic 'é'}}
+void BigPony(int GI : é) { }
+
+// expected-error at +2 {{unexpected character <U+1F60A>}}
+// expected-error at +1 {{expected HLSL Semantic identifier}}
+void UTFPony(int GI : 😊) { }
+
+// expected-error at +2 {{character <U+1F60A> not allowed in an identifier}}
+// expected-error at +1 {{unknown HLSL semantic 'PonyWithA😊'}}
+void SmilingPony(int GI : PonyWithA😊) { }

diff  --git a/clang/test/ParserHLSL/semantic_parsing_define.hlsl b/clang/test/ParserHLSL/semantic_parsing_define.hlsl
new file mode 100644
index 0000000000000..b42e2e6abd3de
--- /dev/null
+++ b/clang/test/ParserHLSL/semantic_parsing_define.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -o - %s -verify
+
+#define SomeDefine SV_IWantAPony
+
+// expected-error at 7 {{unknown HLSL semantic 'SV_IWantAPony'}}
+void Pony(int GI : SomeDefine) { }

diff  --git a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
index 1bb4ee5182d62..070075d419df1 100644
--- a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
+++ b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
@@ -17,13 +17,13 @@ void CSMain2(ST ID : SV_DispatchThreadID) {
 }
 
 void foo() {
-// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters, non-static data members, and functions}}
   uint V : SV_DispatchThreadID;
 
 }
 
 struct ST2 {
-// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters, non-static data members, and functions}}
     static uint X : SV_DispatchThreadID;
     uint s : SV_DispatchThreadID;
 };
@@ -40,12 +40,12 @@ void CSMain2_GID(ST GID : SV_GroupID) {
 }
 
 void foo_GID() {
-// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters, non-static data members, and functions}}
   uint GIS : SV_GroupID;
 }
 
 struct ST2_GID {
-// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters, non-static data members, and functions}}
     static uint GID : SV_GroupID;
     uint s_gid : SV_GroupID;
 };
@@ -62,12 +62,12 @@ void CSMain2_GThreadID(ST GID : SV_GroupThreadID) {
 }
 
 void foo_GThreadID() {
-// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters, non-static data members, and functions}}
   uint GThreadIS : SV_GroupThreadID;
 }
 
 struct ST2_GThreadID {
-// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters, non-static data members, and functions}}
     static uint GThreadID : SV_GroupThreadID;
     uint s_gthreadid : SV_GroupThreadID;
 };

diff  --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 2e2f32a7a1cb1..a4e4de32ba53f 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,8 @@ 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) {
@@ -3270,7 +3275,8 @@ static const AttrClassDescriptor AttrClassDescriptors[] = {
     {"INHERITABLE_PARAM_ATTR", "InheritableParamAttr"},
     {"INHERITABLE_PARAM_OR_STMT_ATTR", "InheritableParamOrStmtAttr"},
     {"PARAMETER_ABI_ATTR", "ParameterABIAttr"},
-    {"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}};
+    {"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"},
+    {"HLSL_SEMANTIC_ATTR", "HLSLSemanticAttr"}};
 
 static void emitDefaultDefine(raw_ostream &OS, StringRef name,
                               const char *superName) {


        


More information about the cfe-commits mailing list