[llvm] b649b35 - [HLSL] Adding support for Root Constants in LLVM Metadata (#135085)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 24 13:56:38 PDT 2025


Author: joaosaffran
Date: 2025-04-24T13:56:34-07:00
New Revision: b649b3557e7b0a95612be64c1fe2334f6ecb2132

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

LOG: [HLSL] Adding support for Root Constants in LLVM Metadata (#135085)

- Closes [#126637](https://github.com/llvm/llvm-project/issues/126637)

---------

Co-authored-by: joaosaffran <joao.saffran at microsoft.com>

Added: 
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll

Modified: 
    llvm/lib/Target/DirectX/DXILRootSignature.cpp
    llvm/lib/Target/DirectX/DXILRootSignature.h
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll

Removed: 
    llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll


################################################################################
diff  --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
index 3ba0535e0114b..ef299c17baf76 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
@@ -40,14 +40,66 @@ static bool reportError(LLVMContext *Ctx, Twine Message,
   return true;
 }
 
+static bool reportValueError(LLVMContext *Ctx, Twine ParamName,
+                             uint32_t Value) {
+  Ctx->diagnose(DiagnosticInfoGeneric(
+      "Invalid value for " + ParamName + ": " + Twine(Value), DS_Error));
+  return true;
+}
+
+static std::optional<uint32_t> extractMdIntValue(MDNode *Node,
+                                                 unsigned int OpId) {
+  if (auto *CI =
+          mdconst::dyn_extract<ConstantInt>(Node->getOperand(OpId).get()))
+    return CI->getZExtValue();
+  return std::nullopt;
+}
+
 static bool parseRootFlags(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD,
                            MDNode *RootFlagNode) {
 
   if (RootFlagNode->getNumOperands() != 2)
     return reportError(Ctx, "Invalid format for RootFlag Element");
 
-  auto *Flag = mdconst::extract<ConstantInt>(RootFlagNode->getOperand(1));
-  RSD.Flags = Flag->getZExtValue();
+  if (std::optional<uint32_t> Val = extractMdIntValue(RootFlagNode, 1))
+    RSD.Flags = *Val;
+  else
+    return reportError(Ctx, "Invalid value for RootFlag");
+
+  return false;
+}
+
+static bool parseRootConstants(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD,
+                               MDNode *RootConstantNode) {
+
+  if (RootConstantNode->getNumOperands() != 5)
+    return reportError(Ctx, "Invalid format for RootConstants Element");
+
+  mcdxbc::RootParameter NewParameter;
+  NewParameter.Header.ParameterType =
+      llvm::to_underlying(dxbc::RootParameterType::Constants32Bit);
+
+  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 1))
+    NewParameter.Header.ShaderVisibility = *Val;
+  else
+    return reportError(Ctx, "Invalid value for ShaderVisibility");
+
+  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 2))
+    NewParameter.Constants.ShaderRegister = *Val;
+  else
+    return reportError(Ctx, "Invalid value for ShaderRegister");
+
+  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 3))
+    NewParameter.Constants.RegisterSpace = *Val;
+  else
+    return reportError(Ctx, "Invalid value for RegisterSpace");
+
+  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 4))
+    NewParameter.Constants.Num32BitValues = *Val;
+  else
+    return reportError(Ctx, "Invalid value for Num32BitValues");
+
+  RSD.Parameters.push_back(NewParameter);
 
   return false;
 }
