https://github.com/inbelic created 
https://github.com/llvm/llvm-project/pull/218058

Updates SemaHLSL and CGHLSL to not use stringref compares to distinguish 
semantics and converts them to a common `SemanticKind` enum.

Further, it moves the classification of valid shader stages into a common table 
to denote where a semantic is interpreted and how and uses this to derive if it 
is valid.

This is a pre-req for the signature packing issues (#205875, etc) and #189765

>From e52b84aa7ee4c878202e01826bfaa40de0128bf4 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:40:58 +0000
Subject: [PATCH 01/18] nfc: move def to semasig

---
 clang/include/clang/Sema/SemaHLSL.h           | 21 +++++--------------
 clang/lib/Sema/SemaHLSL.cpp                   |  2 ++
 .../llvm/Frontend/HLSL/SemanticSignatures.h   | 15 +++++++++++++
 3 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 8928524e49783..0f834df21c40d 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -23,6 +23,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Frontend/HLSL/SemanticSignatures.h"
 #include "llvm/TargetParser/Triple.h"
 #include <initializer_list>
 
@@ -289,14 +290,6 @@ class SemaHLSL : public SemaBase {
     std::optional<uint32_t> Index = std::nullopt;
   };
 
-  // Bitmask used to recall if the current semantic subtree is
-  // input, output or inout.
-  enum IOType {
-    In = 0b01,
-    Out = 0b10,
-    InOut = 0b11,
-  };
-
   // The context shared by all semantics with the same IOType during
   // flattening.
   struct SemanticContext {
@@ -307,12 +300,7 @@ class SemaHLSL : public SemaBase {
     // index collisions.
     llvm::StringSet<> ActiveSemantics = {};
     // The IOType of this semantic set.
-    IOType CurrentIOType;
-  };
-
-  struct SemanticStageInfo {
-    llvm::Triple::EnvironmentType Stage;
-    IOType AllowedIOTypesMask;
+    llvm::hlsl::IOType CurrentIOType;
   };
 
 private:
@@ -343,8 +331,9 @@ class SemaHLSL : public SemaBase {
       std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
 
   void diagnoseSemanticStageMismatch(
-      const Attr *A, llvm::Triple::EnvironmentType Stage, IOType CurrentIOType,
-      std::initializer_list<SemanticStageInfo> AllowedStages);
+      const Attr *A, llvm::Triple::EnvironmentType Stage,
+      llvm::hlsl::IOType CurrentIOType,
+      std::initializer_list<llvm::hlsl::SemanticStageInfo> AllowedStages);
 
   void handleGlobalStructOrArrayOfWithResources(VarDecl *VD);
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 184339044e5bf..6bcd6d9182e44 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -54,6 +54,8 @@
 
 using namespace clang;
 using namespace clang::hlsl;
+using llvm::hlsl::IOType;
+using llvm::hlsl::SemanticStageInfo;
 using RegisterType = HLSLResourceBindingAttr::RegisterType;
 
 static CXXRecordDecl *createHostLayoutStruct(Sema &S,
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 0d0da50189e53..042b4afdf6faf 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -21,6 +21,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DXILABI.h"
 #include "llvm/Support/Error.h"
+#include "llvm/TargetParser/Triple.h"
 #include <cstdint>
 
 namespace llvm {
@@ -32,6 +33,20 @@ namespace hlsl {
 
 // Definitions of the in-memory data layout structures
 
+// Bitmask denoting whether a semantic is an input, output, or a value that is
+// constant across a patch (hull/domain shaders) or primitive (mesh shaders).
+enum IOType {
+  In = 0b001,
+  Out = 0b010,
+  InOut = 0b011,
+  PatchConstantOrPrimitive = 0b100,
+};
+
+struct SemanticStageInfo {
+  Triple::EnvironmentType Stage;
+  IOType AllowedIOTypesMask;
+};
+
 // Sentinel values denoting that an element is unallocated
 static constexpr uint32_t UnallocatedRow = ~0U;
 static constexpr uint8_t UnallocatedCol = 0xFF;

>From 0a79bad0fc01ced54e83f66e55fa3d289ae02229 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:42:51 +0000
Subject: [PATCH 02/18] extend to for patch constants

---
 clang/lib/Sema/SemaHLSL.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6bcd6d9182e44..5ed6d4632d8ee 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1158,12 +1158,19 @@ void SemaHLSL::diagnoseSemanticStageMismatch(
             ValidType.push_back("input");
           if (Case.AllowedIOTypesMask & IOType::Out)
             ValidType.push_back("output");
+          if (Case.AllowedIOTypesMask & IOType::PatchConstantOrPrimitive)
+            ValidType.push_back("patch constant or primitive");
           return std::string(
                      HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)) +
                  " " + join(ValidType, "/");
         });
+    StringRef CurrentIOTypeName = "patch constant or primitive";
+    if (CurrentIOType & IOType::In)
+      CurrentIOTypeName = "input";
+    else if (CurrentIOType & IOType::Out)
+      CurrentIOTypeName = "output";
     Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage)
-        << A->getAttrName() << (CurrentIOType & IOType::In ? "input" : 
"output")
+        << A->getAttrName() << CurrentIOTypeName
         << llvm::Triple::getEnvironmentTypeName(Case.Stage)
         << join(ValidCases, ", ");
     return;

>From a65ec0ce3b98b7330cc61d0c7b47f5f51a0cc497 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:54:45 +0000
Subject: [PATCH 03/18] define common info getter

---
 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 3 +++
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp        | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 042b4afdf6faf..5749f0b0538a9 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -119,6 +119,9 @@ struct SemanticSignatureElement {
 
 LLVM_ABI dxbc::PSV::SemanticKind getSemanticKind(StringRef SemanticName);
 
+LLVM_ABI ArrayRef<SemanticStageInfo>
+getAvailableStages(dxbc::PSV::SemanticKind SemanticKind);
+
 } // namespace hlsl
 } // namespace llvm
 
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 48d68c68946d7..72a5366bafb70 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -17,6 +17,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Type.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace llvm;
 using namespace llvm::hlsl;
@@ -54,6 +55,11 @@ dxbc::PSV::SemanticKind hlsl::getSemanticKind(StringRef 
SemanticName) {
   return dxbc::PSV::SemanticKind::Invalid;
 }
 
+ArrayRef<SemanticStageInfo>
+hlsl::getAvailableStages(dxbc::PSV::SemanticKind SemanticKind) {
+  llvm_unreachable("available stages for given semantic kind are not handled");
+}
+
 Expected<SemanticSignatureElement>
 SemanticSignatureElement::fromMetadata(const MDNode *Node) {
   // Operand positions within a signature element metadata node.

>From cf60ce9fdef9340dc1860e6bce45d521bc4d8d7b Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:56:51 +0000
Subject: [PATCH 04/18] categorize compute semantics

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 72a5366bafb70..68f8e20b4ff8b 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -57,7 +57,19 @@ dxbc::PSV::SemanticKind hlsl::getSemanticKind(StringRef 
SemanticName) {
 
 ArrayRef<SemanticStageInfo>
 hlsl::getAvailableStages(dxbc::PSV::SemanticKind SemanticKind) {
-  llvm_unreachable("available stages for given semantic kind are not handled");
+  switch (SemanticKind) {
+  case dxbc::PSV::SemanticKind::DispatchThreadID:
+  case dxbc::PSV::SemanticKind::GroupID:
+  case dxbc::PSV::SemanticKind::GroupIndex:
+  case dxbc::PSV::SemanticKind::GroupThreadID: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Compute, IOType::In}};
+    return Stages;
+  }
+  default:
+    llvm_unreachable(
+        "available stages for given semantic kind are not handled");
+  }
 }
 
 Expected<SemanticSignatureElement>

