[llvm] [DirectX] Updating DXContainer logic to read version 1.2 of static samplers (PR #160184)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 26 09:07:35 PDT 2025


https://github.com/joaosaffran updated https://github.com/llvm/llvm-project/pull/160184

>From 787c77638092b06e7648f03660a4429dc602aac6 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Thu, 18 Sep 2025 14:16:25 -0700
Subject: [PATCH 01/15] adding yaml representation and updating write logic

---
 llvm/include/llvm/BinaryFormat/DXContainer.h  | 24 ++++++++
 .../BinaryFormat/DXContainerConstants.def     | 10 +++
 .../llvm/MC/DXContainerRootSignature.h        |  1 +
 .../include/llvm/ObjectYAML/DXContainerYAML.h |  5 ++
 llvm/lib/BinaryFormat/DXContainer.cpp         |  9 +++
 .../HLSL/RootSignatureValidations.cpp         |  4 +-
 llvm/lib/MC/DXContainerRootSignature.cpp      |  7 ++-
 llvm/lib/ObjectYAML/DXContainerEmitter.cpp    |  3 +
 llvm/lib/ObjectYAML/DXContainerYAML.cpp       | 12 ++++
 .../ObjectYAML/DXContainerYAMLTest.cpp        | 61 +++++++++++++++++++
 10 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index c04380667a640..a08cfff4b4974 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -185,6 +185,15 @@ enum class DescriptorRangeFlags : uint32_t {
 
 LLVM_ABI ArrayRef<EnumEntry<DescriptorRangeFlags>> getDescriptorRangeFlags();
 
+#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) Enum = Num,
+enum class StaticSamplerFlags : uint32_t {
+#include "DXContainerConstants.def"
+
+  LLVM_MARK_AS_BITMASK_ENUM(NonNormalizedCoordinates)
+};
+
+LLVM_ABI ArrayRef<EnumEntry<StaticSamplerFlags>> getStaticSamplerFlags();
+
 #define ROOT_PARAMETER(Val, Enum) Enum = Val,
 enum class RootParameterType : uint32_t {
 #include "DXContainerConstants.def"
@@ -813,6 +822,21 @@ struct DescriptorRange {
   }
 };
 } // namespace v2
+namespace v3 {
+struct StaticSampler : public v1::StaticSampler {
+  uint32_t Flags;
+
+  StaticSampler() = default;
+  explicit StaticSampler(v1::StaticSampler &Base)
+      : v1::StaticSampler(Base), Flags(0U) {}
+
+  void swapBytes() {
+    v1::StaticSampler::swapBytes();
+    sys::swapByteOrder(Flags);
+  }
+};
+
+} // namespace v3
 } // namespace RTS0
 
 // D3D_ROOT_SIGNATURE_VERSION