@@ -62,12 +114,16 @@ static bool parseRootSignatureElement(LLVMContext *Ctx,
   RootSignatureElementKind ElementKind =
       StringSwitch<RootSignatureElementKind>(ElementText->getString())
           .Case("RootFlags", RootSignatureElementKind::RootFlags)
+          .Case("RootConstants", RootSignatureElementKind::RootConstants)
           .Default(RootSignatureElementKind::Error);
 
   switch (ElementKind) {
 
   case RootSignatureElementKind::RootFlags:
     return parseRootFlags(Ctx, RSD, Element);
+  case RootSignatureElementKind::RootConstants:
+    return parseRootConstants(Ctx, RSD, Element);
+    break;
   case RootSignatureElementKind::Error:
     return reportError(Ctx, "Invalid Root Signature Element: " +
                                 ElementText->getString());
@@ -94,10 +150,29 @@ static bool parse(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD,
 
 static bool verifyRootFlag(uint32_t Flags) { return (Flags & ~0xfff) == 0; }
 
+static bool verifyVersion(uint32_t Version) {
+  return (Version == 1 || Version == 2);
+}
+
 static bool validate(LLVMContext *Ctx, const mcdxbc::RootSignatureDesc &RSD) {
+
+  if (!verifyVersion(RSD.Version)) {
+    return reportValueError(Ctx, "Version", RSD.Version);
+  }
+
   if (!verifyRootFlag(RSD.Flags)) {
-    return reportError(Ctx, "Invalid Root Signature flag value");
+    return reportValueError(Ctx, "RootFlags", RSD.Flags);
+  }
+
+  for (const mcdxbc::RootParameter &P : RSD.Parameters) {
+    if (!dxbc::isValidShaderVisibility(P.Header.ShaderVisibility))
+      return reportValueError(Ctx, "ShaderVisibility",
+                              P.Header.ShaderVisibility);
+
+    assert(dxbc::isValidParameterType(P.Header.ParameterType) &&
+           "Invalid value for ParameterType");
   }
+
   return false;
 }
 
@@ -166,6 +241,10 @@ analyzeModule(Module &M) {
     }
 
     mcdxbc::RootSignatureDesc RSD;
+    // Clang emits the root signature data in dxcontainer following a specific
+    // sequence. First the header, then the root parameters. So the header
+    // offset will always equal to the header size.
+    RSD.RootParameterOffset = sizeof(dxbc::RootSignatureHeader);
 
     if (parse(Ctx, RSD, RootElementListNode) || validate(Ctx, RSD)) {
       return RSDMap;
@@ -192,7 +271,6 @@ PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M,
   SmallDenseMap<const Function *, mcdxbc::RootSignatureDesc> &RSDMap =
       AM.getResult<RootSignatureAnalysis>(M);
 
-  const size_t RSHSize = sizeof(dxbc::RootSignatureHeader);
   OS << "Root Signature Definitions"
      << "\n";
   uint8_t Space = 0;
@@ -205,14 +283,33 @@ PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M,
 
     // start root signature header
     Space++;
-    OS << indent(Space) << "Flags: " << format_hex(RS.Flags, 8) << ":\n";
-    OS << indent(Space) << "Version: " << RS.Version << ":\n";
-    OS << indent(Space) << "NumParameters: " << RS.Parameters.size() << ":\n";
-    OS << indent(Space) << "RootParametersOffset: " << RSHSize << ":\n";
-    OS << indent(Space) << "NumStaticSamplers: " << 0 << ":\n";
-    OS << indent(Space)
-       << "StaticSamplersOffset: " << RSHSize + RS.Parameters.size_in_bytes()
-       << ":\n";
+    OS << indent(Space) << "Flags: " << format_hex(RS.Flags, 8) << "\n";
+    OS << indent(Space) << "Version: " << RS.Version << "\n";
+    OS << indent(Space) << "RootParametersOffset: " << RS.RootParameterOffset
+       << "\n";
+    OS << indent(Space) << "NumParameters: " << RS.Parameters.size() << "\n";
+    Space++;
+    for (auto const &P : RS.Parameters) {
+      OS << indent(Space) << "- Parameter Type: " << P.Header.ParameterType
+         << "\n";
+      OS << indent(Space + 2)
+         << "Shader Visibility: " << P.Header.ShaderVisibility << "\n";
+      switch (P.Header.ParameterType) {
+      case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit):
+        OS << indent(Space + 2)
+           << "Register Space: " << P.Constants.RegisterSpace << "\n";
+        OS << indent(Space + 2)
+           << "Shader Register: " << P.Constants.ShaderRegister << "\n";
+        OS << indent(Space + 2)
+           << "Num 32 Bit Values: " << P.Constants.Num32BitValues << "\n";
+        break;
+      }
+    }
+    Space--;
+    OS << indent(Space) << "NumStaticSamplers: " << 0 << "\n";
+    OS << indent(Space) << "StaticSamplersOffset: " << RS.StaticSamplersOffset
+       << "\n";
+
     Space--;
     // end root signature header
   }

diff  --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h
index 8c25b2eb3fadf..93ec614f1ab85 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.h
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.h
@@ -24,7 +24,11 @@
 namespace llvm {
 namespace dxil {
 
-enum class RootSignatureElementKind { Error = 0, RootFlags = 1 };
+enum class RootSignatureElementKind {
+  Error = 0,
+  RootFlags = 1,
+  RootConstants = 2
+};
 class RootSignatureAnalysis : public AnalysisInfoMixin<RootSignatureAnalysis> {
   friend AnalysisInfoMixin<RootSignatureAnalysis>;
   static AnalysisKey Key;

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll
index ef2b97860bfae..e81679732a5d8 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll
@@ -23,7 +23,7 @@ attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
 ; DXC-NEXT:    RootSignature:
 ; DXC-NEXT:      Version:         2
 ; DXC-NEXT:      NumRootParameters: 0
-; DXC-NEXT:      RootParametersOffset: 0
+; DXC-NEXT:      RootParametersOffset: 24
 ; DXC-NEXT:      NumStaticSamplers: 0
 ; DXC-NEXT:      StaticSamplersOffset: 0
 ; DXC-NEXT:      Parameters: []

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll
index 581ac9aaec110..d23e1c71d2fc0 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll
@@ -26,15 +26,15 @@ attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
 ; CHECK-LABEL: Definition for 'main':
 ; CHECK-NEXT:   Flags: 0x000001
 ; CHECK-NEXT:   Version: 2
-; CHECK-NEXT:   NumParameters: 0
 ; CHECK-NEXT:   RootParametersOffset: 24
+; CHECK-NEXT:   NumParameters: 0
 ; CHECK-NEXT:   NumStaticSamplers: 0
-; CHECK-NEXT:   StaticSamplersOffset: 24
+; CHECK-NEXT:   StaticSamplersOffset: 0
 
 ; CHECK-LABEL: Definition for 'anotherMain':
 ; CHECK-NEXT:   Flags: 0x000002
 ; CHECK-NEXT:   Version: 2
-; CHECK-NEXT:   NumParameters: 0
 ; CHECK-NEXT:   RootParametersOffset: 24
+; CHECK-NEXT:   NumParameters: 0
 ; CHECK-NEXT:   NumStaticSamplers: 0
-; CHECK-NEXT:   StaticSamplersOffset: 24
+; CHECK-NEXT:   StaticSamplersOffset: 0

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll
new file mode 100644
index 0000000000000..2b4a075281f80
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll
@@ -0,0 +1,20 @@
+; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
+
+; CHECK: error: Invalid value for ShaderVisibility: 255
+; CHECK-NOT: Root Signature Definitions
+
+target triple = "dxil-unknown-shadermodel6.0-compute"
+
+
+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 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"RootConstants", i32 255, i32 1, i32 2, i32 3 }

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll
new file mode 100644
index 0000000000000..b55d1283df0c9
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll
@@ -0,0 +1,30 @@
+; RUN: opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
+
+target triple = "dxil-unknown-shadermodel6.0-compute"
+
+
+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 } ; function, root signature
+!3 = !{ !4, !5 } ; list of root signature elements
+!4 = !{ !"RootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout
+!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, i32 3 }
+
+;CHECK-LABEL: Definition for 'main':
+;CHECK-NEXT:  Flags: 0x000001
+;CHECK-NEXT:  Version: 2
+;CHECK-NEXT:  RootParametersOffset: 24
+;CHECK-NEXT:  NumParameters: 1
+;CHECK-NEXT:   - Parameter Type: 1
+;CHECK-NEXT:     Shader Visibility: 0
+;CHECK-NEXT:     Register Space: 2
+;CHECK-NEXT:     Shader Register: 1
+;CHECK-NEXT:     Num 32 Bit Values: 3
+;CHECK-NEXT:  NumStaticSamplers: 0
+;CHECK-NEXT:  StaticSamplersOffset: 0

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll
new file mode 100644
index 0000000000000..552c128e5ab57
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll
@@ -0,0 +1,16 @@
+; 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 Num32BitValues
+; CHECK-NOT: Root Signature Definitions
+
+define void @main() {
+entry:
+  ret void
+}
+
+!dx.rootsignatures = !{!2} ; list of function/root signature pairs
+!2 = !{ ptr @main, !3 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, !"Invalid" }

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll
new file mode 100644
index 0000000000000..1087b414942e2
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll
@@ -0,0 +1,18 @@
+; 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 RegisterSpace
+; 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 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"RootConstants", i32 0, i32 1, !"Invalid", i32 3 }

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll
new file mode 100644
index 0000000000000..53fd924e8f46e
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll
@@ -0,0 +1,18 @@
+; 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 ShaderRegister
+; 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 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"RootConstants", i32 0, !"Invalid", i32 2, i32 3 }

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll
new file mode 100644
index 0000000000000..71511ff523340
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll
@@ -0,0 +1,34 @@
+; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s
+; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+
+target triple = "dxil-unknown-shadermodel6.0-compute"
+
+; CHECK: @dx.rts0 = private constant [48 x i8]  c"{{.*}}", section "RTS0", align 4
+
+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 } ; function, root signature
+!3 = !{ !5 } ; list of root signature elements
+!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, i32 3 }
+
+; DXC:  - Name:            RTS0
+; DXC-NEXT:    Size:            48
+; DXC-NEXT:    RootSignature:
+; DXC-NEXT:      Version:         2
+; DXC-NEXT:      NumRootParameters: 1 
+; DXC-NEXT:      RootParametersOffset: 24 
+; DXC-NEXT:      NumStaticSamplers: 0
+; DXC-NEXT:      StaticSamplersOffset: 0
+; DXC-NEXT:      Parameters:
+; DXC-NEXT:        - ParameterType:   1
+; DXC-NEXT:          ShaderVisibility: 0
+; DXC-NEXT:          Constants:
+; DXC-NEXT:            Num32BitValues:  3
+; DXC-NEXT:            RegisterSpace:   2
+; DXC-NEXT:            ShaderRegister:  1

diff  --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll
similarity index 90%
rename from llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll
rename to llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll
index fe93c9993c1c3..4b8e6abacd7ad 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll
@@ -1,6 +1,6 @@
 ; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s
 
-; CHECK: error: Invalid Root Signature flag value
+; CHECK: error: Invalid value for RootFlags: 2147487744
 ; CHECK-NOT: Root Signature Definitions
 
 target triple = "dxil-unknown-shadermodel6.0-compute"


        


More information about the llvm-commits mailing list