>From 66534f60a860bc77aafbe42cb93d3fda558eac69 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:56:57 +0000
Subject: [PATCH 05/18] categorize target

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 68f8e20b4ff8b..7b631fa22d545 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -66,6 +66,11 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
         {Triple::Compute, IOType::In}};
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::Target: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Pixel, IOType::Out}};
+    return Stages;
+  }
   default:
     llvm_unreachable(
         "available stages for given semantic kind are not handled");

>From ab60f591d0e0b153a3c4b73e7b99f4a8c5eb980e Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:03 +0000
Subject: [PATCH 06/18] categorize vertexid

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 7b631fa22d545..4704f2859be82 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -71,6 +71,11 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
         {Triple::Pixel, IOType::Out}};
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::VertexID: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Vertex, IOType::In}};
+    return Stages;
+  }
   default:
     llvm_unreachable(
         "available stages for given semantic kind are not handled");

>From 910bf701476377dab90ea5ee78a70b3781862a1b Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:12 +0000
Subject: [PATCH 07/18] categorize position

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 4704f2859be82..1ac635e50d635 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -76,6 +76,11 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
         {Triple::Vertex, IOType::In}};
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::Position: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Vertex, IOType::InOut}, {Triple::Pixel, IOType::In}};
+    return Stages;
+  }
   default:
     llvm_unreachable(
         "available stages for given semantic kind are not handled");

>From f7df75f0ba00cf358cb795755f2413b730b81c1c Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:26 +0000
Subject: [PATCH 08/18] categorize arbitrary

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 1ac635e50d635..480e6c0f122d4 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -58,6 +58,18 @@ dxbc::PSV::SemanticKind hlsl::getSemanticKind(StringRef 
SemanticName) {
 ArrayRef<SemanticStageInfo>
 hlsl::getAvailableStages(dxbc::PSV::SemanticKind SemanticKind) {
   switch (SemanticKind) {
+  case dxbc::PSV::SemanticKind::Arbitrary: {
+    static constexpr IOType AllIOTypes =
+        static_cast<IOType>(IOType::InOut | IOType::PatchConstantOrPrimitive);
+    static constexpr IOType OutOrPatchConstant =
+        static_cast<IOType>(IOType::Out | IOType::PatchConstantOrPrimitive);
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Vertex, IOType::InOut}, {Triple::Geometry, IOType::InOut},
+        {Triple::Hull, AllIOTypes},      {Triple::Domain, AllIOTypes},
+        {Triple::Pixel, IOType::In},     {Triple::Mesh, OutOrPatchConstant},
+    };
+    return Stages;
+  }
   case dxbc::PSV::SemanticKind::DispatchThreadID:
   case dxbc::PSV::SemanticKind::GroupID:
   case dxbc::PSV::SemanticKind::GroupIndex:

>From 6c2656c0136147e770aa72ed54ab99a4c8b08a95 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:38 +0000
Subject: [PATCH 09/18] categorize clip/cull

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 480e6c0f122d4..58e44fe756a75 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -93,6 +93,17 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
         {Triple::Vertex, IOType::InOut}, {Triple::Pixel, IOType::In}};
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::ClipDistance:
+  case dxbc::PSV::SemanticKind::CullDistance: {
+    static constexpr IOType AllIOTypes =
+        static_cast<IOType>(IOType::InOut | IOType::PatchConstantOrPrimitive);
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Vertex, IOType::InOut}, {Triple::Hull, AllIOTypes},
+        {Triple::Domain, AllIOTypes},    {Triple::Geometry, IOType::InOut},
+        {Triple::Pixel, IOType::In},     {Triple::Mesh, IOType::Out},
+    };
+    return Stages;
+  }
   default:
     llvm_unreachable(
         "available stages for given semantic kind are not handled");

