[clang] [llvm] [HLSL] Add semantic signature packing flags and invoke packing (PR #226554)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 11:01:38 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-driver

Author: Finn Plummer (inbelic)

<details>
<summary>Changes</summary>

Adds two flags to specify how to pack signature elements: `-pack-prefix-stable` and `-pack-optimized` in the dxc driver mode.
Adds the corresponding `-fdx-semantic-signature-packing-mode=` flag to the clang driver.

Using this it invokes the correct packing algorithm during generation of the semantic signature metadata and reports any packing diags.

Resolves: https://github.com/llvm/llvm-project/issues/204892

Assisted by: ChatGPT 6 Sol

---

Patch is 24.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/226554.diff


15 Files Affected:

- (modified) clang/include/clang/Basic/CodeGenOptions.def (+4) 
- (modified) clang/include/clang/Basic/CodeGenOptions.h (+5) 
- (modified) clang/include/clang/Basic/DiagnosticFrontendKinds.td (+2) 
- (modified) clang/include/clang/Options/Options.td (+13) 
- (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+37) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1) 
- (modified) clang/lib/Driver/ToolChains/HLSL.cpp (+16) 
- (modified) clang/lib/Frontend/CompilerInvocation.cpp (+4) 
- (modified) clang/test/CodeGenHLSL/semantics/semantic.input.hlsl (+4-4) 
- (modified) clang/test/CodeGenHLSL/semantics/semantic.output.hlsl (+4-4) 
- (added) clang/test/CodeGenHLSL/semantics/signature-packing-16bit.hlsl (+25) 
- (added) clang/test/CodeGenHLSL/semantics/signature-packing-errors.hlsl (+28) 
- (added) clang/test/CodeGenHLSL/semantics/signature-packing.hlsl (+84) 
- (added) clang/test/Driver/dxc_signature_packing.hlsl (+23) 
- (modified) llvm/docs/DirectX/SemanticSignatures.md (+10) 


``````````diff
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index dd9590d406d5e..9ef7ec4bac3f6 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -523,6 +523,10 @@ CODEGENOPT(ResMayAlias, 1, 0, Benign)
 /// Assume that all resources are bound if enabled
 CODEGENOPT(AllResourcesBound, 1, 0, Benign)
 
+/// Packing mode for HLSL signatures connecting programmable shader stages.
+ENUM_CODEGENOPT(HLSLSemanticSignaturePacking, HLSLSemanticSignaturePackingMode, 1,
+               HLSLSemanticSignaturePackingMode::PrefixStable, Benign)
+
 /// Do not embed dx.source.* metadata in HLSL modules.
 CODEGENOPT(DisableDXSourceMetadata, 1, 0, Benign)
 
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index c3a23415c922a..1f7b6cbac0b70 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -142,6 +142,11 @@ class CodeGenOptions : public CodeGenOptionsBase {
     All,
   };
 
