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