>From 5e5f6474d507f3110de7b9ef2e1015111b113d3f Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:46 +0000
Subject: [PATCH 10/18] categorize tess factors

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 58e44fe756a75..f28979bf702f6 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -104,6 +104,14 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
     };
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::TessFactor:
+  case dxbc::PSV::SemanticKind::InsideTessFactor: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Hull, IOType::PatchConstantOrPrimitive},
+        {Triple::Domain, IOType::PatchConstantOrPrimitive},
+    };
+    return Stages;
+  }
   default:
     llvm_unreachable(
         "available stages for given semantic kind are not handled");

>From 0be9a96259a637132ee32e7b388a228590c969f9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:57:53 +0000
Subject: [PATCH 11/18] categorize front-face semantics

---
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index f28979bf702f6..5971275fd0dde 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -88,6 +88,11 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
         {Triple::Vertex, IOType::In}};
     return Stages;
   }
+  case dxbc::PSV::SemanticKind::IsFrontFace: {
+    static constexpr SemanticStageInfo Stages[] = {
+        {Triple::Geometry, IOType::Out}, {Triple::Pixel, IOType::In}};
+    return Stages;
+  }
   case dxbc::PSV::SemanticKind::Position: {
     static constexpr SemanticStageInfo Stages[] = {
         {Triple::Vertex, IOType::InOut}, {Triple::Pixel, IOType::In}};

>From 03e6d10cf6c65923c5b27c556db3b931d7ada19b Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:59:05 +0000
Subject: [PATCH 12/18] nfc: define all in enum

---
 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h |  1 +
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp        | 10 +++-------
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 5749f0b0538a9..0af56b46d60b1 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -40,6 +40,7 @@ enum IOType {
   Out = 0b010,
   InOut = 0b011,
   PatchConstantOrPrimitive = 0b100,
+  All = 0b111,
 };
 
 struct SemanticStageInfo {
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 5971275fd0dde..09fd5c4ee6744 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -59,13 +59,11 @@ ArrayRef<SemanticStageInfo>
 hlsl::getAvailableStages(dxbc::PSV::SemanticKind SemanticKind) {
   switch (SemanticKind) {
   case dxbc::PSV::SemanticKind::Arbitrary: {
-    static constexpr IOType AllIOTypes =
-        static_cast<IOType>(IOType::InOut | IOType::PatchConstantOrPrimitive);
     static constexpr IOType OutOrPatchConstant =
         static_cast<IOType>(IOType::Out | IOType::PatchConstantOrPrimitive);
     static constexpr SemanticStageInfo Stages[] = {
         {Triple::Vertex, IOType::InOut}, {Triple::Geometry, IOType::InOut},
-        {Triple::Hull, AllIOTypes},      {Triple::Domain, AllIOTypes},
+        {Triple::Hull, IOType::All},     {Triple::Domain, IOType::All},
         {Triple::Pixel, IOType::In},     {Triple::Mesh, OutOrPatchConstant},
     };
     return Stages;
@@ -100,11 +98,9 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
   }
   case dxbc::PSV::SemanticKind::ClipDistance:
   case dxbc::PSV::SemanticKind::CullDistance: {
-    static constexpr IOType AllIOTypes =
-        static_cast<IOType>(IOType::InOut | IOType::PatchConstantOrPrimitive);
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Vertex, IOType::InOut}, {Triple::Hull, AllIOTypes},
-        {Triple::Domain, AllIOTypes},    {Triple::Geometry, IOType::InOut},
+        {Triple::Vertex, IOType::InOut}, {Triple::Hull, IOType::All},
+        {Triple::Domain, IOType::All},   {Triple::Geometry, IOType::InOut},
         {Triple::Pixel, IOType::In},     {Triple::Mesh, IOType::Out},
     };
     return Stages;

>From a127af01ebc58492dbd2a9af1b7233b295e874e6 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 17:59:46 +0000
Subject: [PATCH 13/18] define interpretation kinds enum

---
 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 0af56b46d60b1..85ddabe266c1e 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -43,6 +43,17 @@ enum IOType {
   All = 0b111,
 };
 
+enum class SemanticInterpretation {
+  Invalid,
+  NotAllocated,
+  Arbitrary,
+  SV,
+  SGV,
+  ClipCull,
+  TessFactor,
+  Target,
+};
+
 struct SemanticStageInfo {
   Triple::EnvironmentType Stage;
   IOType AllowedIOTypesMask;

>From afd27adc4a2c4d149948c3869338ef17cc2f7f4e Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 18:02:29 +0000
Subject: [PATCH 14/18] include interpretation in semantic stage info

---
 .../llvm/Frontend/HLSL/SemanticSignatures.h   |  1 +
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 42 +++++++++++++------
 2 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 85ddabe266c1e..30d04f0da098e 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -57,6 +57,7 @@ enum class SemanticInterpretation {
 struct SemanticStageInfo {
   Triple::EnvironmentType Stage;
   IOType AllowedIOTypesMask;
+  SemanticInterpretation Interpretation;
 };
 
 // Sentinel values denoting that an element is unallocated
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 09fd5c4ee6744..9361f57115f5b 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -62,9 +62,12 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
     static constexpr IOType OutOrPatchConstant =
         static_cast<IOType>(IOType::Out | IOType::PatchConstantOrPrimitive);
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Vertex, IOType::InOut}, {Triple::Geometry, IOType::InOut},
-        {Triple::Hull, IOType::All},     {Triple::Domain, IOType::All},
-        {Triple::Pixel, IOType::In},     {Triple::Mesh, OutOrPatchConstant},
+        {Triple::Vertex, IOType::InOut, SemanticInterpretation::Arbitrary},
+        {Triple::Geometry, IOType::InOut, SemanticInterpretation::Arbitrary},
+        {Triple::Hull, IOType::All, SemanticInterpretation::Arbitrary},
+        {Triple::Domain, IOType::All, SemanticInterpretation::Arbitrary},
+        {Triple::Pixel, IOType::In, SemanticInterpretation::Arbitrary},
+        {Triple::Mesh, OutOrPatchConstant, SemanticInterpretation::Arbitrary},
     };
     return Stages;
   }
@@ -73,43 +76,56 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
   case dxbc::PSV::SemanticKind::GroupIndex:
   case dxbc::PSV::SemanticKind::GroupThreadID: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Compute, IOType::In}};
