[llvm] [HLSL] Add in-memory representation of Semantic Signatures (PR #209907)
Finn Plummer via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 22 10:59:31 PDT 2026
https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/209907
>From 0a531171aae974ad3df359970f4cea2d6efb08ac Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 21:15:16 +0000
Subject: [PATCH 01/12] add in-memory representation
---
.../llvm/Frontend/HLSL/SemanticSignatures.h | 89 +++++++++++++++++++
1 file changed, 89 insertions(+)
create mode 100644 llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
new file mode 100644
index 0000000000000..16461a8d2faf0
--- /dev/null
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -0,0 +1,89 @@
+//===- SemanticSignatures.h - HLSL Semantic Signature helper objects ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains structure definitions of HLSL Semantic Signature
+/// objects.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FRONTEND_HLSL_SEMANTICSIGNATURES_H
+#define LLVM_FRONTEND_HLSL_SEMANTICSIGNATURES_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DXILABI.h"
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+namespace hlsl {
+
+// Definitions of the in-memory data layout structures
+
+// Sentinel values denoting that an element is unallocated
+static constexpr uint32_t UnallocatedRow = ~0U;
+static constexpr uint8_t UnallocatedCol = 0xFF;
+
+// Models a single packed range of signature rows with its semantic name and
+// indices, register placement, component masks, and stage-specific attributes.
+struct SemanticSignatureElement {
+ uint32_t SigId;
+ StringRef SemanticName;
+ dxil::ElementType CompType = dxil::ElementType::Invalid;
+ dxbc::PSV::SemanticKind SemanticKind = dxbc::PSV::SemanticKind::Arbitrary;
+ SmallVector<uint32_t> SemanticIndices;
+ dxbc::PSV::InterpolationMode InterpMode =
+ dxbc::PSV::InterpolationMode::Undefined;
+ uint32_t Rows = 1;
+ uint8_t Cols = 1;
+ uint32_t StartRow = UnallocatedRow;
+ uint8_t StartCol = UnallocatedCol;
+ uint8_t UsageMask = 0;
+ uint8_t DynIndexMask = 0;
+ uint32_t GSStream = 0;
+
+ bool isAllocated() const {
+ return StartRow != UnallocatedRow && StartCol != UnallocatedCol;
+ }
+
+ uint8_t getDeclaredMask() const {
+ if (!isAllocated())
+ return 0;
+ return static_cast<uint8_t>(((1U << Cols) - 1U) << StartCol);
+ }
+
+ uint8_t getAlwaysReadsMask() const { return UsageMask; }
+
+ uint8_t getNeverWritesMask() const {
+ return static_cast<uint8_t>(~UsageMask & getDeclaredMask());
+ }
+
+ dxbc::SigMinPrecision getMinPrecision(bool UseMinPrecision) const {
+ if (!UseMinPrecision)
+ return dxbc::SigMinPrecision::Default;
+ switch (CompType) {
+ case dxil::ElementType::F16:
+ return dxbc::SigMinPrecision::Float16;
+ case dxil::ElementType::I16:
+ case dxil::ElementType::SNormF16:
+ case dxil::ElementType::UNormF16:
+ return dxbc::SigMinPrecision::SInt16;
+ case dxil::ElementType::U16:
+ return dxbc::SigMinPrecision::UInt16;
+ default:
+ return dxbc::SigMinPrecision::Default;
+ }
+ }
+};
+
+} // namespace hlsl
+} // namespace llvm
+
+#endif // LLVM_FRONTEND_HLSL_SEMANTICSIGNATURES_H
>From 8bcbde9a68b9cabbdbe04f0aa5cff700cb321231 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:22:40 +0000
Subject: [PATCH 02/12] add a harness for testing metadata
---
.../llvm/Frontend/HLSL/SemanticSignatures.h | 12 ++++
llvm/lib/Frontend/HLSL/CMakeLists.txt | 1 +
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 27 +++++++++
llvm/unittests/Frontend/CMakeLists.txt | 1 +
.../HLSLSemanticSignatureMetadataTest.cpp | 57 +++++++++++++++++++
5 files changed, 98 insertions(+)
create mode 100644 llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
create mode 100644 llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 16461a8d2faf0..7d5efc663e02a 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -19,10 +19,15 @@
#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DXILABI.h"
+#include "llvm/Support/Error.h"
#include <cstdint>
#include <string>
namespace llvm {
+
+class LLVMContext;
+class MDNode;
+
namespace hlsl {
// Definitions of the in-memory data layout structures
@@ -81,6 +86,13 @@ struct SemanticSignatureElement {
return dxbc::SigMinPrecision::Default;
}
}
+
+ // Parse a signature element from its metadata representation
+ LLVM_ABI static Expected<SemanticSignatureElement>
+ fromMetadata(const MDNode *Node);
+
+ // Build the metadata representation of this signature element
+ LLVM_ABI MDNode *toMetadata(LLVMContext &Ctx) const;
};
} // namespace hlsl
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index 3d225770e8d5b..b8d1456a787ce 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -5,6 +5,7 @@ add_llvm_component_library(LLVMFrontendHLSL
HLSLRootSignature.cpp
RootSignatureMetadata.cpp
RootSignatureValidations.cpp
+ SemanticSignatures.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
new file mode 100644
index 0000000000000..f5d277d91a889
--- /dev/null
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -0,0 +1,27 @@
+//===- SemanticSignatures.cpp - HLSL Semantic Signature helpers -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file implements a library for working with HLSL shader input and
+/// output semantic signatures and their DirectX metadata representation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/SemanticSignatures.h"
+#include "llvm/IR/Metadata.h"
+
+using namespace llvm;
+using namespace llvm::hlsl;
+
+Expected<SemanticSignatureElement>
+SemanticSignatureElement::fromMetadata(const MDNode *Node) {
+ return SemanticSignatureElement{};
+}
+
+MDNode *SemanticSignatureElement::toMetadata(LLVMContext &Ctx) const {
+ return MDNode::get(Ctx, {});
+}
diff --git a/llvm/unittests/Frontend/CMakeLists.txt b/llvm/unittests/Frontend/CMakeLists.txt
index 1ce34e77cb348..ff3b382a67fe9 100644
--- a/llvm/unittests/Frontend/CMakeLists.txt
+++ b/llvm/unittests/Frontend/CMakeLists.txt
@@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(LLVMFrontendTests
HLSLBindingTest.cpp
HLSLRootSignatureDumpTest.cpp
+ HLSLSemanticSignatureMetadataTest.cpp
OpenACCTest.cpp
OpenMPContextTest.cpp
OpenMPIRBuilderTest.cpp
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
new file mode 100644
index 0000000000000..6784a735840fe
--- /dev/null
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -0,0 +1,57 @@
+//===- HLSLSemanticSignatureMetadataTest.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/SemanticSignatures.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Type.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::hlsl;
+
+namespace {
+
+class HLSLSemanticSignatureMetadataTest : public testing::Test {
+protected:
+ LLVMContext Ctx;
+
+ Metadata *getI32(uint32_t Val) {
+ return ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), Val));
+ }
+
+ Metadata *getI8(uint8_t Val) {
+ return ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt8Ty(Ctx), Val));
+ }
+
+ Metadata *getStr(StringRef Val) { return MDString::get(Ctx, Val); }
+
+ MDNode *getIndices(ArrayRef<uint32_t> Indices) {
+ SmallVector<Metadata *> Ops;
+ for (uint32_t I : Indices)
+ Ops.push_back(getI32(I));
+ return MDNode::get(Ctx, Ops);
+ }
+};
+
+TEST_F(HLSLSemanticSignatureMetadataTest, StructHelpers) {
+ SemanticSignatureElement Elem;
+ EXPECT_FALSE(Elem.isAllocated());
+
+ Elem.Cols = 4;
+ Elem.StartRow = 0;
+ Elem.StartCol = 0;
+ EXPECT_TRUE(Elem.isAllocated());
+ EXPECT_EQ(Elem.getDeclaredMask(), 0xF);
+}
+
+} // namespace
>From b6acceaaab4d47f9ba2ae1e5323cb9cd1580edbd Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:36:41 +0000
Subject: [PATCH 03/12] add testing of metadata to struct
---
.../HLSLSemanticSignatureMetadataTest.cpp | 184 ++++++++++++++++++
1 file changed, 184 insertions(+)
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index 6784a735840fe..817f67e1c4753 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -11,6 +11,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Type.h"
+#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -41,8 +42,25 @@ class HLSLSemanticSignatureMetadataTest : public testing::Test {
Ops.push_back(getI32(I));
return MDNode::get(Ctx, Ops);
}
+
+ // Assemble a raw signature element node from the example in the spec
+ MDNode *getElement(uint32_t SigId, StringRef Name, uint32_t CompType,
+ uint32_t SemanticKind, ArrayRef<uint32_t> Indices,
+ uint32_t InterpMode, uint32_t Rows, uint8_t Cols,
+ uint32_t StartRow, uint8_t StartCol, uint8_t UsageMask,
+ uint8_t DynIndexMask, uint32_t GSStream) {
+ return MDNode::get(
+ Ctx, {getI32(SigId), getStr(Name), getI32(CompType),
+ getI32(SemanticKind), getIndices(Indices), getI32(InterpMode),
+ getI32(Rows), getI8(Cols), getI32(StartRow), getI8(StartCol),
+ getI8(UsageMask), getI8(DynIndexMask), getI32(GSStream)});
+ }
};
+//===----------------------------------------------------------------------===//
+// Success cases
+//===----------------------------------------------------------------------===//
+
TEST_F(HLSLSemanticSignatureMetadataTest, StructHelpers) {
SemanticSignatureElement Elem;
EXPECT_FALSE(Elem.isAllocated());
@@ -54,4 +72,170 @@ TEST_F(HLSLSemanticSignatureMetadataTest, StructHelpers) {
EXPECT_EQ(Elem.getDeclaredMask(), 0xF);
}
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElement) {
+ MDNode *Node = getElement(/*SigId=*/1, "TEXCOORD", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0, 1},
+ /*InterpMode=*/0, /*Rows=*/2, /*Cols=*/4,
+ /*StartRow=*/1, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+
+ EXPECT_EQ(Elem->SigId, 1u);
+ EXPECT_EQ(Elem->SemanticName, "TEXCOORD");
+ EXPECT_EQ(Elem->CompType, dxil::ElementType::F32);
+ EXPECT_EQ(Elem->SemanticKind, dxbc::PSV::SemanticKind::Arbitrary);
+ EXPECT_THAT(Elem->SemanticIndices, testing::ElementsAre(0u, 1u));
+ EXPECT_EQ(Elem->InterpMode, dxbc::PSV::InterpolationMode::Undefined);
+ EXPECT_EQ(Elem->Rows, 2u);
+ EXPECT_EQ(Elem->Cols, 4u);
+ EXPECT_EQ(Elem->StartRow, 1u);
+ EXPECT_EQ(Elem->StartCol, 0u);
+ EXPECT_EQ(Elem->UsageMask, 0u);
+ EXPECT_EQ(Elem->DynIndexMask, 0u);
+ EXPECT_EQ(Elem->GSStream, 0u);
+}
+
+// SV_Target output with a non-zero usage/dynamic-index mask and semantic index
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementSystemValue) {
+ MDNode *Node = getElement(/*SigId=*/1, "SV_Target", /*CompType=*/9,
+ /*SemanticKind=*/16, /*Indices=*/{1},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/4,
+ /*StartRow=*/1, /*StartCol=*/0, /*UsageMask=*/0x7,
+ /*DynIndexMask=*/0x1, /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+
+ EXPECT_EQ(Elem->SemanticName, "SV_Target");
+ EXPECT_EQ(Elem->SemanticKind, dxbc::PSV::SemanticKind::Target);
+ EXPECT_THAT(Elem->SemanticIndices, testing::ElementsAre(1u));
+ EXPECT_EQ(Elem->UsageMask, 0x7u);
+ EXPECT_EQ(Elem->DynIndexMask, 0x1u);
+}
+
+// An unallocated element uses the row/col sentinels
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementUnallocated) {
+ MDNode *Node = getElement(/*SigId=*/0, "POSITION", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/4,
+ /*StartRow=*/UnallocatedRow, /*StartCol=*/UnallocatedCol,
+ /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+
+ EXPECT_EQ(Elem->StartRow, UnallocatedRow);
+ EXPECT_EQ(Elem->StartCol, UnallocatedCol);
+ EXPECT_FALSE(Elem->isAllocated());
+}
+
+// Every component type value maps onto the matching dxil::ElementType
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementComponentTypes) {
+ for (dxil::ElementType CompType :
+ {dxil::ElementType::I32, dxil::ElementType::U32,
+ dxil::ElementType::F16, dxil::ElementType::F32,
+ dxil::ElementType::F64, dxil::ElementType::I16}) {
+ MDNode *Node = getElement(
+ /*SigId=*/0, "A", static_cast<uint32_t>(CompType), /*SemanticKind=*/0,
+ /*Indices=*/{0}, /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0, /*DynIndexMask=*/0,
+ /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+ EXPECT_EQ(Elem->CompType, CompType);
+ }
+}
+
+// Every interpolation mode value maps onto the matching enumerator
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInterpModes) {
+ for (dxbc::PSV::InterpolationMode Mode :
+ {dxbc::PSV::InterpolationMode::Constant,
+ dxbc::PSV::InterpolationMode::Linear,
+ dxbc::PSV::InterpolationMode::LinearCentroid,
+ dxbc::PSV::InterpolationMode::LinearNoperspective,
+ dxbc::PSV::InterpolationMode::LinearSample}) {
+ MDNode *Node = getElement(
+ /*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
+ static_cast<uint32_t>(Mode), /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0,
+ /*StartCol=*/0, /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+ EXPECT_EQ(Elem->InterpMode, Mode);
+ }
+}
+
+// A column-offset allocation drives the derived declared/usage masks
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementDerivedMasks) {
+ MDNode *Node = getElement(/*SigId=*/0, "SV_Position", /*CompType=*/9,
+ /*SemanticKind=*/3, /*Indices=*/{0},
+ /*InterpMode=*/4, /*Rows=*/1, /*Cols=*/2,
+ /*StartRow=*/0, /*StartCol=*/1, /*UsageMask=*/0x2,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+
+ EXPECT_EQ(Elem->SemanticKind, dxbc::PSV::SemanticKind::Position);
+ EXPECT_TRUE(Elem->isAllocated());
+ // ((1 << 2) - 1) << 1 == 0b0110
+ EXPECT_EQ(Elem->getDeclaredMask(), 0x6);
+ EXPECT_EQ(Elem->getAlwaysReadsMask(), 0x2);
+ // ~0x2 & 0x6 == 0x4
+ EXPECT_EQ(Elem->getNeverWritesMask(), 0x4);
+}
+
+// A geometry shader output carries a non-zero stream index
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementGSStream) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/3);
+
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+ EXPECT_EQ(Elem->GSStream, 3u);
+}
+
+//===----------------------------------------------------------------------===//
+// Error cases
+//===----------------------------------------------------------------------===//
+
+// A null node is not a valid signature element
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementNull) {
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(nullptr),
+ Failed());
+}
+
+// A node with the wrong number of operands is rejected
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementWrongOperandCount) {
+ MDNode *Node = MDNode::get(Ctx, {getI32(0), getStr("A")});
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// A node with an operand of the wrong type is rejected
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementWrongOperandType) {
+ // Operand 0 (SigId) should be an integer, not a string
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ SmallVector<Metadata *> Ops(Node->op_begin(), Node->op_end());
+ Ops[0] = getStr("not an int");
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(MDNode::get(Ctx, Ops)), Failed());
+}
+
} // namespace
>From 4b387134edce9ded753629db206768183d62a46c Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:39:00 +0000
Subject: [PATCH 04/12] add metadata to struct validation tests
---
.../HLSLSemanticSignatureMetadataTest.cpp | 112 ++++++++++++++++++
1 file changed, 112 insertions(+)
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index 817f67e1c4753..53ca977a603e3 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -238,4 +238,116 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementWrongOperandType) {
SemanticSignatureElement::fromMetadata(MDNode::get(Ctx, Ops)), Failed());
}
+//===--------------------------------------------------------------------===//
+// Per-operand range/enum validation
+//===--------------------------------------------------------------------===//
+
+// A component type outside dxil::ElementType is rejected
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidCompType) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/100,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// A semantic kind outside dxbc::PSV::SemanticKind is rejected
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSemanticKind) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/100, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// An interpolation mode outside dxbc::PSV::InterpolationMode is rejected
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidInterpMode) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/100, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// The number of components per row must be within 1-4
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidCols) {
+ for (uint8_t Cols : {uint8_t(0), uint8_t(5)}) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, Cols,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node),
+ Failed());
+ }
+}
+
+// A start column must be within 0-3 or the unallocated sentinel
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidStartCol) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/4, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// The row/col sentinels must be set together
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSentinelPair) {
+ MDNode *RowOnly = getElement(
+ /*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/UnallocatedRow,
+ /*StartCol=*/0, /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(RowOnly),
+ Failed());
+
+ MDNode *ColOnly = getElement(
+ /*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0,
+ /*StartCol=*/UnallocatedCol, /*UsageMask=*/0, /*DynIndexMask=*/0,
+ /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(ColOnly),
+ Failed());
+}
+
+// The usage and dynamic-index masks are 4-bit values
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidMasks) {
+ MDNode *BadUsage = getElement(
+ /*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0, /*StartCol=*/0,
+ /*UsageMask=*/0x10, /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(BadUsage),
+ Failed());
+
+ MDNode *BadDyn = getElement(
+ /*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0, /*StartCol=*/0,
+ /*UsageMask=*/0, /*DynIndexMask=*/0x10, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(BadDyn),
+ Failed());
+}
+
+// A geometry shader output stream index must be within 0-3
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidGSStream) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/4);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
+// The number of semantic indices must equal the number of rows
+TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementIndicesRowMismatch) {
+ MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/2, /*Cols=*/1,
+ /*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+}
+
} // namespace
>From a37c23a3a84d0b55a8e88bde2f9e5b5685ea62c4 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:44:34 +0000
Subject: [PATCH 05/12] add struct to metadata tests
---
.../HLSLSemanticSignatureMetadataTest.cpp | 123 ++++++++++++++++++
1 file changed, 123 insertions(+)
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index 53ca977a603e3..73aa5d19cac11 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -55,6 +55,16 @@ class HLSLSemanticSignatureMetadataTest : public testing::Test {
getI32(Rows), getI8(Cols), getI32(StartRow), getI8(StartCol),
getI8(UsageMask), getI8(DynIndexMask), getI32(GSStream)});
}
+
+ // Read back an integer operand
+ uint64_t getIntOp(const MDNode *N, unsigned I) {
+ return mdconst::extract<ConstantInt>(N->getOperand(I))->getZExtValue();
+ }
+
+ // Read back a string operand
+ StringRef getStrOp(const MDNode *N, unsigned I) {
+ return cast<MDString>(N->getOperand(I))->getString();
+ }
};
//===----------------------------------------------------------------------===//
@@ -350,4 +360,117 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementIndicesRowMismatch) {
EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
}
+//===--------------------------------------------------------------------===//
+// struct -> metadata
+//===--------------------------------------------------------------------===//
+
+// A fully populated element emits all 13 operands in order
+TEST_F(HLSLSemanticSignatureMetadataTest, ElementToMetadata) {
+ SemanticSignatureElement Elem;
+ Elem.SigId = 1;
+ Elem.SemanticName = "TEXCOORD";
+ Elem.CompType = dxil::ElementType::F32;
+ Elem.SemanticKind = dxbc::PSV::SemanticKind::Arbitrary;
+ Elem.SemanticIndices = {0, 1};
+ Elem.InterpMode = dxbc::PSV::InterpolationMode::Undefined;
+ Elem.Rows = 2;
+ Elem.Cols = 4;
+ Elem.StartRow = 1;
+ Elem.StartCol = 0;
+ Elem.UsageMask = 0;
+ Elem.DynIndexMask = 0;
+ Elem.GSStream = 0;
+
+ MDNode *Node = Elem.toMetadata(Ctx);
+ ASSERT_EQ(Node->getNumOperands(), 13u);
+ EXPECT_EQ(getIntOp(Node, 0), 1u);
+ EXPECT_EQ(getStrOp(Node, 1), "TEXCOORD");
+ EXPECT_EQ(getIntOp(Node, 2), 9u);
+ EXPECT_EQ(getIntOp(Node, 3), 0u);
+ EXPECT_EQ(Node->getOperand(4).get(), getIndices({0, 1}));
+ EXPECT_EQ(getIntOp(Node, 5), 0u);
+ EXPECT_EQ(getIntOp(Node, 6), 2u);
+ EXPECT_EQ(getIntOp(Node, 7), 4u);
+ EXPECT_EQ(getIntOp(Node, 8), 1u);
+ EXPECT_EQ(getIntOp(Node, 9), 0u);
+ EXPECT_EQ(getIntOp(Node, 10), 0u);
+ EXPECT_EQ(getIntOp(Node, 11), 0u);
+ EXPECT_EQ(getIntOp(Node, 12), 0u);
+}
+
+// System value, non-zero masks and a non-zero stream index are emitted
+TEST_F(HLSLSemanticSignatureMetadataTest, ElementToMetadataSystemValue) {
+ SemanticSignatureElement Elem;
+ Elem.SigId = 1;
+ Elem.SemanticName = "SV_Target";
+ Elem.CompType = dxil::ElementType::F32;
+ Elem.SemanticKind = dxbc::PSV::SemanticKind::Target;
+ Elem.SemanticIndices = {1};
+ Elem.Rows = 1;
+ Elem.Cols = 4;
+ Elem.StartRow = 1;
+ Elem.StartCol = 0;
+ Elem.UsageMask = 0x7;
+ Elem.DynIndexMask = 0x1;
+ Elem.GSStream = 2;
+
+ MDNode *Node = Elem.toMetadata(Ctx);
+ ASSERT_EQ(Node->getNumOperands(), 13u);
+ EXPECT_EQ(getStrOp(Node, 1), "SV_Target");
+ EXPECT_EQ(getIntOp(Node, 3), 16u);
+ EXPECT_EQ(Node->getOperand(4).get(), getIndices({1}));
+ EXPECT_EQ(getIntOp(Node, 10), 0x7u);
+ EXPECT_EQ(getIntOp(Node, 11), 0x1u);
+ EXPECT_EQ(getIntOp(Node, 12), 2u);
+}
+
+// An unallocated element emits the row/col sentinels
+TEST_F(HLSLSemanticSignatureMetadataTest, ElementToMetadataUnallocated) {
+ SemanticSignatureElement Elem;
+ Elem.SemanticName = "POSITION";
+ Elem.CompType = dxil::ElementType::F32;
+ Elem.SemanticIndices = {0};
+
+ MDNode *Node = Elem.toMetadata(Ctx);
+ ASSERT_EQ(Node->getNumOperands(), 13u);
+ EXPECT_EQ(getIntOp(Node, 8), UnallocatedRow);
+ EXPECT_EQ(getIntOp(Node, 9), UnallocatedCol);
+}
+
+// Emitting then parsing yields an equivalent element
+TEST_F(HLSLSemanticSignatureMetadataTest, ElementRoundTrip) {
+ SemanticSignatureElement Elem;
+ Elem.SigId = 2;
+ Elem.SemanticName = "TEXCOORD";
+ Elem.CompType = dxil::ElementType::F32;
+ Elem.SemanticKind = dxbc::PSV::SemanticKind::Arbitrary;
+ Elem.SemanticIndices = {1};
+ Elem.InterpMode = dxbc::PSV::InterpolationMode::LinearNoperspective;
+ Elem.Rows = 1;
+ Elem.Cols = 4;
+ Elem.StartRow = 2;
+ Elem.StartCol = 0;
+ Elem.UsageMask = 0x7;
+ Elem.DynIndexMask = 0;
+ Elem.GSStream = 0;
+
+ Expected<SemanticSignatureElement> Parsed =
+ SemanticSignatureElement::fromMetadata(Elem.toMetadata(Ctx));
+ ASSERT_THAT_EXPECTED(Parsed, Succeeded());
+ EXPECT_EQ(Parsed->SigId, Elem.SigId);
+ EXPECT_EQ(Parsed->SemanticName, Elem.SemanticName);
+ EXPECT_EQ(Parsed->CompType, Elem.CompType);
+ EXPECT_EQ(Parsed->SemanticKind, Elem.SemanticKind);
+ EXPECT_THAT(Parsed->SemanticIndices,
+ testing::ElementsAreArray(Elem.SemanticIndices));
+ EXPECT_EQ(Parsed->InterpMode, Elem.InterpMode);
+ EXPECT_EQ(Parsed->Rows, Elem.Rows);
+ EXPECT_EQ(Parsed->Cols, Elem.Cols);
+ EXPECT_EQ(Parsed->StartRow, Elem.StartRow);
+ EXPECT_EQ(Parsed->StartCol, Elem.StartCol);
+ EXPECT_EQ(Parsed->UsageMask, Elem.UsageMask);
+ EXPECT_EQ(Parsed->DynIndexMask, Elem.DynIndexMask);
+ EXPECT_EQ(Parsed->GSStream, Elem.GSStream);
+}
+
} // namespace
>From 436498e9d4268754d5b3e1f2da18a887ad445bf6 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:45:54 +0000
Subject: [PATCH 06/12] implement the toMetadata function
---
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 24 ++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index f5d277d91a889..8450e18114a9a 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -12,7 +12,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Frontend/HLSL/SemanticSignatures.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Type.h"
using namespace llvm;
using namespace llvm::hlsl;
@@ -23,5 +25,25 @@ SemanticSignatureElement::fromMetadata(const MDNode *Node) {
}
MDNode *SemanticSignatureElement::toMetadata(LLVMContext &Ctx) const {
- return MDNode::get(Ctx, {});
+ Type *I32Ty = Type::getInt32Ty(Ctx);
+ Type *I8Ty = Type::getInt8Ty(Ctx);
+ auto GetI32 = [&](uint32_t Val) -> Metadata * {
+ return ConstantAsMetadata::get(ConstantInt::get(I32Ty, Val));
+ };
+ auto GetI8 = [&](uint8_t Val) -> Metadata * {
+ return ConstantAsMetadata::get(ConstantInt::get(I8Ty, Val));
+ };
+
+ SmallVector<Metadata *> IndexOps;
+ for (uint32_t Index : SemanticIndices)
+ IndexOps.push_back(GetI32(Index));
+
+ return MDNode::get(
+ Ctx, {GetI32(SigId), MDString::get(Ctx, SemanticName),
+ GetI32(static_cast<uint32_t>(CompType)),
+ GetI32(static_cast<uint32_t>(SemanticKind)),
+ MDNode::get(Ctx, IndexOps),
+ GetI32(static_cast<uint32_t>(InterpMode)), GetI32(Rows),
+ GetI8(Cols), GetI32(StartRow), GetI8(StartCol), GetI8(UsageMask),
+ GetI8(DynIndexMask), GetI32(GSStream)});
}
>From 74a8dc05b45b705fe64baed86c89fce757f93c19 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:47:47 +0000
Subject: [PATCH 07/12] implement the fromMetadata function
---
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 127 +++++++++++++++++-
1 file changed, 126 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 8450e18114a9a..8032f5975ae6a 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -15,13 +15,138 @@
#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;
+namespace {
+// The fixed number of operands in a signature element node
+constexpr unsigned NumElementOperands = 13;
+
+// Inclusive upper bounds of the operand enums
+constexpr uint32_t MaxCompType =
+ static_cast<uint32_t>(dxil::ElementType::PackedU8x32);
+constexpr uint32_t MaxSemanticKind =
+ static_cast<uint32_t>(dxbc::PSV::SemanticKind::Invalid);
+constexpr uint32_t MaxInterpMode =
+ static_cast<uint32_t>(dxbc::PSV::InterpolationMode::Invalid);
+
+Error makeError(const Twine &Msg) {
+ return createStringError(inconvertibleErrorCode(), Msg);
+}
+
+Expected<uint64_t> extractInt(const MDNode *Node, unsigned OpId) {
+ auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(Node->getOperand(OpId));
+ if (!CI)
+ return makeError("expected integer operand " + Twine(OpId));
+ return CI->getZExtValue();
+}
+} // namespace
+
Expected<SemanticSignatureElement>
SemanticSignatureElement::fromMetadata(const MDNode *Node) {
- return SemanticSignatureElement{};
+ if (!Node)
+ return makeError("signature element node is null");
+ if (Node->getNumOperands() != NumElementOperands)
+ return makeError("signature element node has wrong number of operands");
+
+ SemanticSignatureElement Elem;
+
+ Expected<uint64_t> SigId = extractInt(Node, 0);
+ if (!SigId)
+ return SigId.takeError();
+ Elem.SigId = *SigId;
+
+ auto *Name = dyn_cast<MDString>(Node->getOperand(1));
+ if (!Name)
+ return makeError("expected semantic name string");
+ Elem.SemanticName = Name->getString();
+
+ Expected<uint64_t> CompType = extractInt(Node, 2);
+ if (!CompType)
+ return CompType.takeError();
+ if (*CompType > MaxCompType)
+ return makeError("invalid component type");
+ Elem.CompType = static_cast<dxil::ElementType>(*CompType);
+
+ Expected<uint64_t> SemanticKind = extractInt(Node, 3);
+ if (!SemanticKind)
+ return SemanticKind.takeError();
+ if (*SemanticKind > MaxSemanticKind)
+ return makeError("invalid semantic kind");
+ Elem.SemanticKind = static_cast<dxbc::PSV::SemanticKind>(*SemanticKind);
+
+ auto *Indices = dyn_cast<MDNode>(Node->getOperand(4));
+ if (!Indices)
+ return makeError("expected semantic indices node");
+ for (unsigned I = 0, E = Indices->getNumOperands(); I != E; ++I) {
+ Expected<uint64_t> Index = extractInt(Indices, I);
+ if (!Index)
+ return Index.takeError();
+ Elem.SemanticIndices.push_back(*Index);
+ }
+
+ Expected<uint64_t> InterpMode = extractInt(Node, 5);
+ if (!InterpMode)
+ return InterpMode.takeError();
+ if (*InterpMode > MaxInterpMode)
+ return makeError("invalid interpolation mode");
+ Elem.InterpMode = static_cast<dxbc::PSV::InterpolationMode>(*InterpMode);
+
+ Expected<uint64_t> Rows = extractInt(Node, 6);
+ if (!Rows)
+ return Rows.takeError();
+ Elem.Rows = *Rows;
+
+ Expected<uint64_t> Cols = extractInt(Node, 7);
+ if (!Cols)
+ return Cols.takeError();
+ if (*Cols < 1 || *Cols > 4)
+ return makeError("number of components per row must be within 1-4");
+ Elem.Cols = *Cols;
+
+ Expected<uint64_t> StartRow = extractInt(Node, 8);
+ if (!StartRow)
+ return StartRow.takeError();
+ Elem.StartRow = *StartRow;
+
+ Expected<uint64_t> StartCol = extractInt(Node, 9);
+ if (!StartCol)
+ return StartCol.takeError();
+ if (*StartCol > 3 && *StartCol != UnallocatedCol)
+ return makeError("start column must be within 0-3 or unallocated");
+ Elem.StartCol = *StartCol;
+
+ // The row/col sentinels are always set together
+ if ((Elem.StartRow == UnallocatedRow) != (Elem.StartCol == UnallocatedCol))
+ return makeError("start row and column sentinels must be set together");
+
+ Expected<uint64_t> UsageMask = extractInt(Node, 10);
+ if (!UsageMask)
+ return UsageMask.takeError();
+ if (*UsageMask > 0xF)
+ return makeError("usage mask must be a 4-bit value");
+ Elem.UsageMask = *UsageMask;
+
+ Expected<uint64_t> DynIndexMask = extractInt(Node, 11);
+ if (!DynIndexMask)
+ return DynIndexMask.takeError();
+ if (*DynIndexMask > 0xF)
+ return makeError("dynamic index mask must be a 4-bit value");
+ Elem.DynIndexMask = *DynIndexMask;
+
+ Expected<uint64_t> GSStream = extractInt(Node, 12);
+ if (!GSStream)
+ return GSStream.takeError();
+ if (*GSStream > 3)
+ return makeError("geometry shader stream index must be within 0-3");
+ Elem.GSStream = *GSStream;
+
+ if (Elem.SemanticIndices.size() != Elem.Rows)
+ return makeError("number of semantic indices must equal the number of rows");
+
+ return Elem;
}
MDNode *SemanticSignatureElement::toMetadata(LLVMContext &Ctx) const {
>From 067a40010a0bc2d3f0f0bf7d9a94b2537b97334c Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 18:52:20 +0000
Subject: [PATCH 08/12] update tests to check error strings
---
.../HLSLSemanticSignatureMetadataTest.cpp | 56 ++++++++++++-------
1 file changed, 37 insertions(+), 19 deletions(-)
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index 73aa5d19cac11..8950498887e2f 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -224,14 +224,17 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementGSStream) {
// A null node is not a valid signature element
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementNull) {
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(nullptr),
- Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(nullptr),
+ FailedWithMessage("signature element node is null"));
}
// A node with the wrong number of operands is rejected
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementWrongOperandCount) {
MDNode *Node = MDNode::get(Ctx, {getI32(0), getStr("A")});
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("signature element node has wrong number of operands"));
}
// A node with an operand of the wrong type is rejected
@@ -245,7 +248,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementWrongOperandType) {
SmallVector<Metadata *> Ops(Node->op_begin(), Node->op_end());
Ops[0] = getStr("not an int");
EXPECT_THAT_EXPECTED(
- SemanticSignatureElement::fromMetadata(MDNode::get(Ctx, Ops)), Failed());
+ SemanticSignatureElement::fromMetadata(MDNode::get(Ctx, Ops)),
+ FailedWithMessage("expected integer operand 0"));
}
//===--------------------------------------------------------------------===//
@@ -259,7 +263,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidCompType) {
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("invalid component type"));
}
// A semantic kind outside dxbc::PSV::SemanticKind is rejected
@@ -269,7 +274,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSemanticKind)
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("invalid semantic kind"));
}
// An interpolation mode outside dxbc::PSV::InterpolationMode is rejected
@@ -279,7 +285,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidInterpMode) {
/*InterpMode=*/100, /*Rows=*/1, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("invalid interpolation mode"));
}
// The number of components per row must be within 1-4
@@ -290,8 +297,9 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidCols) {
/*InterpMode=*/0, /*Rows=*/1, Cols,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node),
- Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("number of components per row must be within 1-4"));
}
}
@@ -302,7 +310,9 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidStartCol) {
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/4, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("start column must be within 0-3 or unallocated"));
}
// The row/col sentinels must be set together
@@ -311,16 +321,18 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSentinelPair)
/*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/UnallocatedRow,
/*StartCol=*/0, /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(RowOnly),
- Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(RowOnly),
+ FailedWithMessage("start row and column sentinels must be set together"));
MDNode *ColOnly = getElement(
/*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0,
/*StartCol=*/UnallocatedCol, /*UsageMask=*/0, /*DynIndexMask=*/0,
/*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(ColOnly),
- Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(ColOnly),
+ FailedWithMessage("start row and column sentinels must be set together"));
}
// The usage and dynamic-index masks are 4-bit values
@@ -330,14 +342,15 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidMasks) {
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0, /*StartCol=*/0,
/*UsageMask=*/0x10, /*DynIndexMask=*/0, /*GSStream=*/0);
EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(BadUsage),
- Failed());
+ FailedWithMessage("usage mask must be a 4-bit value"));
MDNode *BadDyn = getElement(
/*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/0, /*StartCol=*/0,
/*UsageMask=*/0, /*DynIndexMask=*/0x10, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(BadDyn),
- Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(BadDyn),
+ FailedWithMessage("dynamic index mask must be a 4-bit value"));
}
// A geometry shader output stream index must be within 0-3
@@ -347,7 +360,9 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidGSStream) {
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/4);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage("geometry shader stream index must be within 0-3"));
}
// The number of semantic indices must equal the number of rows
@@ -357,7 +372,10 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementIndicesRowMismatch) {
/*InterpMode=*/0, /*Rows=*/2, /*Cols=*/1,
/*StartRow=*/0, /*StartCol=*/0, /*UsageMask=*/0,
/*DynIndexMask=*/0, /*GSStream=*/0);
- EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(Node), Failed());
+ EXPECT_THAT_EXPECTED(
+ SemanticSignatureElement::fromMetadata(Node),
+ FailedWithMessage(
+ "number of semantic indices must equal the number of rows"));
}
//===--------------------------------------------------------------------===//
>From b54b529e1323d501c74c0cd5965d6bb8c28e36ad Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 21:53:01 +0000
Subject: [PATCH 09/12] review: clang-format
---
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 19 ++++++------
.../HLSLSemanticSignatureMetadataTest.cpp | 31 ++++++++++---------
2 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 8032f5975ae6a..860fa7905fce3 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -144,7 +144,8 @@ SemanticSignatureElement::fromMetadata(const MDNode *Node) {
Elem.GSStream = *GSStream;
if (Elem.SemanticIndices.size() != Elem.Rows)
- return makeError("number of semantic indices must equal the number of rows");
+ return makeError(
+ "number of semantic indices must equal the number of rows");
return Elem;
}
@@ -163,12 +164,12 @@ MDNode *SemanticSignatureElement::toMetadata(LLVMContext &Ctx) const {
for (uint32_t Index : SemanticIndices)
IndexOps.push_back(GetI32(Index));
- return MDNode::get(
- Ctx, {GetI32(SigId), MDString::get(Ctx, SemanticName),
- GetI32(static_cast<uint32_t>(CompType)),
- GetI32(static_cast<uint32_t>(SemanticKind)),
- MDNode::get(Ctx, IndexOps),
- GetI32(static_cast<uint32_t>(InterpMode)), GetI32(Rows),
- GetI8(Cols), GetI32(StartRow), GetI8(StartCol), GetI8(UsageMask),
- GetI8(DynIndexMask), GetI32(GSStream)});
+ return MDNode::get(Ctx,
+ {GetI32(SigId), MDString::get(Ctx, SemanticName),
+ GetI32(static_cast<uint32_t>(CompType)),
+ GetI32(static_cast<uint32_t>(SemanticKind)),
+ MDNode::get(Ctx, IndexOps),
+ GetI32(static_cast<uint32_t>(InterpMode)), GetI32(Rows),
+ GetI8(Cols), GetI32(StartRow), GetI8(StartCol),
+ GetI8(UsageMask), GetI8(DynIndexMask), GetI32(GSStream)});
}
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index 8950498887e2f..6833ee7c60f96 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -30,8 +30,7 @@ class HLSLSemanticSignatureMetadataTest : public testing::Test {
}
Metadata *getI8(uint8_t Val) {
- return ConstantAsMetadata::get(
- ConstantInt::get(Type::getInt8Ty(Ctx), Val));
+ return ConstantAsMetadata::get(ConstantInt::get(Type::getInt8Ty(Ctx), Val));
}
Metadata *getStr(StringRef Val) { return MDString::get(Ctx, Val); }
@@ -129,11 +128,12 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementSystemValue) {
// An unallocated element uses the row/col sentinels
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementUnallocated) {
- MDNode *Node = getElement(/*SigId=*/0, "POSITION", /*CompType=*/9,
- /*SemanticKind=*/0, /*Indices=*/{0},
- /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/4,
- /*StartRow=*/UnallocatedRow, /*StartCol=*/UnallocatedCol,
- /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
+ MDNode *Node =
+ getElement(/*SigId=*/0, "POSITION", /*CompType=*/9,
+ /*SemanticKind=*/0, /*Indices=*/{0},
+ /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/4,
+ /*StartRow=*/UnallocatedRow, /*StartCol=*/UnallocatedCol,
+ /*UsageMask=*/0, /*DynIndexMask=*/0, /*GSStream=*/0);
Expected<SemanticSignatureElement> Elem =
SemanticSignatureElement::fromMetadata(Node);
@@ -147,9 +147,9 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementUnallocated) {
// Every component type value maps onto the matching dxil::ElementType
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementComponentTypes) {
for (dxil::ElementType CompType :
- {dxil::ElementType::I32, dxil::ElementType::U32,
- dxil::ElementType::F16, dxil::ElementType::F32,
- dxil::ElementType::F64, dxil::ElementType::I16}) {
+ {dxil::ElementType::I32, dxil::ElementType::U32, dxil::ElementType::F16,
+ dxil::ElementType::F32, dxil::ElementType::F64,
+ dxil::ElementType::I16}) {
MDNode *Node = getElement(
/*SigId=*/0, "A", static_cast<uint32_t>(CompType), /*SemanticKind=*/0,
/*Indices=*/{0}, /*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
@@ -224,9 +224,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementGSStream) {
// A null node is not a valid signature element
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementNull) {
- EXPECT_THAT_EXPECTED(
- SemanticSignatureElement::fromMetadata(nullptr),
- FailedWithMessage("signature element node is null"));
+ EXPECT_THAT_EXPECTED(SemanticSignatureElement::fromMetadata(nullptr),
+ FailedWithMessage("signature element node is null"));
}
// A node with the wrong number of operands is rejected
@@ -268,7 +267,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidCompType) {
}
// A semantic kind outside dxbc::PSV::SemanticKind is rejected
-TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSemanticKind) {
+TEST_F(HLSLSemanticSignatureMetadataTest,
+ MetadataToElementInvalidSemanticKind) {
MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
/*SemanticKind=*/100, /*Indices=*/{0},
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1,
@@ -316,7 +316,8 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidStartCol) {
}
// The row/col sentinels must be set together
-TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementInvalidSentinelPair) {
+TEST_F(HLSLSemanticSignatureMetadataTest,
+ MetadataToElementInvalidSentinelPair) {
MDNode *RowOnly = getElement(
/*SigId=*/0, "A", /*CompType=*/9, /*SemanticKind=*/0, /*Indices=*/{0},
/*InterpMode=*/0, /*Rows=*/1, /*Cols=*/1, /*StartRow=*/UnallocatedRow,
>From e18bd05581f3f07c96521ffcd87fb3125fc3d3cd Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 15 Jul 2026 21:53:21 +0000
Subject: [PATCH 10/12] review: remove unused includes
---
llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 1 -
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 1 -
2 files changed, 2 deletions(-)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 7d5efc663e02a..639ba3cd66b32 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -21,7 +21,6 @@
#include "llvm/Support/DXILABI.h"
#include "llvm/Support/Error.h"
#include <cstdint>
-#include <string>
namespace llvm {
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 860fa7905fce3..71e018dba5d38 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -15,7 +15,6 @@
#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;
>From d4f24d14fe769c06bee0083972f7557ec7d1b042 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 22 Jul 2026 17:55:37 +0000
Subject: [PATCH 11/12] review: correct minprecision and add opindex helper
---
.../llvm/Frontend/HLSL/SemanticSignatures.h | 2 -
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 58 ++++++++++++++-----
2 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 639ba3cd66b32..ab3f87f1ff579 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -76,8 +76,6 @@ struct SemanticSignatureElement {
case dxil::ElementType::F16:
return dxbc::SigMinPrecision::Float16;
case dxil::ElementType::I16:
- case dxil::ElementType::SNormF16:
- case dxil::ElementType::UNormF16:
return dxbc::SigMinPrecision::SInt16;
case dxil::ElementType::U16:
return dxbc::SigMinPrecision::UInt16;
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 71e018dba5d38..778f654524a63 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Frontend/HLSL/SemanticSignatures.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Type.h"
@@ -20,8 +21,6 @@ using namespace llvm;
using namespace llvm::hlsl;
namespace {
-// The fixed number of operands in a signature element node
-constexpr unsigned NumElementOperands = 13;
// Inclusive upper bounds of the operand enums
constexpr uint32_t MaxCompType =
@@ -45,6 +44,25 @@ Expected<uint64_t> extractInt(const MDNode *Node, unsigned OpId) {
Expected<SemanticSignatureElement>
SemanticSignatureElement::fromMetadata(const MDNode *Node) {
+ // Operand positions within a signature element metadata node.
+ enum class OpIdx : unsigned {
+ SigId,
+ SemanticName,
+ CompType,
+ SemanticKind,
+ SemanticIndices,
+ InterpMode,
+ Rows,
+ Cols,
+ StartRow,
+ StartCol,
+ UsageMask,
+ DynIndexMask,
+ GSStream,
+ NumOperands,
+ };
+ const unsigned NumElementOperands = to_underlying(OpIdx::NumOperands);
+
if (!Node)
return makeError("signature element node is null");
if (Node->getNumOperands() != NumElementOperands)
@@ -52,31 +70,35 @@ SemanticSignatureElement::fromMetadata(const MDNode *Node) {
SemanticSignatureElement Elem;
- Expected<uint64_t> SigId = extractInt(Node, 0);
+ Expected<uint64_t> SigId = extractInt(Node, to_underlying(OpIdx::SigId));
if (!SigId)
return SigId.takeError();
Elem.SigId = *SigId;
- auto *Name = dyn_cast<MDString>(Node->getOperand(1));
+ auto *Name =
+ dyn_cast<MDString>(Node->getOperand(to_underlying(OpIdx::SemanticName)));
if (!Name)
return makeError("expected semantic name string");
Elem.SemanticName = Name->getString();
- Expected<uint64_t> CompType = extractInt(Node, 2);
+ Expected<uint64_t> CompType =
+ extractInt(Node, to_underlying(OpIdx::CompType));
if (!CompType)
return CompType.takeError();
if (*CompType > MaxCompType)
return makeError("invalid component type");
Elem.CompType = static_cast<dxil::ElementType>(*CompType);
- Expected<uint64_t> SemanticKind = extractInt(Node, 3);
+ Expected<uint64_t> SemanticKind =
+ extractInt(Node, to_underlying(OpIdx::SemanticKind));
if (!SemanticKind)
return SemanticKind.takeError();
if (*SemanticKind > MaxSemanticKind)
return makeError("invalid semantic kind");
Elem.SemanticKind = static_cast<dxbc::PSV::SemanticKind>(*SemanticKind);
- auto *Indices = dyn_cast<MDNode>(Node->getOperand(4));
+ auto *Indices =
+ dyn_cast<MDNode>(Node->getOperand(to_underlying(OpIdx::SemanticIndices)));
if (!Indices)
return makeError("expected semantic indices node");
for (unsigned I = 0, E = Indices->getNumOperands(); I != E; ++I) {
@@ -86,31 +108,34 @@ SemanticSignatureElement::fromMetadata(const MDNode *Node) {
Elem.SemanticIndices.push_back(*Index);
}
- Expected<uint64_t> InterpMode = extractInt(Node, 5);
+ Expected<uint64_t> InterpMode =
+ extractInt(Node, to_underlying(OpIdx::InterpMode));
if (!InterpMode)
return InterpMode.takeError();
if (*InterpMode > MaxInterpMode)
return makeError("invalid interpolation mode");
Elem.InterpMode = static_cast<dxbc::PSV::InterpolationMode>(*InterpMode);
- Expected<uint64_t> Rows = extractInt(Node, 6);
+ Expected<uint64_t> Rows = extractInt(Node, to_underlying(OpIdx::Rows));
if (!Rows)
return Rows.takeError();
Elem.Rows = *Rows;
- Expected<uint64_t> Cols = extractInt(Node, 7);
+ Expected<uint64_t> Cols = extractInt(Node, to_underlying(OpIdx::Cols));
if (!Cols)
return Cols.takeError();
if (*Cols < 1 || *Cols > 4)
return makeError("number of components per row must be within 1-4");
Elem.Cols = *Cols;
- Expected<uint64_t> StartRow = extractInt(Node, 8);
+ Expected<uint64_t> StartRow =
+ extractInt(Node, to_underlying(OpIdx::StartRow));
if (!StartRow)
return StartRow.takeError();
Elem.StartRow = *StartRow;
- Expected<uint64_t> StartCol = extractInt(Node, 9);
+ Expected<uint64_t> StartCol =
+ extractInt(Node, to_underlying(OpIdx::StartCol));
if (!StartCol)
return StartCol.takeError();
if (*StartCol > 3 && *StartCol != UnallocatedCol)
@@ -121,21 +146,24 @@ SemanticSignatureElement::fromMetadata(const MDNode *Node) {
if ((Elem.StartRow == UnallocatedRow) != (Elem.StartCol == UnallocatedCol))
return makeError("start row and column sentinels must be set together");
- Expected<uint64_t> UsageMask = extractInt(Node, 10);
+ Expected<uint64_t> UsageMask =
+ extractInt(Node, to_underlying(OpIdx::UsageMask));
if (!UsageMask)
return UsageMask.takeError();
if (*UsageMask > 0xF)
return makeError("usage mask must be a 4-bit value");
Elem.UsageMask = *UsageMask;
- Expected<uint64_t> DynIndexMask = extractInt(Node, 11);
+ Expected<uint64_t> DynIndexMask =
+ extractInt(Node, to_underlying(OpIdx::DynIndexMask));
if (!DynIndexMask)
return DynIndexMask.takeError();
if (*DynIndexMask > 0xF)
return makeError("dynamic index mask must be a 4-bit value");
Elem.DynIndexMask = *DynIndexMask;
- Expected<uint64_t> GSStream = extractInt(Node, 12);
+ Expected<uint64_t> GSStream =
+ extractInt(Node, to_underlying(OpIdx::GSStream));
if (!GSStream)
return GSStream.takeError();
if (*GSStream > 3)
>From 5692455af6d48b18efdbf293eb46746df0d25b2c Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 22 Jul 2026 17:58:59 +0000
Subject: [PATCH 12/12] review: update mandatory arguments to not have a
default value
---
llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index ab3f87f1ff579..c5be2516a7364 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -40,13 +40,13 @@ static constexpr uint8_t UnallocatedCol = 0xFF;
struct SemanticSignatureElement {
uint32_t SigId;
StringRef SemanticName;
- dxil::ElementType CompType = dxil::ElementType::Invalid;
- dxbc::PSV::SemanticKind SemanticKind = dxbc::PSV::SemanticKind::Arbitrary;
+ dxil::ElementType CompType;
+ dxbc::PSV::SemanticKind SemanticKind;
SmallVector<uint32_t> SemanticIndices;
dxbc::PSV::InterpolationMode InterpMode =
dxbc::PSV::InterpolationMode::Undefined;
- uint32_t Rows = 1;
- uint8_t Cols = 1;
+ uint32_t Rows;
+ uint8_t Cols;
uint32_t StartRow = UnallocatedRow;
uint8_t StartCol = UnallocatedCol;
uint8_t UsageMask = 0;
More information about the llvm-commits
mailing list