+  enum class HLSLSemanticSignaturePackingMode {
+    PrefixStable,
+    Optimized,
+  };
+
   enum InlineAsmDialectKind {
     IAD_ATT,
     IAD_Intel,
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 031858610ede2..f0dddc0492f35 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -493,6 +493,8 @@ def warn_hlsl_langstd_minimal :
   Warning<"support for HLSL language version %0 is incomplete, "
           "recommend using %1 instead">,
   InGroup<HLSLDXCCompat>;
+def err_hlsl_signature_packing : Error<
+  "failed to pack %select{input|output}0 signature: %1">;
 def warn_hlsl_failed_to_embed_source
     : Warning<"failed to embed source for '%0' into dx.source.contents">,
       InGroup<HLSLDXCCompat>;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 15b2196b68e76..d15115620ce0d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -9986,6 +9986,19 @@ def fcgl : DXCFlag<"fcgl">, Alias<emit_pristine_llvm>;
 def enable_16bit_types : DXCFlag<"enable-16bit-types">,
   HelpText<"Enable 16-bit types and disable min precision types."
            "Available in HLSL 2018 and shader model 6.2.">;
+def dxc_pack_prefix_stable : DXCFlag<"pack-prefix-stable">,
+  HelpText<"Pack signature elements without moving previously packed elements (default)">;
+def dxc_pack_optimized : DXCFlag<"pack-optimized">,
+  HelpText<"Reorder signature elements for optimized packing">;
+def fdx_semantic_signature_packing_mode_EQ :
+  Joined<["-"], "fdx-semantic-signature-packing-mode=">,
+  Group<dxc_Group>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Select the packing mode for HLSL semantic signatures (default: prefix-stable)">,
+  Values<"prefix-stable,optimized">,
+  NormalizedValuesScope<"CodeGenOptions::HLSLSemanticSignaturePackingMode">,
+  NormalizedValues<["PrefixStable", "Optimized"]>,
+  MarshallingInfoEnum<CodeGenOpts<"HLSLSemanticSignaturePacking">, "PrefixStable">;
 def fdx_rootsignature_version :
   Joined<["-"], "fdx-rootsignature-version=">,
   Group<dxc_Group>,
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 52fde18dc3ebd..6ee89d14665d5 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -38,6 +38,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Frontend/HLSL/HLSLResource.h"
 #include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
+#include "llvm/Frontend/HLSL/SemanticSignaturePacking.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -104,6 +105,23 @@ void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
   RootSignatureValMD->addOperand(MDVals);
 }
 
+Expected<unsigned> packSemanticSignature(
+    MutableArrayRef<llvm::hlsl::SemanticSignatureElement> Elements,
+    llvm::Triple::EnvironmentType Stage, llvm::hlsl::IOType IOTy,
+    CodeGenOptions::HLSLSemanticSignaturePackingMode Mode,
+    bool UseNative16BitTypes) {
+  using namespace llvm::hlsl;
+  // Vertex inputs and pixel outputs have fixed packing rules, independent of
+  // the packing mode used between programmable stages.
+  if (Stage == llvm::Triple::Vertex && IOTy == IOType::In)
+    return packSignatureStacked(Elements, Stage, IOTy);
+  if (Stage == llvm::Triple::Pixel && IOTy == IOType::Out)
+    return packSignatureIndexed(Elements, Stage, IOTy);
+  if (Mode == CodeGenOptions::HLSLSemanticSignaturePackingMode::Optimized)
+    return packSignatureOptimized(Elements, Stage, IOTy, UseNative16BitTypes);
+  return packSignaturePrefixStable(Elements, Stage, IOTy, UseNative16BitTypes);
+}
+
 MDNode *buildSemanticSignatureMD(
     ArrayRef<llvm::hlsl::SemanticSignatureElement> Elements, LLVMContext &Ctx) {
   if (Elements.empty())
@@ -1865,6 +1883,25 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
     }
   }
 