+        {Triple::Compute, IOType::In, SemanticInterpretation::NotAllocated}};
     return Stages;
   }
   case dxbc::PSV::SemanticKind::Target: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Pixel, IOType::Out}};
+        {Triple::Pixel, IOType::Out, SemanticInterpretation::Target}};
     return Stages;
   }
   case dxbc::PSV::SemanticKind::VertexID: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Vertex, IOType::In}};
+        {Triple::Vertex, IOType::In, SemanticInterpretation::SV}};
     return Stages;
   }
   case dxbc::PSV::SemanticKind::IsFrontFace: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Geometry, IOType::Out}, {Triple::Pixel, IOType::In}};
+        {Triple::Geometry, IOType::Out, SemanticInterpretation::SGV},
+        {Triple::Pixel, IOType::In, SemanticInterpretation::SGV}};
     return Stages;
   }
   case dxbc::PSV::SemanticKind::Position: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Vertex, IOType::InOut}, {Triple::Pixel, IOType::In}};
+        {Triple::Vertex, IOType::In, SemanticInterpretation::Arbitrary},
+        {Triple::Vertex, IOType::Out, SemanticInterpretation::SV},
+        {Triple::Pixel, IOType::In, SemanticInterpretation::SV}};
     return Stages;
   }
   case dxbc::PSV::SemanticKind::ClipDistance:
   case dxbc::PSV::SemanticKind::CullDistance: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Vertex, IOType::InOut}, {Triple::Hull, IOType::All},
-        {Triple::Domain, IOType::All},   {Triple::Geometry, IOType::InOut},
-        {Triple::Pixel, IOType::In},     {Triple::Mesh, IOType::Out},
+        {Triple::Vertex, IOType::In, SemanticInterpretation::Arbitrary},
+        {Triple::Vertex, IOType::Out, SemanticInterpretation::ClipCull},
+        {Triple::Hull, IOType::InOut, SemanticInterpretation::ClipCull},
+        {Triple::Hull, IOType::PatchConstantOrPrimitive,
+         SemanticInterpretation::Arbitrary},
+        {Triple::Domain, IOType::InOut, SemanticInterpretation::ClipCull},
+        {Triple::Domain, IOType::PatchConstantOrPrimitive,
+         SemanticInterpretation::Arbitrary},
+        {Triple::Geometry, IOType::InOut, SemanticInterpretation::ClipCull},
+        {Triple::Pixel, IOType::In, SemanticInterpretation::ClipCull},
+        {Triple::Mesh, IOType::Out, SemanticInterpretation::ClipCull},
     };
     return Stages;
   }
   case dxbc::PSV::SemanticKind::TessFactor:
   case dxbc::PSV::SemanticKind::InsideTessFactor: {
     static constexpr SemanticStageInfo Stages[] = {
-        {Triple::Hull, IOType::PatchConstantOrPrimitive},
-        {Triple::Domain, IOType::PatchConstantOrPrimitive},
+        {Triple::Hull, IOType::PatchConstantOrPrimitive,
+         SemanticInterpretation::TessFactor},
+        {Triple::Domain, IOType::PatchConstantOrPrimitive,
+         SemanticInterpretation::TessFactor},
     };
     return Stages;
   }

>From e22de0a6a70d27808e867748a216a9b08381935f Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 18:10:44 +0000
Subject: [PATCH 15/18] add kind helper

---
 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 4 ++++
 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp        | 9 +++++++++
 2 files changed, 13 insertions(+)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 30d04f0da098e..8e355a05cb86c 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -135,6 +135,10 @@ LLVM_ABI dxbc::PSV::SemanticKind getSemanticKind(StringRef 
SemanticName);
 LLVM_ABI ArrayRef<SemanticStageInfo>
 getAvailableStages(dxbc::PSV::SemanticKind SemanticKind);
 
+LLVM_ABI SemanticInterpretation
+getInterpretationKind(dxbc::PSV::SemanticKind SemanticKind,
+                      Triple::EnvironmentType ShaderStage, IOType IOTy);
+
 } // namespace hlsl
 } // namespace llvm
 
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp 
b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 9361f57115f5b..7a0e3a21564d4 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -135,6 +135,15 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind 
SemanticKind) {
   }
 }
 