diff --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
index 889653611d79a..f576d958037cd 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
+++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
@@ -104,6 +104,16 @@ DESCRIPTOR_RANGE_FLAG(0x10000, DescriptorsStaticKeepingBufferBoundsChecks, DESCR
 #undef DESCRIPTOR_RANGE_FLAG
 #endif // DESCRIPTOR_RANGE_FLAG
 
+// STATIC_SAMPLER_FLAG(flag value, name, flag).
+#ifdef STATIC_SAMPLER_FLAG
+
+STATIC_SAMPLER_FLAG(0x0, None, SAMPLER_FLAG_NONE)
+STATIC_SAMPLER_FLAG(0x1, UintBorderColor, SAMPLER_FLAG_UINT_BORDER_COLOR)
+STATIC_SAMPLER_FLAG(0x2, NonNormalizedCoordinates, SAMPLER_FLAG_NON_NORMALIZED_COORDINATES)
+
+#undef STATIC_SAMPLER_FLAG
+#endif // STATIC_SAMPLER_FLAG
+
 #ifdef ROOT_PARAMETER
 
 ROOT_PARAMETER(0, DescriptorTable)
diff --git a/llvm/include/llvm/MC/DXContainerRootSignature.h b/llvm/include/llvm/MC/DXContainerRootSignature.h
index 54677ef70244f..2a76e81fefc5f 100644
--- a/llvm/include/llvm/MC/DXContainerRootSignature.h
+++ b/llvm/include/llvm/MC/DXContainerRootSignature.h
@@ -74,6 +74,7 @@ struct StaticSampler {
   uint32_t ShaderRegister;
   uint32_t RegisterSpace;
   dxbc::ShaderVisibility ShaderVisibility;
+  uint32_t Flags;
 };
 
 struct RootParametersContainer {
diff --git a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h
index 62bfee7693db1..b5b110d0f59a1 100644
--- a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h
+++ b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h
@@ -178,6 +178,11 @@ struct StaticSamplerYamlDesc {
   uint32_t ShaderRegister;
   uint32_t RegisterSpace;
   dxbc::ShaderVisibility ShaderVisibility;
+
+  LLVM_ABI uint32_t getEncodedFlags() const;
+
+#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) bool Enum = false;
+#include "llvm/BinaryFormat/DXContainerConstants.def"
 };
 
 struct RootSignatureYamlDesc {
diff --git a/llvm/lib/BinaryFormat/DXContainer.cpp b/llvm/lib/BinaryFormat/DXContainer.cpp
index 36d10d0b63078..c06a3e34653f0 100644
--- a/llvm/lib/BinaryFormat/DXContainer.cpp
+++ b/llvm/lib/BinaryFormat/DXContainer.cpp
@@ -89,6 +89,15 @@ ArrayRef<EnumEntry<DescriptorRangeFlags>> dxbc::getDescriptorRangeFlags() {
   return ArrayRef(DescriptorRangeFlagNames);
 }
 
+static const EnumEntry<StaticSamplerFlags> StaticSamplerFlagNames[] = {
+#define STATIC_SAMPLER_FLAG(Val, Enum, Flag) {#Enum, StaticSamplerFlags::Enum},
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+};
+
+ArrayRef<EnumEntry<StaticSamplerFlags>> dxbc::getStaticSamplerFlags() {
+  return ArrayRef(StaticSamplerFlagNames);
+}
+
 #define SHADER_VISIBILITY(Val, Enum) {#Enum, ShaderVisibility::Enum},
 
 static const EnumEntry<ShaderVisibility> ShaderVisibilityValues[] = {
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
index 0970977b5064f..8c298f0685286 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
@@ -20,7 +20,9 @@ namespace rootsig {
 
 bool verifyRootFlag(uint32_t Flags) { return (Flags & ~0xfff) == 0; }
 
-bool verifyVersion(uint32_t Version) { return (Version == 1 || Version == 2); }
+bool verifyVersion(uint32_t Version) {
+  return (Version == 1 || Version == 2 || Version == 3);
+}
 
 bool verifyRegisterValue(uint32_t RegisterValue) {
   return RegisterValue != ~0U;
diff --git a/llvm/lib/MC/DXContainerRootSignature.cpp b/llvm/lib/MC/DXContainerRootSignature.cpp
index b9ebb7a9e789c..13784e7c86684 100644
--- a/llvm/lib/MC/DXContainerRootSignature.cpp
+++ b/llvm/lib/MC/DXContainerRootSignature.cpp
@@ -33,7 +33,9 @@ static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream,
 size_t RootSignatureDesc::getSize() const {
   uint32_t StaticSamplersOffset = computeStaticSamplersOffset();
   size_t StaticSamplersSize =
-      StaticSamplers.size() * sizeof(dxbc::RTS0::v1::StaticSampler);
+      (Version > 2 ? sizeof(dxbc::RTS0::v3::StaticSampler)
+                   : sizeof(dxbc::RTS0::v1::StaticSampler)) *
+      StaticSamplers.size();
 
   return size_t(StaticSamplersOffset) + StaticSamplersSize;
 }
@@ -171,6 +173,9 @@ void RootSignatureDesc::write(raw_ostream &OS) const {
     support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little);
     support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little);
     support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little);
+
+    if (Version > 2)
+      support::endian::write(BOS, S.Flags, llvm::endianness::little);
   }
   assert(Storage.size() == getSize());
   OS.write(Storage.data(), Storage.size());
diff --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
index 910383816f43b..b00e45d912be1 100644
--- a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
@@ -343,6 +343,9 @@ Error DXContainerWriter::writeParts(raw_ostream &OS) {
         NewSampler.RegisterSpace = Param.RegisterSpace;
         NewSampler.ShaderVisibility = Param.ShaderVisibility;
 
+        if (RS.Version > 2)
+          NewSampler.Flags = Param.getEncodedFlags();
+
         RS.StaticSamplers.push_back(NewSampler);
       }
 
diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 22674b1ceb734..39f42fb4dc839 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -245,6 +245,15 @@ uint32_t DXContainerYAML::DescriptorRangeYaml::getEncodedFlags() const {
   return Flags;
 }
 
+uint32_t DXContainerYAML::StaticSamplerYamlDesc::getEncodedFlags() const {
+  uint64_t Flags = 0;
+#define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
+  if (Enum)                                                                    \
+    Flags |= (uint32_t)dxbc::StaticSamplerFlags::Enum;
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+  return Flags;
+}
+
 uint64_t DXContainerYAML::ShaderFeatureFlags::getEncodedFlags() {
   uint64_t Flag = 0;
 #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str)                      \
@@ -512,6 +521,9 @@ void MappingTraits<llvm::DXContainerYAML::StaticSamplerYamlDesc>::mapping(
   IO.mapRequired("ShaderRegister", S.ShaderRegister);
   IO.mapRequired("RegisterSpace", S.RegisterSpace);
   IO.mapRequired("ShaderVisibility", S.ShaderVisibility);
+
+#define STATIC_SAMPLER_FLAG_FLAG(Num, Val) IO.mapOptional(#Val, S.Val, false);
+#include "llvm/BinaryFormat/DXContainerConstants.def"
 }
 
 void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
diff --git a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
index b0ad208625436..eee0b64e4b866 100644
--- a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
@@ -526,3 +526,64 @@ TEST(RootSignature, ParseStaticSamplers) {
   EXPECT_EQ(Storage.size(), 144u);
   EXPECT_TRUE(memcmp(Buffer, Storage.data(), 144u) == 0);
 }
+
+TEST(RootSignature, ParseStaticSamplersV13) {
+  SmallString<128> Storage;
+
+  // First read a fully explicit yaml with all sizes and offsets provided
+  ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  PartCount:       1
+  PartOffsets:     [ 60 ]
+Parts:
+  - Name:            RTS0
+    Size:            76
+    RootSignature:
+      Version: 3
+      NumRootParameters: 0
+      RootParametersOffset: 24
+      NumStaticSamplers: 1
+      StaticSamplersOffset: 24
+      Parameters: []
+      Samplers: 
+        - Filter: MinLinearMagMipPoint 
+          AddressU: Wrap
+          AddressV: Mirror
+          AddressW: MirrorOnce
+          MipLODBias: 1.23
+          MaxAnisotropy: 20
+          ComparisonFunc: LessEqual
+          BorderColor: TransparentBlack
+          MinLOD: 4.56
+          MaxLOD: 8.90
+          ShaderRegister: 31 
+          RegisterSpace: 32
+          ShaderVisibility:  Mesh
+          SAMPLER_FLAG_UINT_BORDER_COLOR: true
+      AllowInputAssemblerInputLayout: true
+      DenyGeometryShaderRootAccess: true
+    )"));
+
+  uint8_t Buffer[] = {
+      0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+      0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
+      0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x01};
+
+  EXPECT_EQ(Storage.size(), 148U);
+  EXPECT_TRUE(memcmp(Buffer, Storage.data(), 148U) == 0);
+}

>From 57fd710107c459b53e2f9fe2c3f0de3f24d6b064 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Thu, 18 Sep 2025 16:54:27 -0700
Subject: [PATCH 02/15] fix test

---
 llvm/lib/ObjectYAML/DXContainerYAML.cpp           | 4 ++--
 llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 39f42fb4dc839..42074731c4e16 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -521,8 +521,8 @@ void MappingTraits<llvm::DXContainerYAML::StaticSamplerYamlDesc>::mapping(
   IO.mapRequired("ShaderRegister", S.ShaderRegister);
   IO.mapRequired("RegisterSpace", S.RegisterSpace);
   IO.mapRequired("ShaderVisibility", S.ShaderVisibility);
-
-#define STATIC_SAMPLER_FLAG_FLAG(Num, Val) IO.mapOptional(#Val, S.Val, false);
+#define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
+  IO.mapOptional(#Flag, S.Enum, false);
 #include "llvm/BinaryFormat/DXContainerConstants.def"
 }
 
diff --git a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
index eee0b64e4b866..db9861f0149a4 100644
--- a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
@@ -528,7 +528,7 @@ TEST(RootSignature, ParseStaticSamplers) {
 }
 
 TEST(RootSignature, ParseStaticSamplersV13) {
-  SmallString<128> Storage;
+  SmallString<160> Storage;
 
   // First read a fully explicit yaml with all sizes and offsets provided
   ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
@@ -575,14 +575,14 @@ TEST(RootSignature, ParseStaticSamplersV13) {
       0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-      0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+      0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
       0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
       0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
       0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
       0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
-      0x01};
+      0x01, 0x00, 0x00, 0x00};
 
   EXPECT_EQ(Storage.size(), 148U);
   EXPECT_TRUE(memcmp(Buffer, Storage.data(), 148U) == 0);

>From d72adfe11a56a57e970f28b7ff0725c316ec8900 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Fri, 19 Sep 2025 10:46:53 -0700
Subject: [PATCH 03/15] adding missing test

---
 .../RootSignature-Invalid-Version.ll          | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Invalid-Version.ll

diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Invalid-Version.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Invalid-Version.ll
new file mode 100644
index 0000000000000..26867e6d7ec25
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Invalid-Version.ll
@@ -0,0 +1,20 @@
+; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
+
+target triple = "dxil-unknown-shadermodel6.0-compute"
+
+
+; CHECK: error: Invalid value for Version: 4
+; CHECK-NOT: Root Signature Definitions
+define void @main() #0 {
+entry:
+  ret void
+}
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+
+
+!dx.rootsignatures = !{!2, !3, !4, !5} ; list of function/root signature pairs
+!2 = !{ ptr @main, !6, i32 1 } ; function, root signature
+!3 = !{ ptr @main, !6, i32 4 } ; function, root signature
+!4 = !{ ptr @main, !6, i32 2 } ; function, root signature
+!5 = !{ ptr @main, !6, i32 3 } ; function, root signature
+!6 = !{ } ; list of root signature elements

>From fefd58c2ab1044ac51c546b6bc6df968eb5edaa8 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Fri, 19 Sep 2025 12:48:11 -0700
Subject: [PATCH 04/15] fix test

---
 llvm/include/llvm/Object/DXContainer.h    | 57 ++++++++++++++++-------
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   | 16 ++++++-
 llvm/unittests/Object/DXContainerTest.cpp | 16 ++++---
 3 files changed, 63 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index 9bc1918852335..e3e532f6635a4 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -123,25 +123,26 @@ template <typename T> struct ViewArray {
 };
 
 namespace DirectX {
+
+template <typename T> Expected<T> readParameter(StringRef Data) {
+  T Struct;
+  if (sizeof(T) != Data.size())
+    return make_error<GenericBinaryError>(
+        "Reading structure out of file bounds", object_error::parse_failed);
+
+  memcpy(&Struct, Data.data(), sizeof(T));
+  // DXContainer is always little endian
+  if (sys::IsBigEndianHost)
+    Struct.swapBytes();
+  return Struct;
+}
+
 struct RootParameterView {
   const dxbc::RTS0::v1::RootParameterHeader &Header;
   StringRef ParamData;
 
   RootParameterView(const dxbc::RTS0::v1::RootParameterHeader &H, StringRef P)
       : Header(H), ParamData(P) {}
-
-  template <typename T> Expected<T> readParameter() {
-    T Struct;
-    if (sizeof(T) != ParamData.size())
-      return make_error<GenericBinaryError>(
-          "Reading structure out of file bounds", object_error::parse_failed);
-
-    memcpy(&Struct, ParamData.data(), sizeof(T));
-    // DXContainer is always little endian
-    if (sys::IsBigEndianHost)
-      Struct.swapBytes();
-    return Struct;
-  }
 };
 
 struct RootConstantView : RootParameterView {
@@ -151,7 +152,7 @@ struct RootConstantView : RootParameterView {
   }
 
   llvm::Expected<dxbc::RTS0::v1::RootConstants> read() {
-    return readParameter<dxbc::RTS0::v1::RootConstants>();
+    return readParameter<dxbc::RTS0::v1::RootConstants>(ParamData);
   }
 };
 
@@ -167,7 +168,8 @@ struct RootDescriptorView : RootParameterView {
 
   llvm::Expected<dxbc::RTS0::v2::RootDescriptor> read(uint32_t Version) {
     if (Version == 1) {
-      auto Descriptor = readParameter<dxbc::RTS0::v1::RootDescriptor>();
+      auto Descriptor =
+          readParameter<dxbc::RTS0::v1::RootDescriptor>(ParamData);
       if (Error E = Descriptor.takeError())
         return E;
       return dxbc::RTS0::v2::RootDescriptor(*Descriptor);
@@ -176,9 +178,10 @@ struct RootDescriptorView : RootParameterView {
       return make_error<GenericBinaryError>("Invalid Root Signature version: " +
                                                 Twine(Version),
                                             object_error::parse_failed);
-    return readParameter<dxbc::RTS0::v2::RootDescriptor>();
+    return readParameter<dxbc::RTS0::v2::RootDescriptor>(ParamData);
   }
 };
+
 template <typename T> struct DescriptorTable {
   uint32_t NumRanges;
   uint32_t RangesOffset;
@@ -247,8 +250,26 @@ class RootSignature {
   llvm::iterator_range<param_header_iterator> param_headers() const {
     return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
   }
-  llvm::iterator_range<samplers_iterator> samplers() const {
-    return llvm::make_range(StaticSamplers.begin(), StaticSamplers.end());
+  llvm::Expected<dxbc::RTS0::v3::StaticSampler> getSampler(uint32_t Loc) const {
+    if (Loc >= getNumStaticSamplers())
+      return parseFailed("Static sampler index out of range");
+
+    auto SamplerSize = (Version <= 2) ? sizeof(dxbc::RTS0::v1::StaticSampler)
+                                     : sizeof(dxbc::RTS0::v3::StaticSampler);
+
+    StringRef Buff = PartData.substr(StaticSamplersOffset + (Loc * SamplerSize),
+                                     SamplerSize);
+    if (Version < 3) {
+      auto Sampler = readParameter<dxbc::RTS0::v1::StaticSampler>(Buff);
+      if (Error E = Sampler.takeError())
+        return E;
+      return dxbc::RTS0::v3::StaticSampler(*Sampler);
+    }
+    if (Version != 3)
+      return make_error<GenericBinaryError>("Invalid Root Signature version: " +
+                                                Twine(Version),
+                                            object_error::parse_failed);
+    return readParameter<dxbc::RTS0::v3::StaticSampler>(Buff);
   }
   uint32_t getFlags() const { return Flags; }
 
diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 42074731c4e16..6f24b7d2573ec 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -163,7 +163,13 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     }
   }
 
-  for (const auto &S : Data.samplers()) {
+  for (uint32_t Loc = 0; Loc < Data.getNumStaticSamplers(); ++Loc) {
+    llvm::Expected<dxbc::RTS0::v3::StaticSampler> MaybeSampler =
+        Data.getSampler(Loc);
+    if (Error E = MaybeSampler.takeError())
+      return std::move(E);
+    const llvm::dxbc::RTS0::v3::StaticSampler &S = *MaybeSampler;
+
     if (!dxbc::isValidSamplerFilter(S.Filter))
       return createStringError(std::errc::invalid_argument,
                                "Invalid value for static sampler filter");
@@ -209,6 +215,14 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     NewS.RegisterSpace = S.RegisterSpace;
     NewS.ShaderVisibility = dxbc::ShaderVisibility(S.ShaderVisibility);
 
+    if (Version > 2) {
+      if (Version > 1) {
+#define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
+  NewS.Enum =                                                                  \
+      (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum)) > 0;
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+      }
+    }
     RootSigDesc.StaticSamplers.push_back(NewS);
   }
 
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index 396d060a75bfd..f2a7bdfdcd75a 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1165,11 +1165,11 @@ TEST(RootSignature, ParseStaticSamplers) {
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-        0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-        0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
+        0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
+        0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x7f,
         0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00};
     DXContainer C =
         llvm::cantFail(DXContainer::create(getMemoryBuffer<133>(Buffer)));
@@ -1179,12 +1179,14 @@ TEST(RootSignature, ParseStaticSamplers) {
     const auto &RS = MaybeRS.value();
     ASSERT_EQ(RS.getVersion(), 2u);
     ASSERT_EQ(RS.getNumParameters(), 0u);
-    ASSERT_EQ(RS.getRootParametersOffset(), 0u);
+    ASSERT_EQ(RS.getRootParametersOffset(), 24u);
     ASSERT_EQ(RS.getNumStaticSamplers(), 1u);
     ASSERT_EQ(RS.getStaticSamplersOffset(), 24u);
     ASSERT_EQ(RS.getFlags(), 17u);
 
-    auto Sampler = *RS.samplers().begin();
+    auto MaybeSamplerView = RS.getSampler(0);
+    ASSERT_THAT_ERROR(MaybeSamplerView.takeError(), Succeeded());
+    const auto &Sampler = *MaybeSamplerView;
 
     ASSERT_EQ(Sampler.Filter, 10u);
     ASSERT_EQ(Sampler.AddressU, 1u);

>From 1d0cbd39875a84c983106678c8b857d8157bfa51 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 22 Sep 2025 10:28:12 -0700
Subject: [PATCH 05/15] adding samplers_iterator

---
 llvm/include/llvm/Object/DXContainer.h    | 70 +++++++++++++++++------
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   |  5 +-
 llvm/unittests/Object/DXContainerTest.cpp |  2 +-
 3 files changed, 56 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index e3e532f6635a4..e3913ece842bc 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -223,6 +223,28 @@ static Error parseFailed(const Twine &Msg) {
 
 class RootSignature {
 private:
+  struct samplers_iterator {
+    const RootSignature *Parent = nullptr;
+    uint32_t Index = 0;
+
+    llvm::Expected<dxbc::RTS0::v3::StaticSampler> operator*() const {
+      return Parent->getSampler(Index);
+    }
+
+    samplers_iterator &operator++() {
+      ++Index;
+      return *this;
+    }
+
+    bool operator==(const samplers_iterator &Other) const {
+      return Parent == Other.Parent && Index == Other.Index;
+    }
+
+    bool operator!=(const samplers_iterator &Other) const {
+      return !(*this == Other);
+    }
+  };
+
   uint32_t Version;
   uint32_t NumParameters;
   uint32_t RootParametersOffset;
@@ -233,23 +255,6 @@ class RootSignature {
   StringRef PartData;
   ViewArray<dxbc::RTS0::v1::StaticSampler> StaticSamplers;
 
-  using param_header_iterator =
-      ViewArray<dxbc::RTS0::v1::RootParameterHeader>::iterator;
-  using samplers_iterator = ViewArray<dxbc::RTS0::v1::StaticSampler>::iterator;
-
-public:
-  RootSignature(StringRef PD) : PartData(PD) {}
-
-  LLVM_ABI Error parse();
-  uint32_t getVersion() const { return Version; }
-  uint32_t getNumParameters() const { return NumParameters; }
-  uint32_t getRootParametersOffset() const { return RootParametersOffset; }
-  uint32_t getNumStaticSamplers() const { return NumStaticSamplers; }
-  uint32_t getStaticSamplersOffset() const { return StaticSamplersOffset; }
-  uint32_t getNumRootParameters() const { return ParametersHeaders.size(); }
-  llvm::iterator_range<param_header_iterator> param_headers() const {
-    return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
-  }
   llvm::Expected<dxbc::RTS0::v3::StaticSampler> getSampler(uint32_t Loc) const {
     if (Loc >= getNumStaticSamplers())
       return parseFailed("Static sampler index out of range");
@@ -271,6 +276,37 @@ class RootSignature {
                                             object_error::parse_failed);
     return readParameter<dxbc::RTS0::v3::StaticSampler>(Buff);
   }
+
+  using param_header_iterator =
+      ViewArray<dxbc::RTS0::v1::RootParameterHeader>::iterator;
+
+public:
+  RootSignature(StringRef PD) : PartData(PD) {}
+
+  LLVM_ABI Error parse();
+  uint32_t getVersion() const { return Version; }
+  uint32_t getNumParameters() const { return NumParameters; }
+  uint32_t getRootParametersOffset() const { return RootParametersOffset; }
+  uint32_t getNumStaticSamplers() const { return NumStaticSamplers; }
+  uint32_t getStaticSamplersOffset() const { return StaticSamplersOffset; }
+  uint32_t getNumRootParameters() const { return ParametersHeaders.size(); }
+
+  samplers_iterator samplers_begin() const {
+    return samplers_iterator{this, 0};
+  }
+
+  samplers_iterator samplers_end() const {
+    return samplers_iterator{this, getNumStaticSamplers()};
+  }
+
+  llvm::iterator_range<samplers_iterator> samplers() const {
+    return llvm::make_range(samplers_begin(), samplers_end());
+  }
+
+  llvm::iterator_range<param_header_iterator> param_headers() const {
+    return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
+  }
+
   uint32_t getFlags() const { return Flags; }
 
   llvm::Expected<RootParameterView>
diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 6f24b7d2573ec..91f86caaa4005 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -163,9 +163,8 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     }
   }
 
-  for (uint32_t Loc = 0; Loc < Data.getNumStaticSamplers(); ++Loc) {
-    llvm::Expected<dxbc::RTS0::v3::StaticSampler> MaybeSampler =
-        Data.getSampler(Loc);
+  for (llvm::Expected<dxbc::RTS0::v3::StaticSampler> MaybeSampler :
+       Data.samplers()) {
     if (Error E = MaybeSampler.takeError())
       return std::move(E);
     const llvm::dxbc::RTS0::v3::StaticSampler &S = *MaybeSampler;
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index 923df70f44194..fe898c430b8a3 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1184,7 +1184,7 @@ TEST(RootSignature, ParseStaticSamplers) {
     ASSERT_EQ(RS.getStaticSamplersOffset(), 24u);
     ASSERT_EQ(RS.getFlags(), 17u);
 
-    auto MaybeSamplerView = RS.getSampler(0);
+    auto MaybeSamplerView = *RS.samplers().begin();
     ASSERT_THAT_ERROR(MaybeSamplerView.takeError(), Succeeded());
     const auto &Sampler = *MaybeSamplerView;
 

>From e530bcc1b81b300a12ada139c54553b84ab89a03 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 22 Sep 2025 11:29:55 -0700
Subject: [PATCH 06/15] this was easier than I thought

---
 llvm/include/llvm/Object/DXContainer.h    | 62 ++---------------------
 llvm/lib/Object/DXContainer.cpp           | 13 +++--
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   |  6 +--
 llvm/unittests/Object/DXContainerTest.cpp | 49 ++++++++++++++++--
 4 files changed, 61 insertions(+), 69 deletions(-)

diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index e3913ece842bc..0bfc5cec48da4 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -223,28 +223,6 @@ static Error parseFailed(const Twine &Msg) {
 
 class RootSignature {
 private:
-  struct samplers_iterator {
-    const RootSignature *Parent = nullptr;
-    uint32_t Index = 0;
-
-    llvm::Expected<dxbc::RTS0::v3::StaticSampler> operator*() const {
-      return Parent->getSampler(Index);
-    }
-
-    samplers_iterator &operator++() {
-      ++Index;
-      return *this;
-    }
-
-    bool operator==(const samplers_iterator &Other) const {
-      return Parent == Other.Parent && Index == Other.Index;
-    }
-
-    bool operator!=(const samplers_iterator &Other) const {
-      return !(*this == Other);
-    }
-  };
-
   uint32_t Version;
   uint32_t NumParameters;
   uint32_t RootParametersOffset;
@@ -253,32 +231,11 @@ class RootSignature {
   uint32_t Flags;
   ViewArray<dxbc::RTS0::v1::RootParameterHeader> ParametersHeaders;
   StringRef PartData;
-  ViewArray<dxbc::RTS0::v1::StaticSampler> StaticSamplers;
-
-  llvm::Expected<dxbc::RTS0::v3::StaticSampler> getSampler(uint32_t Loc) const {
-    if (Loc >= getNumStaticSamplers())
-      return parseFailed("Static sampler index out of range");
-
-    auto SamplerSize = (Version <= 2) ? sizeof(dxbc::RTS0::v1::StaticSampler)
-                                     : sizeof(dxbc::RTS0::v3::StaticSampler);
-
-    StringRef Buff = PartData.substr(StaticSamplersOffset + (Loc * SamplerSize),
-                                     SamplerSize);
-    if (Version < 3) {
-      auto Sampler = readParameter<dxbc::RTS0::v1::StaticSampler>(Buff);
-      if (Error E = Sampler.takeError())
-        return E;
-      return dxbc::RTS0::v3::StaticSampler(*Sampler);
-    }
-    if (Version != 3)
-      return make_error<GenericBinaryError>("Invalid Root Signature version: " +
-                                                Twine(Version),
-                                            object_error::parse_failed);
-    return readParameter<dxbc::RTS0::v3::StaticSampler>(Buff);
-  }
+  ViewArray<dxbc::RTS0::v3::StaticSampler> StaticSamplers;
 
   using param_header_iterator =
       ViewArray<dxbc::RTS0::v1::RootParameterHeader>::iterator;
+  using samplers_iterator = ViewArray<dxbc::RTS0::v3::StaticSampler>::iterator;
 
 public:
   RootSignature(StringRef PD) : PartData(PD) {}
@@ -290,21 +247,12 @@ class RootSignature {
   uint32_t getNumStaticSamplers() const { return NumStaticSamplers; }
   uint32_t getStaticSamplersOffset() const { return StaticSamplersOffset; }
   uint32_t getNumRootParameters() const { return ParametersHeaders.size(); }
-
-  samplers_iterator samplers_begin() const {
-    return samplers_iterator{this, 0};
-  }
-
-  samplers_iterator samplers_end() const {
-    return samplers_iterator{this, getNumStaticSamplers()};
+  llvm::iterator_range<param_header_iterator> param_headers() const {
+    return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
   }
 
   llvm::iterator_range<samplers_iterator> samplers() const {
-    return llvm::make_range(samplers_begin(), samplers_end());
-  }
-
-  llvm::iterator_range<param_header_iterator> param_headers() const {
-    return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
+    return llvm::make_range(StaticSamplers.begin(), StaticSamplers.end());
   }
 
   uint32_t getFlags() const { return Flags; }
diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
index 031b9414f4c1a..b7da8316840f0 100644
--- a/llvm/lib/Object/DXContainer.cpp
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <cstddef>
+
 #include "llvm/Object/DXContainer.h"
 #include "llvm/BinaryFormat/DXContainer.h"
 #include "llvm/Object/Error.h"
@@ -276,10 +278,13 @@ Error DirectX::RootSignature::parse() {
       RootParametersOffset,
       NumParameters * sizeof(dxbc::RTS0::v1::RootParameterHeader));
 
-  StaticSamplers.Stride = sizeof(dxbc::RTS0::v1::StaticSampler);
-  StaticSamplers.Data = PartData.substr(
-      StaticSamplersOffset,
-      NumStaticSamplers * sizeof(dxbc::RTS0::v1::StaticSampler));
+  StaticSamplers.Stride = (Version <= 2)
+                              ? sizeof(dxbc::RTS0::v1::StaticSampler)
+                              : sizeof(dxbc::RTS0::v3::StaticSampler);
+
+  StaticSamplers.Data = PartData.substr(StaticSamplersOffset,
+                                        static_cast<size_t>(NumStaticSamplers) *
+                                            StaticSamplers.Stride);
 
   return Error::success();
 }
diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 91f86caaa4005..2fde1b86247f8 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -163,11 +163,7 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     }
   }
 
-  for (llvm::Expected<dxbc::RTS0::v3::StaticSampler> MaybeSampler :
-       Data.samplers()) {
-    if (Error E = MaybeSampler.takeError())
-      return std::move(E);
-    const llvm::dxbc::RTS0::v3::StaticSampler &S = *MaybeSampler;
+  for (const auto &S : Data.samplers()) {
 
     if (!dxbc::isValidSamplerFilter(S.Filter))
       return createStringError(std::errc::invalid_argument,
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index fe898c430b8a3..76b2aed5bb591 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1184,9 +1184,7 @@ TEST(RootSignature, ParseStaticSamplers) {
     ASSERT_EQ(RS.getStaticSamplersOffset(), 24u);
     ASSERT_EQ(RS.getFlags(), 17u);
 
-    auto MaybeSamplerView = *RS.samplers().begin();
-    ASSERT_THAT_ERROR(MaybeSamplerView.takeError(), Succeeded());
-    const auto &Sampler = *MaybeSamplerView;
+    auto Sampler = *RS.samplers().begin();
 
     ASSERT_EQ(Sampler.Filter, 10u);
     ASSERT_EQ(Sampler.AddressU, 1u);
@@ -1202,4 +1200,49 @@ TEST(RootSignature, ParseStaticSamplers) {
     ASSERT_EQ(Sampler.RegisterSpace, 32u);
     ASSERT_EQ(Sampler.ShaderVisibility, 7u);
   }
+  {
+    uint8_t Buffer[] = {
+        0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+        0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+        0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
+        0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+        0x01, 0x00, 0x00, 0x00};
+    DXContainer C =
+        llvm::cantFail(DXContainer::create(getMemoryBuffer<148>(Buffer)));
+
+    auto MaybeRS = C.getRootSignature();
+    ASSERT_TRUE(MaybeRS.has_value());
+    const auto &RS = MaybeRS.value();
+    ASSERT_EQ(RS.getVersion(), 3U);
+    ASSERT_EQ(RS.getNumParameters(), 0U);
+    ASSERT_EQ(RS.getRootParametersOffset(), 0U);
+    ASSERT_EQ(RS.getNumStaticSamplers(), 1U);
+    ASSERT_EQ(RS.getStaticSamplersOffset(), 24U);
+    ASSERT_EQ(RS.getFlags(), 17U);
+
+    auto Sampler = *RS.samplers().begin();
+
+    ASSERT_EQ(Sampler.Filter, 10U);
+    ASSERT_EQ(Sampler.AddressU, 1U);
+    ASSERT_EQ(Sampler.AddressV, 2U);
+    ASSERT_EQ(Sampler.AddressW, 5U);
+    ASSERT_FLOAT_EQ(Sampler.MipLODBias, 1.23F);
+    ASSERT_EQ(Sampler.MaxAnisotropy, 20U);
+    ASSERT_EQ(Sampler.ComparisonFunc, 4U);
+    ASSERT_EQ(Sampler.BorderColor, 0U);
+    ASSERT_FLOAT_EQ(Sampler.MinLOD, 4.56F);
+    ASSERT_FLOAT_EQ(Sampler.MaxLOD, 8.9F);
+    ASSERT_EQ(Sampler.ShaderRegister, 31U);
+    ASSERT_EQ(Sampler.RegisterSpace, 32U);
+    ASSERT_EQ(Sampler.ShaderVisibility, 7U);
+    ASSERT_EQ(Sampler.Flags, 1U);
+  }
 }

>From 79ea587527552aaf93110098b526a88edbce620b Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 22 Sep 2025 12:17:34 -0700
Subject: [PATCH 07/15] adding new test

---
 llvm/lib/ObjectYAML/DXContainerYAML.cpp       |  2 -
 .../RootSignature-StaticSamplers1.3.yaml      | 65 +++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/ObjectYAML/DXContainer/RootSignature-StaticSamplers1.3.yaml

diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 2fde1b86247f8..806722be0813d 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -211,12 +211,10 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     NewS.ShaderVisibility = dxbc::ShaderVisibility(S.ShaderVisibility);
 
     if (Version > 2) {
-      if (Version > 1) {
 #define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
   NewS.Enum =                                                                  \
       (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum)) > 0;
 #include "llvm/BinaryFormat/DXContainerConstants.def"
-      }
     }
     RootSigDesc.StaticSamplers.push_back(NewS);
   }
diff --git a/llvm/test/ObjectYAML/DXContainer/RootSignature-StaticSamplers1.3.yaml b/llvm/test/ObjectYAML/DXContainer/RootSignature-StaticSamplers1.3.yaml
new file mode 100644
index 0000000000000..1623b05def009
--- /dev/null
+++ b/llvm/test/ObjectYAML/DXContainer/RootSignature-StaticSamplers1.3.yaml
@@ -0,0 +1,65 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+
+--- !dxcontainer
+Header:
+  Hash:            [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+  Version:
+    Major:           1
+    Minor:           0
+  PartCount:       1
+  PartOffsets:     [ 60 ]
+Parts:
+  - Name:            RTS0
+    Size:            80
+    RootSignature:
+      Version: 3
+      NumRootParameters: 0
+      RootParametersOffset: 24
+      NumStaticSamplers: 1
+      StaticSamplersOffset: 24
+      Parameters: []
+      Samplers: 
+        - Filter: MinLinearMagMipPoint 
+          AddressU: Wrap
+          AddressV: Mirror
+          AddressW: MirrorOnce
+          MipLODBias: 1.23
+          MaxAnisotropy: 20
+          ComparisonFunc: LessEqual
+          BorderColor: TransparentBlack
+          MinLOD: 4.56
+          MaxLOD: 8.90
+          ShaderRegister: 31 
+          RegisterSpace: 32
+          ShaderVisibility:  Mesh
+          SAMPLER_FLAG_UINT_BORDER_COLOR: true
+      AllowInputAssemblerInputLayout: true
+      DenyGeometryShaderRootAccess: true
+
+#CHECK:  - Name:            RTS0
+#CHECK-NEXT:    Size:            80
+#CHECK-NEXT:    RootSignature:
+#CHECK-NEXT:      Version:         3
+#CHECK-NEXT:      NumRootParameters: 0
+#CHECK-NEXT:      RootParametersOffset: 24
+#CHECK-NEXT:      NumStaticSamplers: 1
+#CHECK-NEXT:      StaticSamplersOffset: 24
+#CHECK-NEXT:      Parameters:      []
+#CHECK-NEXT:      Samplers:
+#CHECK-NEXT:        - Filter:          MinLinearMagMipPoint
+#CHECK-NEXT:          AddressU:        Wrap
+#CHECK-NEXT:          AddressV:        Mirror
+#CHECK-NEXT:          AddressW:        MirrorOnce
+#CHECK-NEXT:          MipLODBias:      1.23
+#CHECK-NEXT:          MaxAnisotropy:   20
+#CHECK-NEXT:          ComparisonFunc:  LessEqual
+#CHECK-NEXT:          BorderColor:     TransparentBlack
+#CHECK-NEXT:          MinLOD:          4.56
+#CHECK-NEXT:          MaxLOD:          8.9
+#CHECK-NEXT:          ShaderRegister:  31
+#CHECK-NEXT:          RegisterSpace:   32
+#CHECK-NEXT:          ShaderVisibility: Mesh
+#CHECK-NEXT:          SAMPLER_FLAG_UINT_BORDER_COLOR: true
+#CHECK-NEXT:      AllowInputAssemblerInputLayout: true
+#CHECK-NEXT:      DenyGeometryShaderRootAccess: true

>From 905d5d39d93e35a512537bec76566abefc79ce27 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 22 Sep 2025 12:32:25 -0700
Subject: [PATCH 08/15] clean up

---
 llvm/include/llvm/Object/DXContainer.h    | 33 +++++++++++------------
 llvm/lib/Object/DXContainer.cpp           |  2 --
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   |  1 -
 llvm/unittests/Object/DXContainerTest.cpp |  2 +-
 4 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index 0bfc5cec48da4..6f10401dd2ba2 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -124,25 +124,25 @@ template <typename T> struct ViewArray {
 
 namespace DirectX {
 
-template <typename T> Expected<T> readParameter(StringRef Data) {
-  T Struct;
-  if (sizeof(T) != Data.size())
-    return make_error<GenericBinaryError>(
-        "Reading structure out of file bounds", object_error::parse_failed);
-
-  memcpy(&Struct, Data.data(), sizeof(T));
-  // DXContainer is always little endian
-  if (sys::IsBigEndianHost)
-    Struct.swapBytes();
-  return Struct;
-}
-
 struct RootParameterView {
   const dxbc::RTS0::v1::RootParameterHeader &Header;
   StringRef ParamData;
 
   RootParameterView(const dxbc::RTS0::v1::RootParameterHeader &H, StringRef P)
       : Header(H), ParamData(P) {}
+
+  template <typename T> Expected<T> readParameter() {
+    T Struct;
+    if (sizeof(T) != ParamData.size())
+      return make_error<GenericBinaryError>(
+          "Reading structure out of file bounds", object_error::parse_failed);
+
+    memcpy(&Struct, ParamData.data(), sizeof(T));
+    // DXContainer is always little endian
+    if (sys::IsBigEndianHost)
+      Struct.swapBytes();
+    return Struct;
+  }
 };
 
 struct RootConstantView : RootParameterView {
@@ -152,7 +152,7 @@ struct RootConstantView : RootParameterView {
   }
 
   llvm::Expected<dxbc::RTS0::v1::RootConstants> read() {
-    return readParameter<dxbc::RTS0::v1::RootConstants>(ParamData);
+    return readParameter<dxbc::RTS0::v1::RootConstants>();
   }
 };
 
@@ -168,8 +168,7 @@ struct RootDescriptorView : RootParameterView {
 
   llvm::Expected<dxbc::RTS0::v2::RootDescriptor> read(uint32_t Version) {
     if (Version == 1) {
-      auto Descriptor =
-          readParameter<dxbc::RTS0::v1::RootDescriptor>(ParamData);
+      auto Descriptor = readParameter<dxbc::RTS0::v1::RootDescriptor>();
       if (Error E = Descriptor.takeError())
         return E;
       return dxbc::RTS0::v2::RootDescriptor(*Descriptor);
@@ -178,7 +177,7 @@ struct RootDescriptorView : RootParameterView {
       return make_error<GenericBinaryError>("Invalid Root Signature version: " +
                                                 Twine(Version),
                                             object_error::parse_failed);
-    return readParameter<dxbc::RTS0::v2::RootDescriptor>(ParamData);
+    return readParameter<dxbc::RTS0::v2::RootDescriptor>();
   }
 };
 
diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
index b7da8316840f0..7b7b8d88c63fc 100644
--- a/llvm/lib/Object/DXContainer.cpp
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <cstddef>
-
 #include "llvm/Object/DXContainer.h"
 #include "llvm/BinaryFormat/DXContainer.h"
 #include "llvm/Object/Error.h"
diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index 806722be0813d..bfb3837707f0a 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -164,7 +164,6 @@ DXContainerYAML::RootSignatureYamlDesc::create(
   }
 
   for (const auto &S : Data.samplers()) {
-
     if (!dxbc::isValidSamplerFilter(S.Filter))
       return createStringError(std::errc::invalid_argument,
                                "Invalid value for static sampler filter");
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index 76b2aed5bb591..7fec8addc8d52 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1172,7 +1172,7 @@ TEST(RootSignature, ParseStaticSamplers) {
         0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
         0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00};
     DXContainer C =
-        llvm::cantFail(DXContainer::create(getMemoryBuffer<144>(Buffer)));
+        llvm::cantFail(DXContainer::create(getMemoryBuffer<133>(Buffer)));
 
     auto MaybeRS = C.getRootSignature();
     ASSERT_TRUE(MaybeRS.has_value());

>From b73bf248c1225498e6372d25f8e75ce6a03d5489 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 22 Sep 2025 12:33:59 -0700
Subject: [PATCH 09/15] clean up

---
 llvm/include/llvm/Object/DXContainer.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index 6f10401dd2ba2..5a5a4dbaae2ad 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -123,7 +123,6 @@ template <typename T> struct ViewArray {
 };
 
 namespace DirectX {
-
 struct RootParameterView {
   const dxbc::RTS0::v1::RootParameterHeader &Header;
   StringRef ParamData;
@@ -180,7 +179,6 @@ struct RootDescriptorView : RootParameterView {
     return readParameter<dxbc::RTS0::v2::RootDescriptor>();
   }
 };
-
 template <typename T> struct DescriptorTable {
   uint32_t NumRanges;
   uint32_t RangesOffset;
@@ -249,11 +247,9 @@ class RootSignature {
   llvm::iterator_range<param_header_iterator> param_headers() const {
     return llvm::make_range(ParametersHeaders.begin(), ParametersHeaders.end());
   }
-
   llvm::iterator_range<samplers_iterator> samplers() const {
     return llvm::make_range(StaticSamplers.begin(), StaticSamplers.end());
   }
-
   uint32_t getFlags() const { return Flags; }
 
   llvm::Expected<RootParameterView>

>From ddf99455e409897f245c38dc98234f43ff51325b Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Wed, 24 Sep 2025 11:45:28 -0700
Subject: [PATCH 10/15] changing size and remove untested parameters

---
 llvm/include/llvm/BinaryFormat/DXContainer.h  |  1 +
 .../ObjectYAML/DXContainerYAMLTest.cpp        | 26 ++++++-------------
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index a08cfff4b4974..08a7ddb6929f5 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -822,6 +822,7 @@ struct DescriptorRange {
   }
 };
 } // namespace v2
+
 namespace v3 {
 struct StaticSampler : public v1::StaticSampler {
   uint32_t Flags;
diff --git a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
index db9861f0149a4..1b21fe01dfca9 100644
--- a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
@@ -528,7 +528,7 @@ TEST(RootSignature, ParseStaticSamplers) {
 }
 
 TEST(RootSignature, ParseStaticSamplersV13) {
-  SmallString<160> Storage;
+  SmallString<128> Storage;
 
   // First read a fully explicit yaml with all sizes and offsets provided
   ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
@@ -551,19 +551,9 @@ TEST(RootSignature, ParseStaticSamplersV13) {
       StaticSamplersOffset: 24
       Parameters: []
       Samplers: 
-        - Filter: MinLinearMagMipPoint 
-          AddressU: Wrap
-          AddressV: Mirror
-          AddressW: MirrorOnce
-          MipLODBias: 1.23
-          MaxAnisotropy: 20
-          ComparisonFunc: LessEqual
-          BorderColor: TransparentBlack
-          MinLOD: 4.56
-          MaxLOD: 8.90
-          ShaderRegister: 31 
+        - ShaderRegister: 31 
           RegisterSpace: 32
-          ShaderVisibility:  Mesh
+          ShaderVisibility:  All
           SAMPLER_FLAG_UINT_BORDER_COLOR: true
       AllowInputAssemblerInputLayout: true
       DenyGeometryShaderRootAccess: true
@@ -577,11 +567,11 @@ TEST(RootSignature, ParseStaticSamplersV13) {
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-      0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-      0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-      0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-      0x00, 0x00, 0x00, 0x00, 0x85, 0xeb, 0x91, 0x40, 0x66, 0x66, 0x0e, 0x41,
-      0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x7f,
+      0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x01, 0x00, 0x00, 0x00};
 
   EXPECT_EQ(Storage.size(), 148U);

>From 284901cb5c5664a8213254773dc3401e59a2c119 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Wed, 24 Sep 2025 11:47:22 -0700
Subject: [PATCH 11/15] adding suggested comment

---
 llvm/include/llvm/MC/DXContainerRootSignature.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/include/llvm/MC/DXContainerRootSignature.h b/llvm/include/llvm/MC/DXContainerRootSignature.h
index 2a76e81fefc5f..514e74b92d101 100644
--- a/llvm/include/llvm/MC/DXContainerRootSignature.h
+++ b/llvm/include/llvm/MC/DXContainerRootSignature.h
@@ -74,6 +74,7 @@ struct StaticSampler {
   uint32_t ShaderRegister;
   uint32_t RegisterSpace;
   dxbc::ShaderVisibility ShaderVisibility;
+  // Version 3 onwards:
   uint32_t Flags;
 };
 

>From 73e6bb53cf5d71b3cf0f4914207782d7636af0f5 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Wed, 24 Sep 2025 12:24:05 -0700
Subject: [PATCH 12/15] addressing inbelic comments

---
 .../Frontend/HLSL/RootSignatureValidations.h  |  2 ++
 .../llvm/MC/DXContainerRootSignature.h        |  2 +-
 .../Frontend/HLSL/RootSignatureMetadata.cpp   |  7 +++++++
 .../HLSL/RootSignatureValidations.cpp         | 15 +++++++++++++++
 llvm/lib/MC/DXContainerRootSignature.cpp      | 10 +++++-----
 ...otSignature-StaticSamplers-Invalid-Flag.ll | 19 +++++++++++++++++++
 6 files changed, 49 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll

diff --git a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
index ea96094b18300..46a6e6eac379e 100644
--- a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
+++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
@@ -33,6 +33,8 @@ LLVM_ABI bool verifyRangeType(uint32_t Type);
 LLVM_ABI bool verifyDescriptorRangeFlag(uint32_t Version,
                                         dxil::ResourceClass Type,
                                         dxbc::DescriptorRangeFlags FlagsVal);
+LLVM_ABI bool verifyStaticSamplerFlags(uint32_t Version,
+                                       dxbc::StaticSamplerFlags Flags);
 LLVM_ABI bool verifyNumDescriptors(uint32_t NumDescriptors);
 LLVM_ABI bool verifyMipLODBias(float MipLODBias);
 LLVM_ABI bool verifyMaxAnisotropy(uint32_t MaxAnisotropy);
diff --git a/llvm/include/llvm/MC/DXContainerRootSignature.h b/llvm/include/llvm/MC/DXContainerRootSignature.h
index 514e74b92d101..2b08b2439d2c0 100644
--- a/llvm/include/llvm/MC/DXContainerRootSignature.h
+++ b/llvm/include/llvm/MC/DXContainerRootSignature.h
@@ -75,7 +75,7 @@ struct StaticSampler {
   uint32_t RegisterSpace;
   dxbc::ShaderVisibility ShaderVisibility;
   // Version 3 onwards:
-  uint32_t Flags;
+  uint32_t Flags = 0;
 };
 
 struct RootParametersContainer {
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
index f29f2c7602fc6..417169576f5d9 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
@@ -651,6 +651,13 @@ Error MetadataParser::validateRootSignature(
           joinErrors(std::move(DeferredErrs),
                      make_error<RootSignatureValidationError<uint32_t>>(
                          "RegisterSpace", Sampler.RegisterSpace));
+
+    if (!hlsl::rootsig::verifyStaticSamplerFlags(
+            RSD.Version, dxbc::StaticSamplerFlags(Sampler.Flags)))
+      DeferredErrs =
+          joinErrors(std::move(DeferredErrs),
+                     make_error<RootSignatureValidationError<uint32_t>>(
+                         "Static Sampler Flag", Sampler.Flags));
   }
 
   return DeferredErrs;
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
index 8c298f0685286..ef1021417414b 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
@@ -113,6 +113,21 @@ bool verifyDescriptorRangeFlag(uint32_t Version, dxil::ResourceClass Type,
   return (Flags & ~Mask) == FlagT::None;
 }
 
+bool verifyStaticSamplerFlags(uint32_t Version,
+                              dxbc::StaticSamplerFlags Flags) {
+
+  if (Version <= 2)
+    return Flags == dxbc::StaticSamplerFlags::None;
+
+  assert(Version == 3 && "Provided invalid root signature version");
+
+  dxbc::StaticSamplerFlags Mask =
+      dxbc::StaticSamplerFlags::NonNormalizedCoordinates |
+      dxbc::StaticSamplerFlags::UintBorderColor |
+      dxbc::StaticSamplerFlags::None;
+  return (Flags | Mask) == Mask;
+}
+
 bool verifyNumDescriptors(uint32_t NumDescriptors) {
   return NumDescriptors > 0;
 }
diff --git a/llvm/lib/MC/DXContainerRootSignature.cpp b/llvm/lib/MC/DXContainerRootSignature.cpp
index 13784e7c86684..2338370d84389 100644
--- a/llvm/lib/MC/DXContainerRootSignature.cpp
+++ b/llvm/lib/MC/DXContainerRootSignature.cpp
@@ -32,12 +32,12 @@ static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream,
 
 size_t RootSignatureDesc::getSize() const {
   uint32_t StaticSamplersOffset = computeStaticSamplersOffset();
-  size_t StaticSamplersSize =
-      (Version > 2 ? sizeof(dxbc::RTS0::v3::StaticSampler)
-                   : sizeof(dxbc::RTS0::v1::StaticSampler)) *
-      StaticSamplers.size();
+  size_t StaticSamplersSize = sizeof(dxbc::RTS0::v1::StaticSampler);
+  if (Version > 2)
+    StaticSamplersSize = sizeof(dxbc::RTS0::v3::StaticSampler);
 
-  return size_t(StaticSamplersOffset) + StaticSamplersSize;
+  return size_t(StaticSamplersOffset) +
+         (StaticSamplersSize * StaticSamplers.size());
 }
 
 uint32_t RootSignatureDesc::computeRootParametersOffset() const {
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll
new file mode 100644
index 0000000000000..fa5bf12e2b8cd
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll
@@ -0,0 +1,19 @@
+; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
+
+
+target triple = "dxil-unknown-shadermodel6.0-compute"
+
+; CHECK: error: Invalid value for ShaderVisibility: 666
+; CHECK-NOT: Root Signature Definitions
+
+define void @main() #0 {
+entry:
+  ret void
+}
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+
+
+!dx.rootsignatures = !{!2} ; list of function/root signature pairs
+!2 = !{ ptr @main, !3, i32 2 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"StaticSampler", i32 4, i32 2, i32 3, i32 5, float 0x3FF6CCCCC0000000, i32 9, i32 3, i32 2, float -1.280000e+02, float 1.280000e+02, i32 42, i32 0, i32 666 }

>From 159cd5793e9bfa1cacaecc4601b8e4607e49cdc8 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Wed, 24 Sep 2025 12:37:02 -0700
Subject: [PATCH 13/15] addressing inbelic comments

---
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   | 2 +-
 llvm/unittests/Object/DXContainerTest.cpp | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index bfb3837707f0a..efa8b40c2d554 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -212,7 +212,7 @@ DXContainerYAML::RootSignatureYamlDesc::create(
     if (Version > 2) {
 #define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
   NewS.Enum =                                                                  \
-      (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum)) > 0;
+      (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum));
 #include "llvm/BinaryFormat/DXContainerConstants.def"
     }
     RootSigDesc.StaticSamplers.push_back(NewS);
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index 7fec8addc8d52..9e805639cb409 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1201,6 +1201,9 @@ TEST(RootSignature, ParseStaticSamplers) {
     ASSERT_EQ(Sampler.ShaderVisibility, 7u);
   }
   {
+    // this is testing static sampler parsing for root signature version 1.2, 
+    // it changes: the version number, the size of root signature being emitted 
+    // and the values for flag fields.
     uint8_t Buffer[] = {
         0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,

>From b7f07aa9781a6e62627aa98a0aa90f5a76d8f75f Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Wed, 24 Sep 2025 13:47:31 -0700
Subject: [PATCH 14/15] format

---
 llvm/lib/ObjectYAML/DXContainerYAML.cpp   | 3 +--
 llvm/unittests/Object/DXContainerTest.cpp | 4 ++--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
index efa8b40c2d554..3c09ae4e5f2bc 100644
--- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp
+++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp
@@ -211,8 +211,7 @@ DXContainerYAML::RootSignatureYamlDesc::create(
 
     if (Version > 2) {
 #define STATIC_SAMPLER_FLAG(Num, Enum, Flag)                                   \
-  NewS.Enum =                                                                  \
-      (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum));
+  NewS.Enum = (S.Flags & llvm::to_underlying(dxbc::StaticSamplerFlags::Enum));
 #include "llvm/BinaryFormat/DXContainerConstants.def"
     }
     RootSigDesc.StaticSamplers.push_back(NewS);
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index 9e805639cb409..d6f7b26b99cd7 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -1201,8 +1201,8 @@ TEST(RootSignature, ParseStaticSamplers) {
     ASSERT_EQ(Sampler.ShaderVisibility, 7u);
   }
   {
-    // this is testing static sampler parsing for root signature version 1.2, 
-    // it changes: the version number, the size of root signature being emitted 
+    // this is testing static sampler parsing for root signature version 1.2,
+    // it changes: the version number, the size of root signature being emitted
     // and the values for flag fields.
     uint8_t Buffer[] = {
         0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

>From efcd87383068e58130656536bb9f67f1320d4972 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Thu, 25 Sep 2025 17:57:31 -0700
Subject: [PATCH 15/15] remove test

---
 .../Frontend/HLSL/RootSignatureValidations.h  |  3 +--
 .../Frontend/HLSL/RootSignatureMetadata.cpp   |  3 +--
 .../HLSL/RootSignatureValidations.cpp         |  8 ++++++--
 ...otSignature-StaticSamplers-Invalid-Flag.ll | 19 -------------------
 4 files changed, 8 insertions(+), 25 deletions(-)
 delete mode 100644 llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll

diff --git a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
index 46a6e6eac379e..64a8061bba078 100644
--- a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
+++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
@@ -33,8 +33,7 @@ LLVM_ABI bool verifyRangeType(uint32_t Type);
 LLVM_ABI bool verifyDescriptorRangeFlag(uint32_t Version,
                                         dxil::ResourceClass Type,
                                         dxbc::DescriptorRangeFlags FlagsVal);
-LLVM_ABI bool verifyStaticSamplerFlags(uint32_t Version,
-                                       dxbc::StaticSamplerFlags Flags);
+LLVM_ABI bool verifyStaticSamplerFlags(uint32_t Version, uint32_t FlagsNumber);
 LLVM_ABI bool verifyNumDescriptors(uint32_t NumDescriptors);
 LLVM_ABI bool verifyMipLODBias(float MipLODBias);
 LLVM_ABI bool verifyMaxAnisotropy(uint32_t MaxAnisotropy);
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
index 417169576f5d9..106e49606b8fd 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
@@ -652,8 +652,7 @@ Error MetadataParser::validateRootSignature(
                      make_error<RootSignatureValidationError<uint32_t>>(
                          "RegisterSpace", Sampler.RegisterSpace));
 
-    if (!hlsl::rootsig::verifyStaticSamplerFlags(
-            RSD.Version, dxbc::StaticSamplerFlags(Sampler.Flags)))
+    if (!hlsl::rootsig::verifyStaticSamplerFlags(RSD.Version, Sampler.Flags))
       DeferredErrs =
           joinErrors(std::move(DeferredErrs),
                      make_error<RootSignatureValidationError<uint32_t>>(
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
index ef1021417414b..07a508d8d7642 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
@@ -113,9 +113,13 @@ bool verifyDescriptorRangeFlag(uint32_t Version, dxil::ResourceClass Type,
   return (Flags & ~Mask) == FlagT::None;
 }
 
-bool verifyStaticSamplerFlags(uint32_t Version,
-                              dxbc::StaticSamplerFlags Flags) {
+bool verifyStaticSamplerFlags(uint32_t Version, uint32_t FlagsNumber) {
+  uint32_t LargestValue = llvm::to_underlying(
+      dxbc::StaticSamplerFlags::LLVM_BITMASK_LARGEST_ENUMERATOR);
+  if (FlagsNumber >= NextPowerOf2(LargestValue))
+    return false;
 
+  dxbc::StaticSamplerFlags Flags = dxbc::StaticSamplerFlags(FlagsNumber);
   if (Version <= 2)
     return Flags == dxbc::StaticSamplerFlags::None;
 
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll
deleted file mode 100644
index fa5bf12e2b8cd..0000000000000
--- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-StaticSamplers-Invalid-Flag.ll
+++ /dev/null
@@ -1,19 +0,0 @@
-; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
-
-
-target triple = "dxil-unknown-shadermodel6.0-compute"
-
-; CHECK: error: Invalid value for ShaderVisibility: 666
-; CHECK-NOT: Root Signature Definitions
-
-define void @main() #0 {
-entry:
-  ret void
-}
-attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
-
-
-!dx.rootsignatures = !{!2} ; list of function/root signature pairs
-!2 = !{ ptr @main, !3, i32 2 } ; function, root signature
-!3 = !{ !5 } ; list of root signature elements
-!5 = !{ !"StaticSampler", i32 4, i32 2, i32 3, i32 5, float 0x3FF6CCCCC0000000, i32 9, i32 3, i32 2, float -1.280000e+02, float 1.280000e+02, i32 42, i32 0, i32 666 }



More information about the llvm-commits mailing list