+  if (CGM.getTarget().getTriple().isDXIL()) {
+    // Use the entry's shader stage, not the target environment, which may be
+    // 'library' when compiling multiple entry points.
+    auto Stage = FD->getAttr<HLSLShaderAttr>()->getType();
+    auto Mode = CGM.getCodeGenOpts().getHLSLSemanticSignaturePacking();
+    for (auto IOTy : {llvm::hlsl::IOType::In, llvm::hlsl::IOType::Out}) {
+      bool IsOutput = IOTy == llvm::hlsl::IOType::Out;
+      auto Packed = packSemanticSignature(
+          IsOutput ? OutputSignature : InputSignature, Stage, IOTy, Mode,
+          CGM.getLangOpts().NativeHalfType);
+      if (!Packed) {
+        CGM.getDiags().Report(FD->getLocation(),
+                              diag::err_hlsl_signature_packing)
+            << IsOutput << llvm::toString(Packed.takeError());
+        return;
+      }
+    }
+  }
+
   addSemanticSignatureMD(InputSignature, OutputSignature, EntryFn, M);
 }
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6636a5fd6e655..f6f1f4a0ece7f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3974,6 +3974,7 @@ static void RenderHLSLOptions(const Driver &D, const ArgList &Args,
       options::OPT_hlsl_entrypoint,
       options::OPT_fdx_rootsignature_define,
       options::OPT_fdx_rootsignature_version,
+      options::OPT_fdx_semantic_signature_packing_mode_EQ,
       options::OPT_fhlsl_spv_use_unknown_image_format,
       options::OPT_fhlsl_spv_use_legacy_buffer_matrix_order,
       options::OPT_fhlsl_spv_enable_maximal_reconvergence,
diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp
index 9e7005b8798f2..b5356f1ec45d3 100644
--- a/clang/lib/Driver/ToolChains/HLSL.cpp
+++ b/clang/lib/Driver/ToolChains/HLSL.cpp
@@ -441,7 +441,23 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, BoundArch BA,
       Args.hasArg(options::OPT_dxc_row_major))
     getDriver().Diag(diag::err_drv_dxc_invalid_matrix_layout);
 