+SemanticInterpretation
+hlsl::getInterpretationKind(dxbc::PSV::SemanticKind SemanticKind,
+                            Triple::EnvironmentType ShaderStage, IOType IOTy) {
+  for (const SemanticStageInfo &Info : getAvailableStages(SemanticKind))
+    if (Info.Stage == ShaderStage && (Info.AllowedIOTypesMask & IOTy))
+      return Info.Interpretation;
+  return SemanticInterpretation::Invalid;
+}
+
 Expected<SemanticSignatureElement>
 SemanticSignatureElement::fromMetadata(const MDNode *Node) {
   // Operand positions within a signature element metadata node.

>From 11ef54bdc4fdbb1084f4c6b043a54beab6e52122 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 18:17:04 +0000
Subject: [PATCH 16/18] nfc: refactor semahlsl to use look-up table

---
 clang/include/clang/Sema/SemaHLSL.h           |  3 +-
 clang/lib/Sema/SemaHLSL.cpp                   | 73 +++++++++----------
 .../CodeGenHLSL/semantics/SV_Position.ps.hlsl |  4 +-
 .../semantics/semantic.array.output.hlsl      |  2 +-
 .../Availability/attr-availability-pixel.hlsl |  2 +-
 .../Semantics/arbitrary.ps.output.hlsl        |  7 ++
 .../Semantics/position.ps.struct.hlsl         |  5 +-
 .../Semantics/position.ps.struct.reuse.hlsl   |  5 +-
 .../SemaHLSL/Semantics/target.ps.input.hlsl   |  2 +-
 clang/test/SemaHLSL/num_threads.hlsl          |  7 +-
 clang/test/SemaHLSL/shader_type_attr.hlsl     |  2 +-
 11 files changed, 59 insertions(+), 53 deletions(-)
 create mode 100644 clang/test/SemaHLSL/Semantics/arbitrary.ps.output.hlsl

diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 0f834df21c40d..dcf165be082a2 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -20,6 +20,7 @@
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/SemaBase.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSet.h"
@@ -333,7 +334,7 @@ class SemaHLSL : public SemaBase {
   void diagnoseSemanticStageMismatch(
       const Attr *A, llvm::Triple::EnvironmentType Stage,
       llvm::hlsl::IOType CurrentIOType,
-      std::initializer_list<llvm::hlsl::SemanticStageInfo> AllowedStages);
+      llvm::ArrayRef<llvm::hlsl::SemanticStageInfo> AllowedStages);
 
   void handleGlobalStructOrArrayOfWithResources(VarDecl *VD);
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5ed6d4632d8ee..a678df9e4774b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1080,15 +1080,19 @@ void SemaHLSL::checkSemanticAnnotation(
   assert(ShaderAttr && "Entry point has no shader attribute");
   llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
 
-  auto SemanticName = SemanticAttr->getSemanticName().upper();
-  if (SemanticName == "SV_DISPATCHTHREADID" ||
-      SemanticName == "SV_GROUPINDEX" || SemanticName == "SV_GROUPTHREADID" ||
-      SemanticName == "SV_GROUPID") {
-
-    if (ST != llvm::Triple::Compute)
-      diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
-                                    {{llvm::Triple::Compute, IOType::In}});
+  llvm::dxbc::PSV::SemanticKind SemanticKind =
+      llvm::hlsl::getSemanticKind(SemanticAttr->getSemanticName());
+  llvm::hlsl::SemanticInterpretation Interpretation =
+      llvm::hlsl::getInterpretationKind(SemanticKind, ST, SC.CurrentIOType);
+  if (Interpretation == llvm::hlsl::SemanticInterpretation::Invalid)
+    diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
+                                  
llvm::hlsl::getAvailableStages(SemanticKind));
 
+  switch (SemanticKind) {
+  case llvm::dxbc::PSV::SemanticKind::DispatchThreadID:
+  case llvm::dxbc::PSV::SemanticKind::GroupID:
+  case llvm::dxbc::PSV::SemanticKind::GroupIndex:
+  case llvm::dxbc::PSV::SemanticKind::GroupThreadID:
     if (SemanticAttr->getSemanticIndex() != 0) {
       std::string PrettyName =
           "'" + SemanticAttr->getSemanticName().str() + "'";
@@ -1096,33 +1100,10 @@ void SemaHLSL::checkSemanticAnnotation(
            diag::err_hlsl_semantic_indexing_not_supported)
           << PrettyName;
     }
-    return;
-  }
-
-  if (SemanticName == "SV_POSITION") {
-    // SV_Position can be an input or output in vertex shaders,
-    // but only an input in pixel shaders.
-    diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
-                                  {{llvm::Triple::Vertex, IOType::InOut},
-                                   {llvm::Triple::Pixel, IOType::In}});
-    return;
-  }
-  if (SemanticName == "SV_VERTEXID") {
-    diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
-                                  {{llvm::Triple::Vertex, IOType::In}});
-    return;
-  }
-
-  if (SemanticName == "SV_TARGET") {
-    diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
-                                  {{llvm::Triple::Pixel, IOType::Out}});
-    return;
+    break;
+  default:
+    break;
   }