+  if (Args.hasArg(options::OPT_dxc_pack_prefix_stable) &&
+      Args.hasArg(options::OPT_dxc_pack_optimized))
+    getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+        << "-pack-prefix-stable" << "-pack-optimized";
+
   for (Arg *A : Args) {
+    if (A->getOption().matches(options::OPT_dxc_pack_prefix_stable) ||
+        A->getOption().matches(options::OPT_dxc_pack_optimized)) {
+      DAL->AddJoinedArg(
+          nullptr,
+          Opts.getOption(options::OPT_fdx_semantic_signature_packing_mode_EQ),
+          A->getOption().matches(options::OPT_dxc_pack_prefix_stable)
+              ? "prefix-stable"
+              : "optimized");
+      A->claim();
+      continue;
+    }
     if (A->getOption().getID() == options::OPT_dxc_all_resources_bound) {
       DAL->AddFlagArg(nullptr,
                       Opts.getOption(options::OPT_hlsl_all_resources_bound));
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 649a1a18b4ebe..372c48b84d5ca 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -635,6 +635,10 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
     Diags.Report(diag::err_drv_argument_not_allowed_with)
         << "-fdx-rootsignature-define" << GetInputKindName(IK);
 
+  if (Args.hasArg(OPT_fdx_semantic_signature_packing_mode_EQ) && !LangOpts.HLSL)
+    Diags.Report(diag::err_drv_argument_not_allowed_with)
+        << "-fdx-semantic-signature-packing-mode" << GetInputKindName(IK);
+
   if (Args.hasArg(OPT_fgpu_allow_device_init) && !LangOpts.HIP)
     Diags.Report(diag::warn_ignored_hip_only_option)
         << Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args);
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
index 3bd77d783b435..b17298d8dee24 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
@@ -55,10 +55,10 @@ void main(S s) {}
 // CHECK: !dx.semantic.signatures = !{![[#ENTRY_SIG:]]}
 // CHECK: ![[#ENTRY_SIG]] = !{ptr @main, ![[#INPUT_SIG:]], null}
 // CHECK: ![[#INPUT_SIG]] = !{![[#A_SIG:]], ![[#B_SIG:]], ![[#D_SIG:]], ![[#E_SIG:]]}
-// CHECK: ![[#A_SIG]] = !{i32 0, !"A", i32 9, i32 0, ![[#ZERO_INDEX:]], i32 0, i32 1, i8 1, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#A_SIG]] = !{i32 0, !"A", i32 9, i32 0, ![[#ZERO_INDEX:]], i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#ZERO_INDEX]] = !{i32 0}
-// CHECK: ![[#B_SIG]] = !{i32 1, !"B", i32 9, i32 0, ![[#ZERO_INDEX]], i32 0, i32 1, i8 4, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-// CHECK: ![[#D_SIG]] = !{i32 2, !"D", i32 9, i32 0, ![[#D_INDICES:]], i32 0, i32 5, i8 1, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#B_SIG]] = !{i32 1, !"B", i32 9, i32 0, ![[#ZERO_INDEX]], i32 0, i32 1, i8 4, i32 1, i8 0, i8 0, i8 0, i32 0}
+// CHECK: ![[#D_SIG]] = !{i32 2, !"D", i32 9, i32 0, ![[#D_INDICES:]], i32 0, i32 5, i8 1, i32 2, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#D_INDICES]] = !{i32 0, i32 1, i32 2, i32 3, i32 4}
-// CHECK: ![[#E_SIG]] = !{i32 3, !"E", i32 9, i32 0, ![[#E_INDICES:]], i32 0, i32 6, i8 4, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#E_SIG]] = !{i32 3, !"E", i32 9, i32 0, ![[#E_INDICES:]], i32 0, i32 6, i8 4, i32 7, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#E_INDICES]] = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
index 54e9aa83cda0b..f714dba64a629 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
@@ -58,10 +58,10 @@ S main() {
 // CHECK: !dx.semantic.signatures = !{![[#ENTRY_SIG:]]}
 // CHECK: ![[#ENTRY_SIG]] = !{ptr @main, null, ![[#OUTPUT_SIG:]]}
 // CHECK: ![[#OUTPUT_SIG]] = !{![[#A_SIG:]], ![[#B_SIG:]], ![[#D_SIG:]], ![[#E_SIG:]]}
-// CHECK: ![[#A_SIG]] = !{i32 0, !"A", i32 9, i32 0, ![[#ZERO_INDEX:]], i32 0, i32 1, i8 1, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#A_SIG]] = !{i32 0, !"A", i32 9, i32 0, ![[#ZERO_INDEX:]], i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#ZERO_INDEX]] = !{i32 0}
-// CHECK: ![[#B_SIG]] = !{i32 1, !"B", i32 9, i32 0, ![[#ZERO_INDEX]], i32 0, i32 1, i8 4, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-// CHECK: ![[#D_SIG]] = !{i32 2, !"D", i32 9, i32 0, ![[#D_INDICES:]], i32 0, i32 5, i8 1, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#B_SIG]] = !{i32 1, !"B", i32 9, i32 0, ![[#ZERO_INDEX]], i32 0, i32 1, i8 4, i32 1, i8 0, i8 0, i8 0, i32 0}
+// CHECK: ![[#D_SIG]] = !{i32 2, !"D", i32 9, i32 0, ![[#D_INDICES:]], i32 0, i32 5, i8 1, i32 2, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#D_INDICES]] = !{i32 0, i32 1, i32 2, i32 3, i32 4}
-// CHECK: ![[#E_SIG]] = !{i32 3, !"E", i32 9, i32 0, ![[#E_INDICES:]], i32 0, i32 6, i8 4, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// CHECK: ![[#E_SIG]] = !{i32 3, !"E", i32 9, i32 0, ![[#E_INDICES:]], i32 0, i32 6, i8 4, i32 7, i8 0, i8 0, i8 0, i32 0}
 // CHECK: ![[#E_INDICES]] = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}
diff --git a/clang/test/CodeGenHLSL/semantics/signature-packing-16bit.hlsl b/clang/test/CodeGenHLSL/semantics/signature-packing-16bit.hlsl
new file mode 100644
index 0000000000000..d1618d4f2d1ac
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/signature-packing-16bit.hlsl
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-vertex -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=prefix-stable -o - %s | FileCheck %s --check-prefix=WIDE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-vertex -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=optimized -o - %s | FileCheck %s --check-prefix=WIDE
+// RUN: %clang_dxc -T vs_6_2 -fcgl -enable-16bit-types -pack-prefix-stable %s | FileCheck %s --check-prefix=NATIVE
+// RUN: %clang_dxc -T vs_6_2 -fcgl -enable-16bit-types -pack-optimized %s | FileCheck %s --check-prefix=NATIVE
+
+struct Output {
+  half a : A;
+  float b : B;
+  half c : C;
+};
+
+Output main() {
+  Output output = {1, 2, 3};
+  return output;
+}
+
+// Without native 16-bit types, half is float and all elements share a row.
+// WIDE-DAG: !{i32 0, !"A", i32 9, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+// WIDE-DAG: !{i32 1, !"B", i32 9, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 0, i8 1, i8 0, i8 0, i32 0}
+// WIDE-DAG: !{i32 2, !"C", i32 9, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 0, i8 2, i8 0, i8 0, i32 0}
+
+// Native 16-bit and 32-bit components must occupy different rows in both modes.
+// NATIVE-DAG: !{i32 0, !"A", i32 8, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+// NATIVE-DAG: !{i32 1, !"B", i32 9, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 1, i8 0, i8 0, i8 0, i32 0}
+// NATIVE-DAG: !{i32 2, !"C", i32 8, i32 0, !{{[0-9]+}}, i32 0, i32 1, i8 1, i32 0, i8 1, i8 0, i8 0, i32 0}
diff --git a/clang/test/CodeGenHLSL/semantics/signature-packing-errors.hlsl b/clang/test/CodeGenHLSL/semantics/signature-packing-errors.hlsl
new file mode 100644
index 0000000000000..b451c865f8352
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/signature-packing-errors.hlsl
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=prefix-stable -DSTACKED -o /dev/null -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=optimized -DSTACKED -o /dev/null -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=prefix-stable -DOUTPUT -o /dev/null -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=optimized -DOUTPUT -o /dev/null -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=prefix-stable -o /dev/null -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=optimized -o /dev/null -verify %s
+
+// Packing failures must be diagnosed rather than emitting unallocated metadata
+// or reporting a fatal LLVM error. Stacked inputs are limited to 32 rows too.
+#ifdef STACKED
+[shader("vertex")]
+void stacked_overflow(float data[33] : A) {} // expected-error {{failed to pack input signature: signature elements do not fit in 32 rows (element 0)}}
+
+#elif defined(OUTPUT)
+struct Output {
+  float4 data[33] : A;
+};
+
+[shader("vertex")]
+Output output_overflow() { // expected-error {{failed to pack output signature: signature elements do not fit in 32 rows (element 0)}}
+  Output output;
+  return output;
+}
+
+#else
+[shader("pixel")]
+void input_overflow(float4 data[33] : A) {} // expected-error {{failed to pack input signature: signature elements do not fit in 32 rows (element 0)}}
+#endif
diff --git a/clang/test/CodeGenHLSL/semantics/signature-packing.hlsl b/clang/test/CodeGenHLSL/semantics/signature-packing.hlsl
new file mode 100644
index 0000000000000..2dda3734a4165
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/signature-packing.hlsl
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,STABLE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=prefix-stable -o - %s | FileCheck %s --check-prefixes=CHECK,STABLE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -finclude-default-header -disable-llvm-passes -fdx-semantic-signature-packing-mode=optimized -o - %s | FileCheck %s --check-prefixes=CHECK,OPTIMIZED
+// RUN: %clang_dxc -T lib_6_3 -fcgl %s | FileCheck %s --check-prefixes=CHECK,STABLE
+// RUN: %clang_dxc -T lib_6_3 -fcgl -pack-prefix-stable %s | FileCheck %s --check-prefixes=CHECK,STABLE
+// RUN: %clang_dxc -T lib_6_3 -fcgl -pack-optimized %s | FileCheck %s --check-prefixes=CHECK,OPTIMIZED
+
+struct Varyings {
+  float a : A;
+  float2 b : B;
+  float3 c : C;
+  float2 d : D;
+};
+
+struct Attributes {
+  float a : IA;
+  float2 b : IB;
+  float3 c : IC;
+  float2 d : ID;
+};
+
+[shader("vertex")]
+Varyings vs_main(Attributes input) {
+  Varyings output = {input.a, input.b, input.c, input.d};
+  return output;
+}
+
+struct Targets {
+  float4 color : SV_Target3;
+  float extra : SV_Target0;
+};
+
+[shader("pixel")]
+Targets ps_main(Varyings input) {
+  Targets output;
+  output.color = float4(input.a, input.b, input.c.x);
+  output.extra = input.d.x;
+  return output;
+}
+
+// Signature IDs and intrinsic operands stay in declaration order even when
+// optimized packing assigns locations in a different order.
+// CHECK: call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0,
+// CHECK: call void @llvm.dx.store.output.v2f32(i32 1, i32 0, i8 0,
+// CHECK: call void @llvm.dx.store.output.v3f32(i32 2, i32 0, i8 0,
+// CHECK: call void @llvm.dx.store.output.v2f32(i32 3, i32 0, i8 0,
+// CHECK: call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0,
+// CHECK: call <2 x float> @llvm.dx.load.input.v2f32(i32 1, i32 0, i8 0,
+// CHECK: call <3 x float> @llvm.dx.load.input.v3f32(i32 2, i32 0, i8 0,
+// CHECK: call <2 x float> @llvm.dx.load.input.v2f32(i32 3, i32 0, i8 0,
+
+// Use each entry's shader attribute, rather than the library target stage.
+// Vertex outputs and pixel inputs have identical packed metadata.
+// CHECK: !dx.semantic.signatures = !{![[VS:[0-9]+]], ![[PS:[0-9]+]]}
+// CHECK-DAG: ![[VS]] = !{ptr @vs_main, ![[VSIN:[0-9]+]], ![[VARY:[0-9]+]]}
+// CHECK-DAG: ![[PS]] = !{ptr @ps_main, ![[VARY]], ![[PSOUT:[0-9]+]]}
+// CHECK-DAG: ![[VSIN]] = !{![[IA:[0-9]+]], ![[IB:[0-9]+]], ![[IC:[0-9]+]], ![[ID:[0-9]+]]}
+// CHECK-DAG: ![[VARY]] = !{![[A:[0-9]+]], ![[B:[0-9]+]], ![[C:[0-9]+]], ![[D:[0-9]+]]}
+// CHECK-DAG: ![[PSOUT]] = !{![[TARGET3:[0-9]+]], ![[TARGET0:[0-9]+]]}
+
+// Vertex inputs are stacked in declaration order regardless of packing mode.
+// CHECK-DAG: ![[IA]] = !{i32 0, !"IA", i32 9, i32 0, ![[ZERO:[0-9]+]], i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+// CHECK-DAG: ![[IB]] = !{i32 1, !"IB", i32 9, i32 0, ![[ZERO]], i32 0, i32 1, i8 2, i32 1, i8 0, i8 0, i8 0, i32 0}
+// CHECK-DAG: ![[IC]] = !{i32 2, !"IC", i32 9, i32 0, ![[ZERO]], i32 0, i32 1, i8 3, i32 2, i8 0, i8 0, i8 0, i32 0}
+// CHECK-DAG: ![[ID]] = !{i32 3, !"ID", i32 9, i32 0, ![[ZERO]], i32 0, i32 1, i8 2, i32 3, i8 0, i8 0, i8 0, i32 0}
+
+// Prefix-stable packing uses three rows: (a,b), (c), (d).
+// STABLE-DAG: ![[A]] = !{i32 0, !"A", i32 9, i32 0, ![[ZERO]], i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+// STABLE-DAG: ![[B]] = !{i32 1, !"B", i32 9, i32 0, ![[ZERO]], i32 0, i32 1, i8 2, i32 0, i8 1, i8 0, i8 0, i32 0}
+// STABLE-DAG: ![[C]] =...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/226554


More information about the llvm-commits mailing list