-
-  // FIXME: catch-all for non-implemented system semantics reaching this
-  // location.
-  if (SemanticAttr->getAttrName()->getName().starts_with_insensitive("SV_"))
-    llvm_unreachable("Unknown SemanticAttr");
 }
 
 void SemaHLSL::diagnoseAttrStageMismatch(
@@ -1141,9 +1122,21 @@ void SemaHLSL::diagnoseAttrStageMismatch(
 
 void SemaHLSL::diagnoseSemanticStageMismatch(
     const Attr *A, llvm::Triple::EnvironmentType Stage, IOType CurrentIOType,
-    std::initializer_list<SemanticStageInfo> Allowed) {
+    ArrayRef<SemanticStageInfo> Allowed) {
+  SmallVector<SemanticStageInfo, 8> CombinedAllowed;
+  for (const SemanticStageInfo &Case : Allowed) {
+    auto It = llvm::find_if(CombinedAllowed, [&](SemanticStageInfo Info) {
+      return Info.Stage == Case.Stage;
+    });
+    if (It == CombinedAllowed.end()) {
+      CombinedAllowed.push_back(Case);
+      continue;
+    }
+    It->AllowedIOTypesMask =
+        static_cast<IOType>(It->AllowedIOTypesMask | Case.AllowedIOTypesMask);
+  }
 
-  for (auto &Case : Allowed) {
+  for (auto &Case : CombinedAllowed) {
     if (Case.Stage != Stage)
       continue;
 
@@ -1152,7 +1145,8 @@ void SemaHLSL::diagnoseSemanticStageMismatch(
 
     SmallVector<std::string, 8> ValidCases;
     llvm::transform(
-        Allowed, std::back_inserter(ValidCases), [](SemanticStageInfo Case) {
+        CombinedAllowed, std::back_inserter(ValidCases),
+        [](SemanticStageInfo Case) {
           SmallVector<std::string, 2> ValidType;
           if (Case.AllowedIOTypesMask & IOType::In)
             ValidType.push_back("input");
@@ -1178,14 +1172,15 @@ void SemaHLSL::diagnoseSemanticStageMismatch(
 
   SmallVector<StringRef, 8> StageStrings;
   llvm::transform(
-      Allowed, std::back_inserter(StageStrings), [](SemanticStageInfo Case) {
+      CombinedAllowed, std::back_inserter(StageStrings),
+      [](SemanticStageInfo Case) {
         return StringRef(
             HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage));
       });
 
   Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
       << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
-      << (Allowed.size() != 1) << join(StageStrings, ", ");
+      << (CombinedAllowed.size() != 1) << join(StageStrings, ", ");
 }
 
 template <CastKind Kind>
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl 
b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index 095532863ac5a..b1a0a2b16c3d1 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -4,10 +4,10 @@
 // CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(7) 
externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
 
 // CHECK: define void @main() {{.*}} {
-float4 main(float4 p : SV_Position) : A {
+float4 main(float4 p : SV_Position) : SV_Target {
   // CHECK-SPIRV: %[[P:.*]] = load <4 x float>, ptr addrspace(7) @SV_Position, 
align 4
   // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x 
float> %[[P]])
-  // CHECK-SPIRV:            store <4 x float> %[[R]], ptr addrspace(8) @A0, 
align 4
+  // CHECK-SPIRV:            store <4 x float> %[[R]], ptr addrspace(8) 
@SV_Target0, align 4
 
   // CHECK-DXIL: %[[INPUT:.*]] = call <4 x float> 
@llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
   // CHECK-DXIL: %[[RESULT:.*]] = call <4 x float> @_Z4mainDv4_f(<4 x float> 
%[[INPUT]])
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 5427a569e5eee..8a8ba0f52bc1e 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -8,7 +8,7 @@ struct S0 {
 
 // CHECK-SPIRV-DAG:    @A0 = external hidden thread_local addrspace(7) 
externally_initialized constant <4 x float>, !spirv.Decorations 
![[#METADATA_0:]]
 
-[shader("pixel")]
+[shader("vertex")]
 S0 main1(float4 input : A) : B {
 // CHECK:         %[[ARG:.*]] = alloca %struct.S0
 // CHECK-SPIRV: %[[INPUT:.*]] = load <4 x float>, ptr addrspace(7) @A0, align 4
diff --git a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl 
b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
index 83c49738f8810..0f24f7f10f980 100644
--- a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
+++ b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
@@ -36,7 +36,7 @@ __attribute__((availability(shadermodel, introduced = 5.0, 
environment = compute
 __attribute__((availability(shadermodel, introduced = 6.0, environment = 
mesh)))
 unsigned f8();
 
-int main() : A {
+float main() : SV_Target {
     // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or 
newer}}
     // expected-note@#f1 {{'f1' has been marked as being introduced in Shader 
Model 6.0 here, but the deployment target is Shader Model 5.0}}
     unsigned A = f1(); // #f1_call
diff --git a/clang/test/SemaHLSL/Semantics/arbitrary.ps.output.hlsl 
b/clang/test/SemaHLSL/Semantics/arbitrary.ps.output.hlsl
new file mode 100644
index 0000000000000..308bb48b096ba
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/arbitrary.ps.output.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel 
-finclude-default-header -x hlsl -verify -o - %s
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header 
-x hlsl -verify -o - %s
+
+float4 main(float4 a : A) : B {
+// expected-error@-1 {{semantic 'B' is unsupported in pixel shaders as output}}
+  return a;
+}
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl 
b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
index 213a53e30155b..d8fdd58ba0855 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
@@ -9,13 +9,12 @@ struct S {
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:15> "SV_Position" 3
 };
 
-// FIXME(Keenuts): add mandatory output semantic once those are implemented.
-float4 main(S s) : B {
+float4 main(S s) : SV_Target {
 // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 
'float4 (S)'
 // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 used s 'S'
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <line:4:15> 
"SV_Position" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <line:7:15> 
"SV_Position" 3
 
-// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:20> "B" 0
+// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:20> "SV_Target" 0
   return s.f1;
 }
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl 
b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
index d10c817d53af2..532d73131895b 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
@@ -16,14 +16,13 @@ struct Top {
 };
 
 
-// FIXME(Keenuts): add mandatory output semantic once those are implemented.
-float4 main(Top s : D) : F4 {
+float4 main(Top s : D) : SV_Target {
 // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 
'float4 (Top)'
 // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 used s 'Top'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 1
 
-// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:26> "F" 4
+// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:26> "SV_Target" 0
   return s.f0.x;
 }
diff --git a/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl 
b/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl
index a77b46c0e9f1a..87972640e294a 100644
--- a/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl
+++ b/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel 
-finclude-default-header -x hlsl -verify -o - %s
 // RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header 
-x hlsl -verify -o - %s
 
-float4 main(float4 a : SV_Target) : A {
+float4 main(float4 a : SV_Target) : SV_Target {
 // expected-error@-1 {{semantic 'SV_Target' is unsupported in pixel shaders as 
input, requires one of the following: pixel out}}
   return a;
 }
diff --git a/clang/test/SemaHLSL/num_threads.hlsl 
b/clang/test/SemaHLSL/num_threads.hlsl
index 52e71ec458161..6713af80ba9d6 100644
--- a/clang/test/SemaHLSL/num_threads.hlsl
+++ b/clang/test/SemaHLSL/num_threads.hlsl
@@ -130,7 +130,12 @@ int largeZ();
 #endif
 // expected-error-re@+1 {{attribute 'numthreads' is unsupported in 
'{{[A-Za-z]+}}' shaders, requires one of the following: compute, amplification, 
mesh}}
 [numthreads(1,1,1)]
-int main() : A {
+#if __SHADER_TARGET_STAGE == __SHADER_STAGE_PIXEL
+float main() : SV_Target
+#else
+int main() : A
+#endif
+{
  return 1;
 }
 
diff --git a/clang/test/SemaHLSL/shader_type_attr.hlsl 
b/clang/test/SemaHLSL/shader_type_attr.hlsl
index 5f30a520b7255..c0c3ec4fe0e6d 100644
--- a/clang/test/SemaHLSL/shader_type_attr.hlsl
+++ b/clang/test/SemaHLSL/shader_type_attr.hlsl
@@ -31,7 +31,7 @@ static void oops() {}
 [shader("pixel")]
 // expected-note@+1 {{conflicting attribute is here}}
 [shader("vertex")]
-int doubledUp() : A {
+float doubledUp() : SV_Target {
   return 1;
 }
 

>From 0c4a469003efa74ed82544bb96db8898b2fc75d6 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 18:21:46 +0000
Subject: [PATCH 17/18] nfc: refactor cghlsl to not do logic on the names

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 132 ++++++++++++++--------------
 clang/lib/CodeGen/CGHLSLRuntime.h   |  12 +--
 2 files changed, 74 insertions(+), 70 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 05f755edde64b..66178493a9ccc 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1435,18 +1435,17 @@ void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> 
&B, llvm::Value *Source,
 }
 
 llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
-    IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
-    const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
-    std::optional<unsigned> Index, SemanticSignatures &Signature) {
-
-  std::string SemanticName = Semantic->getAttrName()->getName().upper();
-  if (SemanticName == "SV_GROUPINDEX") {
+    IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
+    HLSLAppliedSemanticAttr *Semantic,
+    llvm::dxbc::PSV::SemanticKind SemanticKind, std::optional<unsigned> Index,
+    SemanticSignatures &Signature) {
+  switch (SemanticKind) {
+  case llvm::dxbc::PSV::SemanticKind::GroupIndex: {
     llvm::Function *GroupIndex =
         CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
     return B.CreateCall(FunctionCallee(GroupIndex));
   }
-
-  if (SemanticName == "SV_DISPATCHTHREADID") {
+  case llvm::dxbc::PSV::SemanticKind::DispatchThreadID: {
     llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
     llvm::Function *ThreadIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
@@ -1454,8 +1453,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
             : CGM.getIntrinsic(IntrinID);
     return buildVectorInput(B, ThreadIDIntrinsic, Type);
   }
-
-  if (SemanticName == "SV_GROUPTHREADID") {
+  case llvm::dxbc::PSV::SemanticKind::GroupThreadID: {
     llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
     llvm::Function *GroupThreadIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
@@ -1463,8 +1461,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
             : CGM.getIntrinsic(IntrinID);
     return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
   }
-
-  if (SemanticName == "SV_GROUPID") {
+  case llvm::dxbc::PSV::SemanticKind::GroupID: {
     llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
     llvm::Function *GroupIDIntrinsic =
         llvm::Intrinsic::isOverloaded(IntrinID)
@@ -1472,38 +1469,26 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
             : CGM.getIntrinsic(IntrinID);
     return buildVectorInput(B, GroupIDIntrinsic, Type);
   }
-
-  const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
-  assert(ShaderAttr && "Entry point has no shader attribute");
-  llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
-
-  if (SemanticName == "SV_POSITION") {
-    if (ST == Triple::EnvironmentType::Pixel) {
-      if (CGM.getTarget().getTriple().isSPIRV())
-        return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
-                                      Semantic->getAttrName()->getName(),
-                                      /* BuiltIn::FragCoord */ 15);
-      if (CGM.getTarget().getTriple().isDXIL())
-        return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
-                                        Signature);
-    }
-
-    if (ST == Triple::EnvironmentType::Vertex) {
-      return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index,
-                                  Signature);
-    }
-  }
-
-  if (SemanticName == "SV_VERTEXID") {
-    if (ST == Triple::EnvironmentType::Vertex) {
-      if (CGM.getTarget().getTriple().isSPIRV())
-        return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
-                                      Semantic->getAttrName()->getName(),
-                                      /* BuiltIn::VertexIndex */ 42);
-      else
-        return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
-                                        Signature);
-    }
+  case llvm::dxbc::PSV::SemanticKind::Position:
+    if (CGM.getTarget().getTriple().isSPIRV())
+      return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
+                                    Semantic->getAttrName()->getName(),
+                                    /* BuiltIn::FragCoord */ 15);
+    if (CGM.getTarget().getTriple().isDXIL())
+      return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
+                                      Signature);
+    break;
+  case llvm::dxbc::PSV::SemanticKind::VertexID:
+    if (CGM.getTarget().getTriple().isSPIRV())
+      return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
+                                    Semantic->getAttrName()->getName(),
+                                    /* BuiltIn::VertexIndex */ 42);
+    if (CGM.getTarget().getTriple().isDXIL())
+      return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
+                                      Signature);
+    break;
+  default:
+    break;
   }
 
   llvm_unreachable(
@@ -1524,30 +1509,29 @@ static void createSPIRVBuiltinStore(IRBuilder<> &B, 
llvm::Module &M,
   B.CreateStore(Source, GV);
 }
 
-void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value 
*Source,
-                                            const clang::DeclaratorDecl *Decl,
-                                            HLSLAppliedSemanticAttr *Semantic,
-                                            std::optional<unsigned> Index,
-                                            SemanticSignatures &Signature) {
-
-  std::string SemanticName = Semantic->getAttrName()->getName().upper();
-  if (SemanticName == "SV_POSITION") {
+void CGHLSLRuntime::emitSystemSemanticStore(
+    IRBuilder<> &B, llvm::Value *Source, const clang::DeclaratorDecl *Decl,
+    HLSLAppliedSemanticAttr *Semantic,
+    llvm::dxbc::PSV::SemanticKind SemanticKind, std::optional<unsigned> Index,
+    SemanticSignatures &Signature) {
+  switch (SemanticKind) {
+  case llvm::dxbc::PSV::SemanticKind::Position:
     if (CGM.getTarget().getTriple().isDXIL()) {
       emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
       return;
     }
-
     if (CGM.getTarget().getTriple().isSPIRV()) {
       createSPIRVBuiltinStore(B, CGM.getModule(), Source,
                               Semantic->getAttrName()->getName(),
                               /* BuiltIn::Position */ 0);
       return;
     }
-  }
-
-  if (SemanticName == "SV_TARGET") {
+    break;
+  case llvm::dxbc::PSV::SemanticKind::Target:
     emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
     return;
+  default:
+    break;
   }
 
   llvm_unreachable(
@@ -1560,10 +1544,19 @@ llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad(
     SemanticSignatures &Signature) {
 
   std::optional<unsigned> Index = Semantic->getSemanticIndex();
-  if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
-    return emitSystemSemanticLoad(B, FD, Type, Decl, Semantic, Index,
-                                  Signature);
-  return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index, Signature);
+  llvm::dxbc::PSV::SemanticKind SemanticKind =
+      llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
+  const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
+  assert(ShaderAttr && "Entry point has no shader attribute");
+  llvm::hlsl::SemanticInterpretation Interpretation =
+      llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
+                                        llvm::hlsl::IOType::In);
+  if (Interpretation == llvm::hlsl::SemanticInterpretation::Invalid)
+    llvm_unreachable("invalid semantic should have been diagnosed by Sema");
+  if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
+    return emitUserSemanticLoad(B, FD, Type, Decl, Semantic, Index, Signature);
+  return emitSystemSemanticLoad(B, Type, Decl, Semantic, SemanticKind, Index,
+                                Signature);
 }
 
 void CGHLSLRuntime::handleScalarSemanticStore(IRBuilder<> &B,
@@ -1573,10 +1566,21 @@ void 
CGHLSLRuntime::handleScalarSemanticStore(IRBuilder<> &B,
                                               HLSLAppliedSemanticAttr 
*Semantic,
                                               SemanticSignatures &Signature) {
   std::optional<unsigned> Index = Semantic->getSemanticIndex();
-  if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
-    emitSystemSemanticStore(B, Source, Decl, Semantic, Index, Signature);
-  else
-    emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
+  llvm::dxbc::PSV::SemanticKind SemanticKind =
+      llvm::hlsl::getSemanticKind(Semantic->getAttrName()->getName());
+  const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
+  assert(ShaderAttr && "Entry point has no shader attribute");
+
+  llvm::hlsl::SemanticInterpretation Interpretation =
+      llvm::hlsl::getInterpretationKind(SemanticKind, ShaderAttr->getType(),
+                                        llvm::hlsl::IOType::Out);
+  assert(Interpretation != llvm::hlsl::SemanticInterpretation::Invalid &&
+         "invalid semantic should have been diagnosed by Sema");
+
+  if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary)
+    return emitUserSemanticStore(B, Source, Decl, Semantic, Index, Signature);
+  emitSystemSemanticStore(B, Source, Decl, Semantic, SemanticKind, Index,
+                          Signature);
 }
 
 std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 2f251505cfa3e..29d085b2c76e0 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -222,16 +222,16 @@ class CGHLSLRuntime {
 
   CodeGenModule &CGM;
 
-  llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B,
-                                      const FunctionDecl *FD, llvm::Type *Type,
-                                      const clang::DeclaratorDecl *Decl,
-                                      HLSLAppliedSemanticAttr *Semantic,
-                                      std::optional<unsigned> Index,
-                                      SemanticSignatures &Signature);
+  llvm::Value *emitSystemSemanticLoad(
+      llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl 
*Decl,
+      HLSLAppliedSemanticAttr *Semantic,
+      llvm::dxbc::PSV::SemanticKind SemanticKind, std::optional<unsigned> 
Index,
+      SemanticSignatures &Signature);
 
   void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
                                const clang::DeclaratorDecl *Decl,
                                HLSLAppliedSemanticAttr *Semantic,
+                               llvm::dxbc::PSV::SemanticKind SemanticKind,
                                std::optional<unsigned> Index,
                                SemanticSignatures &Signature);
 

>From 73a666ce1a12e2d2e4a46d2430404a628b7f34a0 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Fri, 21 Aug 2026 19:00:44 +0000
Subject: [PATCH 18/18] review: small typo

---
 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h 
b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 8e355a05cb86c..3f2d2946d44eb 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -41,6 +41,8 @@ enum IOType {
   InOut = 0b011,
   PatchConstantOrPrimitive = 0b100,
   All = 0b111,
+
+  LLVM_MARK_AS_BITMASK_ENUM(PatchConstantOrPrimitive),
 };
 
 enum class SemanticInterpretation {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to