[clang] [llvm] [HLSL] Add the `SV_Barycentric` semantic (PR #233510)
Finn Plummer via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 23 09:57:41 PDT 2026
https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/233510
>From 0144cd43bba81f8a13b28b1d1b47970bafb75079 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:29:55 +0000
Subject: [PATCH 01/29] add interpretation kind for a semantic that is in the
signature but not packed
---
.../llvm/Frontend/HLSL/SemanticSignatures.h | 6 +++---
.../Frontend/HLSL/SemanticSignaturePacking.cpp | 10 +++++++---
llvm/lib/Frontend/HLSL/SemanticSignatures.cpp | 5 +++++
.../HLSLSemanticSignatureMetadataTest.cpp | 15 +++++++++++++++
.../Frontend/HLSLSemanticSignaturePackingTest.cpp | 13 +++++++++++++
.../unittests/Frontend/HLSLSemanticStagesTest.cpp | 14 +++++++++++++-
6 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 969da549b623f7..70407b28e82be7 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -109,6 +109,7 @@ LLVM_ABI dxbc::PSV::InterpolationMode normalizeInterpolationMode(
enum class SemanticInterpretation {
Invalid,
NotAllocated,
+ NotPacked,
Arbitrary,
SV,
SGV,
@@ -162,9 +163,8 @@ struct SemanticSignatureElement {
}
uint8_t getDeclaredMask() const {
- if (!isAllocated())
- return 0;
- return static_cast<uint8_t>(((1U << Cols) - 1U) << StartCol);
+ unsigned Column = isAllocated() ? StartCol : 0;
+ return static_cast<uint8_t>(((1U << Cols) - 1U) << Column);
}
uint8_t getAlwaysReadsMask() const { return UsageMask; }
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignaturePacking.cpp b/llvm/lib/Frontend/HLSL/SemanticSignaturePacking.cpp
index 85808e0e83f9c6..1f7b8e391910a3 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignaturePacking.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignaturePacking.cpp
@@ -158,6 +158,7 @@ getOptimizedPackingGroup(const SemanticSignatureElement &Element,
case SemanticInterpretation::SGV:
return PackingGroup::SystemGenerated;
case SemanticInterpretation::NotAllocated:
+ case SemanticInterpretation::NotPacked:
return PackingGroup::NotAllocated;
case SemanticInterpretation::Invalid:
case SemanticInterpretation::Target:
@@ -602,7 +603,8 @@ Expected<unsigned> llvm::hlsl::packSignatureStacked(
SemanticInterpretation Interpretation =
getInterpretationKind(Element.SemanticKind, ShaderStage, IOTy);
- if (Interpretation == SemanticInterpretation::NotAllocated)
+ if (Interpretation == SemanticInterpretation::NotAllocated ||
+ Interpretation == SemanticInterpretation::NotPacked)
continue;
assert((Interpretation == SemanticInterpretation::Arbitrary ||
@@ -645,7 +647,8 @@ static Expected<unsigned> packSignatureInOrder(
SemanticInterpretation Interpretation =
getInterpretationKind(Element.SemanticKind, ShaderStage, IOTy);
- if (Interpretation == SemanticInterpretation::NotAllocated)
+ if (Interpretation == SemanticInterpretation::NotAllocated ||
+ Interpretation == SemanticInterpretation::NotPacked)
continue;
assert((Interpretation == SemanticInterpretation::Arbitrary ||
@@ -718,7 +721,8 @@ Expected<unsigned> llvm::hlsl::packSignatureIndexed(
SemanticInterpretation Interpretation =
getInterpretationKind(Element.SemanticKind, ShaderStage, IOTy);
- if (Interpretation == SemanticInterpretation::NotAllocated)
+ if (Interpretation == SemanticInterpretation::NotAllocated ||
+ Interpretation == SemanticInterpretation::NotPacked)
continue;
assert(Interpretation == SemanticInterpretation::Target &&
diff --git a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
index 8a092dc4e4c067..455adba63534c6 100644
--- a/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
+++ b/llvm/lib/Frontend/HLSL/SemanticSignatures.cpp
@@ -174,6 +174,11 @@ hlsl::getAvailableStages(dxbc::PSV::SemanticKind SemanticKind) {
};
return Stages;
}
+ case dxbc::PSV::SemanticKind::Barycentrics: {
+ static constexpr SemanticStageInfo Stages[] = {
+ {Triple::Pixel, IOType::In, SemanticInterpretation::NotPacked}};
+ return Stages;
+ }
case dxbc::PSV::SemanticKind::Target: {
static constexpr SemanticStageInfo Stages[] = {
{Triple::Pixel, IOType::Out, SemanticInterpretation::Target}};
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
index e8b8448140cf8a..03370e81ed1c76 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignatureMetadataTest.cpp
@@ -224,6 +224,21 @@ TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementDerivedMasks) {
EXPECT_EQ(Elem->getNeverWritesMask(), 0xD);
}
+TEST_F(HLSLSemanticSignatureMetadataTest, UnallocatedBarycentricMasks) {
+ MDNode *Node = getElement(/*SigId=*/0, "SV_Barycentrics", /*CompType=*/9,
+ /*SemanticKind=*/28, /*Indices=*/{0},
+ /*InterpMode=*/2, /*Rows=*/1, /*Cols=*/3,
+ /*StartRow=*/UnallocatedRow,
+ /*StartCol=*/UnallocatedCol, /*UsageMask=*/0x5,
+ /*DynIndexMask=*/0, /*GSStream=*/0);
+ Expected<SemanticSignatureElement> Elem =
+ SemanticSignatureElement::fromMetadata(Node);
+ ASSERT_THAT_EXPECTED(Elem, Succeeded());
+ EXPECT_FALSE(Elem->isAllocated());
+ EXPECT_EQ(Elem->getDeclaredMask(), 0x7);
+ EXPECT_EQ(Elem->getAlwaysReadsMask(), 0x5);
+}
+
// A geometry shader output carries a non-zero stream index
TEST_F(HLSLSemanticSignatureMetadataTest, MetadataToElementGSStream) {
MDNode *Node = getElement(/*SigId=*/0, "A", /*CompType=*/9,
diff --git a/llvm/unittests/Frontend/HLSLSemanticSignaturePackingTest.cpp b/llvm/unittests/Frontend/HLSLSemanticSignaturePackingTest.cpp
index 6013c9d25500f7..080a675c6e763a 100644
--- a/llvm/unittests/Frontend/HLSLSemanticSignaturePackingTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticSignaturePackingTest.cpp
@@ -245,6 +245,19 @@ TEST_F(HLSLSemanticSignaturePackingTest, SkipsNotAllocatedElements) {
{{/*Row=*/1, /*Col=*/0}, Unallocated, {/*Row=*/0, /*Col=*/0}});
}
+TEST_F(HLSLSemanticSignaturePackingTest, BarycentricsDoNotReserveRegisters) {
+ TestConfig Config(
+ Triple::Pixel, IOType::In,
+ {{dxbc::PSV::SemanticKind::Barycentrics, /*Rows=*/1, /*Cols=*/3,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::Arbitrary, /*Rows=*/32, /*Cols=*/4,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear}});
+ for (PackingMethod Method :
+ {PackingMethod::PrefixStable, PackingMethod::Optimized})
+ verifyPacking(Method, Config, /*ExpectedRows=*/32,
+ {Unallocated, {/*Row=*/0, /*Col=*/0}});
+}
+
TEST_F(HLSLSemanticSignaturePackingTest, StacksInDeclarationOrder) {
// Elements are assigned whole rows in declaration order, regardless of their
// semantic interpretation.
diff --git a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
index 21c20cf8349698..3e6249ff5183b4 100644
--- a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
@@ -22,6 +22,8 @@ static StringRef getInterpretationName(SemanticInterpretation Interpretation) {
return "Invalid";
case SemanticInterpretation::NotAllocated:
return "NotAllocated";
+ case SemanticInterpretation::NotPacked:
+ return "NotPacked";
case SemanticInterpretation::Arbitrary:
return "Arbitrary";
case SemanticInterpretation::SV:
@@ -65,7 +67,7 @@ constexpr SemanticKind SupportedKinds[] = {
SemanticKind::InsideTessFactor, SemanticKind::DispatchThreadID,
SemanticKind::GroupID, SemanticKind::GroupIndex,
SemanticKind::GroupThreadID, SemanticKind::InstanceID,
- SemanticKind::ShadingRate};
+ SemanticKind::ShadingRate, SemanticKind::Barycentrics};
// Ensure all stages return a valid SemanticInterpretation
TEST(HLSLSemanticStagesTest, StagesAreValid) {
@@ -153,4 +155,14 @@ TEST(HLSLSemanticStagesTest, ShadingRateSignaturePoints) {
expectOnlySignaturePoints(SemanticKind::ShadingRate, Valid);
}
+TEST(HLSLSemanticStagesTest, BarycentricsAreUnpackedPixelInputs) {
+ for (Triple::EnvironmentType Stage : AllStages)
+ for (IOType IO : {IOType::In, IOType::Out,
+ IOType::PatchConstantOrPrimitive})
+ EXPECT_EQ(getInterpretationKind(SemanticKind::Barycentrics, Stage, IO),
+ Stage == Triple::Pixel && IO == IOType::In
+ ? SemanticInterpretation::NotPacked
+ : SemanticInterpretation::Invalid);
+}
+
} // namespace
>From 64a6849705da1b216afd2919268ec1bd73529c89 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:01 +0000
Subject: [PATCH 02/29] add frontend diags
---
.../clang/Basic/DiagnosticSemaKinds.td | 6 +-
clang/include/clang/Sema/SemaHLSL.h | 3 +
clang/lib/Sema/SemaHLSL.cpp | 38 +++++++--
.../SV_Barycentrics-shader-model.hlsl | 6 ++
.../SemaHLSL/Semantics/SV_Barycentrics.hlsl | 83 +++++++++++++++++++
5 files changed, 127 insertions(+), 9 deletions(-)
create mode 100644 clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
create mode 100644 clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f0e06e314e3c29..dcb5732c3c19e7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13780,8 +13780,8 @@ def err_hlsl_attribute_param_mismatch : Error<"%0 attribute parameters do not ma
def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier %0">;
def err_hlsl_interpolation_conflict : Error<
"'nointerpolation' cannot be combined with other interpolation modifiers">;
-def err_hlsl_interpolation_position : Error<
- "'nointerpolation' cannot be used on SV_Position">;
+def err_hlsl_interpolation_semantic : Error<
+ "'nointerpolation' cannot be used on %0">;
def err_hlsl_interpolation_type : Error<
"interpolation modifiers other than 'nointerpolation' cannot be used with type %0">;
def warn_hlsl_duplicate_interpolation : Warning<
@@ -13807,7 +13807,7 @@ def err_hlsl_semantic_64bit_type
"or outputs (was %1)">;
def err_hlsl_semantic_invalid_type
: Error<"semantic %0 must be a "
- "%select{scalar|scalar or vector of up to %2 components}1 of "
+ "%select{scalar|scalar or vector of up to %2 components|vector of %2 components}1 of "
"%select{16 or 32 bit integer|32 bit integer|"
"16 or 32 bit floating-point|16 or 32 bit unsigned integer|"
"32 bit unsigned integer}3 type (was %4)">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 00be1b9b06e911..6a4709ed06d119 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -342,6 +342,9 @@ class SemaHLSL : public SemaBase {
void diagnoseSemanticType(const Decl *D, const HLSLAppliedSemanticAttr *A,
llvm::dxbc::PSV::SemanticKind SemanticKind);
+ void diagnoseSemanticShaderModel(const HLSLAppliedSemanticAttr *A,
+ llvm::dxbc::PSV::SemanticKind SemanticKind);
+
void handleGlobalStructOrArrayOfWithResources(VarDecl *VD);
// Infer a common global binding info for an Expr
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 87fe8ee53235a0..14a810ac2ce6aa 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -916,12 +916,13 @@ bool SemaHLSL::checkInterpolationModifiers(
auto Modifiers = static_cast<InterpolationModifier>(A->getModifiers());
if (Modifiers == InterpolationModifier::NoInterpolation) {
- bool IsPosition =
- Semantic && llvm::hlsl::getSemanticKind(Semantic->getSemanticName()) ==
- SemanticKind::Position;
- if (!IsPosition)
+ if (!Semantic)
return true;
- Diag(A->getLocation(), diag::err_hlsl_interpolation_position);
+ SemanticKind Kind = llvm::hlsl::getSemanticKind(Semantic->getSemanticName());
+ if (Kind != SemanticKind::Position && Kind != SemanticKind::Barycentrics)
+ return true;
+ Diag(A->getLocation(), diag::err_hlsl_interpolation_semantic)
+ << Semantic->getSemanticName();
Diag(Semantic->getLocation(), diag::note_conflicting_attribute);
return false;
}
@@ -1012,6 +1013,8 @@ static bool isVkPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD,
// TODO: extend to mesh
return (ST == llvm::Triple::Pixel && IsInput) ||
(ST == llvm::Triple::Vertex && !IsInput);
+ case SemanticKind::Barycentrics:
+ return ST == llvm::Triple::Pixel && IsInput;
default:
return false;
}
@@ -1272,6 +1275,24 @@ void SemaHLSL::checkSemanticAnnotation(
diagnoseSystemSemanticIndex(SemanticAttr, Kind, ElementCount);
diagnoseSemanticType(Param, SemanticAttr, Kind);
+ diagnoseSemanticShaderModel(SemanticAttr, Kind);
+}
+
+void SemaHLSL::diagnoseSemanticShaderModel(
+ const HLSLAppliedSemanticAttr *A, SemanticKind Kind) {
+ const auto &Triple = getASTContext().getTargetInfo().getTriple();
+ if (!Triple.isDXIL())
+ return;
+
+ switch (Kind) {
+ case SemanticKind::Barycentrics:
+ if (Triple.getOSVersion() < VersionTuple(6, 1))
+ Diag(A->getLoc(), diag::err_hlsl_attribute_in_wrong_shader_model)
+ << A->getAttrName() << "6.1";
+ return;
+ default:
+ return;
+ }
}
void SemaHLSL::diagnoseSystemSemanticIndex(const HLSLAppliedSemanticAttr *A,
@@ -1370,6 +1391,12 @@ void SemaHLSL::diagnoseSemanticType(const Decl *D,
bool IsSPIRV = getASTContext().getTargetInfo().getTriple().isSPIRV();
switch (Kind) {
+ case SemanticKind::Barycentrics:
+ if (DeclaredTy != T || !isFloatOrHalfElement(ElemTy) || Components != 3)
+ Diag(A->getLoc(), diag::err_hlsl_semantic_invalid_type)
+ << A->getAttrName() << /* vector of */ 2 << 3
+ << /* 16 or 32 bit floating-point */ 2 << DeclaredTy;
+ return;
case SemanticKind::DispatchThreadID:
case SemanticKind::GroupID:
case SemanticKind::GroupThreadID:
@@ -2225,7 +2252,6 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) {
case SemanticKind::TessFactor:
case SemanticKind::InsideTessFactor:
case SemanticKind::ViewID:
- case SemanticKind::Barycentrics:
case SemanticKind::CullPrimitive:
Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
return;
diff --git a/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl b/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
new file mode 100644
index 00000000000000..f947d3709a83b2
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -finclude-default-header -fsyntax-only -verify=old %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -fsyntax-only -verify=valid %s
+// valid-no-diagnostics
+
+float4 main(float3 b : SV_Barycentrics) : SV_Target { return float4(b, 1); }
+// old-error at -1 {{attribute 'SV_Barycentrics' requires shader model 6.1 or greater}}
diff --git a/clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl b/clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl
new file mode 100644
index 00000000000000..dfc945e1f6e9e2
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-library -fnative-half-type -fnative-int16-type -finclude-default-header -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -DSPIRV -fnative-half-type -fnative-int16-type -finclude-default-header -fsyntax-only -verify %s
+
+[shader("pixel")]
+float4 valid(float3 p : SV_Barycentrics0) : SV_Target {
+ return float4(p, 1);
+}
+[shader("pixel")]
+void affine(noperspective float3 p : sv_barycentrics) {}
+[shader("pixel")]
+void centroid_input(centroid float3 p : SV_Barycentrics) {}
+[shader("pixel")]
+void sample_input(sample noperspective float3 p : SV_Barycentrics) {}
+[shader("pixel")]
+void half_vector(half3 b : SV_Barycentrics) {}
+
+[shader("pixel")]
+void scalar(float b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+[shader("pixel")]
+void short_vector(float2 b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+[shader("pixel")]
+void long_vector(float4 b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+[shader("pixel")]
+void double_vector(double3 b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+[shader("pixel")]
+void integer_vector(uint3 b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+[shader("pixel")]
+void matrix(float1x3 b : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+// expected-error at -2 {{semantic 'SV_Barycentrics' does not allow indexing}}
+[shader("pixel")]
+void array(float3 b[2] : SV_Barycentrics) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' must be a vector of 3 components of 16 or 32 bit floating-point type}}
+// expected-error at -2 {{semantic 'SV_Barycentrics' does not allow indexing}}
+
+[shader("pixel")]
+void bad_index_one(float3 b : SV_Barycentrics1) {}
+// expected-error at -1 {{semantic 'SV_Barycentrics' does not allow indexing}}
+
+[shader("pixel")]
+void flat(nointerpolation float3 b : SV_Barycentrics) {} // expected-note {{conflicting attribute is here}}
+// expected-error at -1 {{'nointerpolation' cannot be used on SV_Barycentrics}}
+
+[shader("pixel")]
+void same_index(float3 p : SV_Barycentrics, // expected-note {{previous use is here}}
+ noperspective float3 q : SV_Barycentrics0) {} // expected-note {{'q' declared here}}
+// expected-error at -1 {{semantic index overlap SV_Barycentrics0}}
+
+struct Input {
+ float3 b : SV_Barycentrics; // expected-note {{conflicting attribute is here}}
+};
+[shader("pixel")]
+void inherited_flat(nointerpolation Input i) {}
+// expected-error at -1 {{'nointerpolation' cannot be used on SV_Barycentrics}}
+
+struct AffineInput {
+ noperspective float3 b : SV_Barycentrics;
+};
+[shader("pixel")]
+void inherited_affine(noperspective Input i) {}
+[shader("pixel")]
+void field_override(linear AffineInput i) {}
+
+[shader("vertex")]
+float4 wrong_stage(float3 b : SV_Barycentrics) : SV_Position { return 0; }
+// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in vertex shader inputs}}
+
+[shader("pixel")]
+float3 wrong_output() : SV_Barycentrics { return 0; }
+// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in pixel shader outputs}}
+
+#ifdef SPIRV
+[shader("pixel")]
+float4 explicit_location(float3 b : SV_Barycentrics,
+ [[vk::location(3)]] float x : VALUE) : SV_Target {
+ return float4(b, x);
+}
+#endif
>From 3c9f973c1289c8f4ae11fd285788dd419f6e1b23 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:07 +0000
Subject: [PATCH 03/29] lower barycentric inputs to DXIL and SPIR-V
---
clang/include/clang/Basic/AttrDocs.td | 3 +
clang/lib/CodeGen/CGHLSLRuntime.cpp | 39 +++++++++++
.../semantics/SV_Barycentrics-half.ps.hlsl | 27 ++++++++
.../semantics/SV_Barycentrics.ps.hlsl | 64 +++++++++++++++++++
4 files changed, 133 insertions(+)
create mode 100644 clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/SV_Barycentrics.ps.hlsl
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 02b7466c679520..687e022c7bd61f 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -9436,6 +9436,9 @@ For SPIR-V targets, `nointerpolation`, `noperspective`, `centroid`, and `sample`
emit `Flat`, `NoPerspective`, `Centroid`, and `Sample` decorations, respectively.
`linear` and `center` use the SPIR-V defaults and require no decoration.
Sample-qualified interfaces also require the `SampleRateShading` capability.
+For `SV_Barycentrics` inputs, `noperspective` selects the `BaryCoordNoPerspKHR`
+built-in instead of adding a `NoPerspective` decoration; `centroid` and `sample`
+still decorate the selected built-in.
}];
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index e576505a733a18..4375a7275dd660 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1094,6 +1094,7 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
return B.CreateTrunc(B.CreateCall(F, {B.getInt32(0)}), Ty);
}
+
// A fragment shader input interface variable whose base type is an integer or
// a 64-bit float (double) cannot be interpolated by the rasterizer. The Vulkan
// specification requires these variables to be decorated with Flat (see
@@ -1505,6 +1506,44 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
llvm::Triple::EnvironmentType Stage, std::optional<unsigned> Index,
SemanticSignatures &Signature, llvm::hlsl::InterpolationMode InterpMode) {
switch (SemanticKind) {
+ case llvm::dxbc::PSV::SemanticKind::Barycentrics:
+ assert(Stage == llvm::Triple::Pixel &&
+ "SV_Barycentrics is only available as a pixel shader input");
+ if (CGM.getTarget().getTriple().isSPIRV()) {
+ using llvm::dxbc::PSV::InterpolationMode;
+ // Perspective is encoded by the built-in; only sampling decorations
+ // belong on the interface variable.
+ bool NoPerspective = false;
+ switch (InterpMode) {
+ case InterpolationMode::LinearNoperspective:
+ NoPerspective = true;
+ InterpMode = InterpolationMode::Linear;
+ break;
+ case InterpolationMode::LinearNoperspectiveCentroid:
+ NoPerspective = true;
+ InterpMode = InterpolationMode::LinearCentroid;
+ break;
+ case InterpolationMode::LinearNoperspectiveSample:
+ NoPerspective = true;
+ InterpMode = InterpolationMode::LinearSample;
+ break;
+ default:
+ break;
+ }
+ // SPIR-V barycentric built-ins are float3, even for half3 inputs.
+ llvm::Type *BuiltinType = llvm::FixedVectorType::get(CGM.FloatTy, 3);
+ llvm::Value *Barycentrics = createSPIRVBuiltinLoad(
+ B, CGM.getModule(), BuiltinType, Semantic->getSemanticName(),
+ NoPerspective ? /* BuiltIn::BaryCoordNoPerspKHR */ 5287
+ : /* BuiltIn::BaryCoordKHR */ 5286,
+ InterpMode);
+ if (Type->getScalarType()->isHalfTy())
+ return B.CreateFPTrunc(Barycentrics, Type);
+ return Barycentrics;
+ }
+ if (CGM.getTarget().getTriple().isDXIL())
+ return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature);
+ break;
case llvm::dxbc::PSV::SemanticKind::GroupIndex: {
assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
llvm::Triple::Amplification},
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
new file mode 100644
index 00000000000000..f61da29007dd8a
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=DXIL
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,PERSPECTIVE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -DAFFINE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,AFFINE
+
+#ifdef AFFINE
+#define INTERPOLATION noperspective
+#else
+#define INTERPOLATION linear
+#endif
+
+half4 main(INTERPOLATION half3 barycentrics : SV_Barycentrics) : SV_Target {
+ return half4(barycentrics, 1);
+}
+
+// DXIL-LABEL: define void @main()
+// DXIL: call <3 x half> @llvm.dx.load.input.v3f16(i32 0, i32 0, i8 0, i32 poison)
+// DXIL-NOT: @llvm.dx.load.input.v3f32
+
+// The SPIR-V built-in must remain float3, not half3. Only the loaded value
+// is truncated to the HLSL input's component type.
+// SPIRV: @SV_Barycentrics = external hidden thread_local addrspace(7) externally_initialized constant <3 x float>, !spirv.Decorations ![[BARY:[0-9]+]]
+// SPIRV-LABEL: define void @main()
+// SPIRV: [[BARY32:%.*]] = load <3 x float>, ptr addrspace(7) @SV_Barycentrics
+// SPIRV-NEXT: [[BARY16:%.*]] = fptrunc <3 x float> [[BARY32]] to <3 x half>
+// SPIRV: ![[BARY]] = !{![[BUILTIN:[0-9]+]]}
+// PERSPECTIVE: ![[BUILTIN]] = !{i32 11, i32 5286}
+// AFFINE: ![[BUILTIN]] = !{i32 11, i32 5287}
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Barycentrics.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics.ps.hlsl
new file mode 100644
index 00000000000000..e4652664167780
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics.ps.hlsl
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,AFFINE-CENTER
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -DPERSPECTIVE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,PERSPECTIVE-CENTER
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -DCENTROID -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,AFFINE-CENTROID
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -DPERSPECTIVE -DCENTROID -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,PERSPECTIVE-CENTROID
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -DSAMPLE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,AFFINE-SAMPLE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -DPERSPECTIVE -DSAMPLE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,PERSPECTIVE-SAMPLE
+// SPIR-V builtin selection and sampling decorations are independent.
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-AFFINE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -DPERSPECTIVE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-PERSPECTIVE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -DCENTROID -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-AFFINE,SPIRV-CENTROID
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -DPERSPECTIVE -DSAMPLE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-PERSPECTIVE,SPIRV-SAMPLE
+
+#ifdef CENTROID
+#define SAMPLING centroid
+#elif defined(SAMPLE)
+#define SAMPLING sample
+#else
+#define SAMPLING
+#endif
+#ifdef PERSPECTIVE
+#define INTERPOLATION linear
+#elif defined(CENTROID) || defined(SAMPLE)
+#define INTERPOLATION noperspective
+#else
+#define INTERPOLATION
+#endif
+
+struct Inputs {
+ SAMPLING INTERPOLATION float3 barycentrics : SV_Barycentrics0;
+ float value : VALUE;
+};
+
+// The parameter's noperspective is inherited unless the field overrides it.
+// Each entry has exactly one barycentric input, which consumes no packed row
+// or SPIR-V location.
+float4 main(noperspective Inputs input) : SV_Target {
+ return float4(input.barycentrics, input.value);
+}
+
+// DXIL-LABEL: define void @main()
+// DXIL: call <3 x float> @llvm.dx.load.input.v3f32(i32 0, i32 0, i8 0, i32 poison)
+// DXIL: call float @llvm.dx.load.input.f32(i32 1, i32 0, i8 0, i32 poison)
+// AFFINE-CENTER-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 4, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// PERSPECTIVE-CENTER-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// AFFINE-CENTROID-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 5, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// PERSPECTIVE-CENTROID-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 3, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// AFFINE-SAMPLE-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 7, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// PERSPECTIVE-SAMPLE-DAG: !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !{{[0-9]+}}, i32 6, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// DXIL-DAG: !{i32 1, !"VALUE", i32 9, i32 0, ![[ZERO:[0-9]+]], i32 4, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+// DXIL-DAG: ![[ZERO]] = !{i32 0}
+
+// SPIRV-DAG: @SV_Barycentrics = external hidden thread_local addrspace(7) externally_initialized constant <3 x float>, !spirv.Decorations ![[BARY:[0-9]+]]
+// SPIRV-DAG: @VALUE0 = {{.*}} !spirv.Decorations ![[VALUE:[0-9]+]]
+// SPIRV-LABEL: define void @main()
+// SPIRV: load <3 x float>, ptr addrspace(7) @SV_Barycentrics
+// SPIRV-NOT: fptrunc
+// SPIRV-DAG: ![[BARY]] = !{![[BUILTIN:[0-9]+]]{{.*}}}
+// SPIRV-DAG: ![[VALUE]] = !{![[VALUE_LOCATION:[0-9]+]], ![[NOPERSP:[0-9]+]]}
+// SPIRV-AFFINE-DAG: ![[BUILTIN]] = !{i32 11, i32 5287}
+// SPIRV-PERSPECTIVE-DAG: ![[BUILTIN]] = !{i32 11, i32 5286}
+// SPIRV-DAG: ![[VALUE_LOCATION]] = !{i32 30, i32 0}
+// SPIRV-DAG: ![[NOPERSP]] = !{i32 13}
+// SPIRV-CENTROID-DAG: !{i32 16}
+// SPIRV-SAMPLE-DAG: !{i32 17}
>From 2b5d67db907515a159ba2970d7626d3029578102 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:17 +0000
Subject: [PATCH 04/29] review: update diagnose naming for semantic checks
---
llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index 83a3a4a47fd05a..ffe2e620934888 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -69,7 +69,7 @@ static bool isIntegerComponent(ElementType Type) {
Type == ElementType::U32;
}
-static Error validateSemanticType(const SemanticSignatureElement &E) {
+static Error diagnoseSemanticType(const SemanticSignatureElement &E) {
switch (E.SemanticKind) {
case dxbc::PSV::SemanticKind::Position:
if (E.Rows != 1 || E.Cols != 4 ||
@@ -102,7 +102,7 @@ static Error validateSemanticType(const SemanticSignatureElement &E) {
return Error::success();
}
-static Error validateSemanticIndex(const SemanticSignatureElement &E) {
+static Error diagnoseSemanticIndex(const SemanticSignatureElement &E) {
switch (E.SemanticKind) {
case dxbc::PSV::SemanticKind::Target:
if (E.Rows != 1 || E.SemanticIndices.front() >= 8)
@@ -185,9 +185,9 @@ static Error parseSignature(Metadata *MD,
for (uint32_t Index : E.SemanticIndices)
if (!Semantics.emplace(E.SemanticName.upper(), Index).second)
return signatureError("duplicate semantic name and index");
- if (Error Err = validateSemanticType(E))
+ if (Error Err = diagnoseSemanticType(E))
return Err;
- if (Error Err = validateSemanticIndex(E))
+ if (Error Err = diagnoseSemanticIndex(E))
return Err;
if (Stage == Triple::Vertex && IO == IOType::In &&
>From 7ed8fa0202a70807dbb985e7798bed7a86f5e1a5 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:17 +0000
Subject: [PATCH 05/29] add directx backend diags
---
.../Target/DirectX/DXILSignatureAnalysis.cpp | 115 +++++++++-----
...semantic-signatures-barycentrics-errors.ll | 148 ++++++++++++++++++
2 files changed, 228 insertions(+), 35 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index ffe2e620934888..7ad0a602665b5f 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -96,6 +96,12 @@ static Error diagnoseSemanticType(const SemanticSignatureElement &E) {
return signatureError(
"SV_ShadingRate requires a scalar 16- or 32-bit unsigned integer");
break;
+ case dxbc::PSV::SemanticKind::Barycentrics:
+ if (E.Rows != 1 || E.Cols != 3 ||
+ (E.CompType != ElementType::F16 && E.CompType != ElementType::F32))
+ return signatureError("SV_Barycentrics requires one row of three 16- or "
+ "32-bit floating-point components");
+ break;
default:
break;
}
@@ -113,6 +119,24 @@ static Error diagnoseSemanticIndex(const SemanticSignatureElement &E) {
if (E.SemanticIndices.front() != 0)
return signatureError("SV_VertexID requires semantic index 0");
break;
+ case dxbc::PSV::SemanticKind::Barycentrics:
+ if (E.SemanticIndices.front() != 0)
+ return signatureError("SV_Barycentrics requires semantic index 0");
+ break;
+ default:
+ break;
+ }
+ return Error::success();
+}
+
+static Error
+diagnoseSemanticShaderModel(const SemanticSignatureElement &E,
+ const VersionTuple &ShaderModelVersion) {
+ switch (E.SemanticKind) {
+ case dxbc::PSV::SemanticKind::Barycentrics:
+ if (ShaderModelVersion < VersionTuple(6, 1))
+ return signatureError("SV_Barycentrics requires shader model 6.1");
+ break;
default:
break;
}
@@ -123,6 +147,7 @@ static Error parseSignature(Metadata *MD,
SmallVectorImpl<SemanticSignatureElement> &Out,
ModuleSignatureInfo &Info,
Triple::EnvironmentType Stage, IOType IO,
+ const VersionTuple &ShaderModelVersion,
bool Native16, unsigned &Extent) {
if (!MD)
return Error::success();
@@ -172,13 +197,19 @@ static Error parseSignature(Metadata *MD,
if (E.SemanticKind != ExpectedKind)
return signatureError("semantic name and kind disagree at this signature "
"point");
- if (!E.isAllocated())
- return signatureError("signature element " + Twine(E.SigId) + " ('" +
- E.SemanticName + "') has no allocated location");
- if (E.StartRow >= MaxSignatureRows ||
- E.Rows > MaxSignatureRows - E.StartRow || E.StartCol + E.Cols > 4)
- return signatureError(
- "allocated signature element exceeds register bounds");
+ if (Interpretation == SemanticInterpretation::NotPacked) {
+ if (E.isAllocated())
+ return signatureError(
+ "SV_Barycentrics must not have an allocated location");
+ } else {
+ if (!E.isAllocated())
+ return signatureError("signature element " + Twine(E.SigId) + " ('" +
+ E.SemanticName + "') has no allocated location");
+ if (E.StartRow >= MaxSignatureRows ||
+ E.Rows > MaxSignatureRows - E.StartRow || E.StartCol + E.Cols > 4)
+ return signatureError(
+ "allocated signature element exceeds register bounds");
+ }
if (E.InterpMode == dxbc::PSV::InterpolationMode::Invalid)
return signatureError("invalid interpolation mode");
@@ -189,6 +220,14 @@ static Error parseSignature(Metadata *MD,
return Err;
if (Error Err = diagnoseSemanticIndex(E))
return Err;
+ if (Error Err = diagnoseSemanticShaderModel(E, ShaderModelVersion))
+ return Err;
+ if (E.SemanticKind == dxbc::PSV::SemanticKind::Barycentrics) {
+ using Mode = dxbc::PSV::InterpolationMode;
+ if (E.InterpMode == Mode::Undefined || E.InterpMode == Mode::Constant)
+ return signatureError(
+ "SV_Barycentrics requires perspective or noperspective interpolation");
+ }
if (Stage == Triple::Vertex && IO == IOType::In &&
(E.StartRow != Extent || E.StartCol != 0))
@@ -205,29 +244,31 @@ static Error parseSignature(Metadata *MD,
return signatureError(
"integer pixel inputs require constant interpolation");
- // Co-packed elements must obey row constraints, even when their component
- // masks do not overlap. Min-precision types occupy 32-bit components.
- bool IsNative16 = Native16 && (E.CompType == ElementType::F16 ||
- E.CompType == ElementType::I16 ||
- E.CompType == ElementType::U16);
- uint8_t Mask = E.getDeclaredMask();
- for (unsigned Row = E.StartRow; Row != E.StartRow + E.Rows; ++Row) {
- if (AllocatedColumns[Row] & Mask)
- return signatureError("signature elements overlap at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
- if (AllocatedColumns[Row] && RowModes[Row] != E.InterpMode)
- return signatureError("signature elements have different interpolation "
- "modes at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
- if (AllocatedColumns[Row] && RowNative16[Row] != IsNative16)
- return signatureError("signature elements have different component "
- "widths at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
- AllocatedColumns[Row] |= Mask;
- RowModes[Row] = E.InterpMode;
- RowNative16[Row] = IsNative16;
+ if (E.isAllocated()) {
+ // Co-packed elements must obey row constraints, even when their component
+ // masks do not overlap. Min-precision types occupy 32-bit components.
+ bool IsNative16 = Native16 && (E.CompType == ElementType::F16 ||
+ E.CompType == ElementType::I16 ||
+ E.CompType == ElementType::U16);
+ uint8_t Mask = E.getDeclaredMask();
+ for (unsigned Row = E.StartRow; Row != E.StartRow + E.Rows; ++Row) {
+ if (AllocatedColumns[Row] & Mask)
+ return signatureError("signature elements overlap at row " +
+ Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ if (AllocatedColumns[Row] && RowModes[Row] != E.InterpMode)
+ return signatureError("signature elements have different interpolation "
+ "modes at row " +
+ Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ if (AllocatedColumns[Row] && RowNative16[Row] != IsNative16)
+ return signatureError("signature elements have different component "
+ "widths at row " +
+ Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ AllocatedColumns[Row] |= Mask;
+ RowModes[Row] = E.InterpMode;
+ RowNative16[Row] = IsNative16;
+ }
+ Extent = std::max(Extent, E.StartRow + E.Rows);
}
- Extent = std::max(Extent, E.StartRow + E.Rows);
E.SemanticName = Info.Names.insert(E.SemanticName).first->getKey();
// Access masks will be recomputed so reset to 0 here.
@@ -296,7 +337,7 @@ static Error analyzeAccess(const IntrinsicInst &I, EntrySignature &Sig) {
if (!CorrectType)
return AccessError("signature access type disagrees with its element");
uint8_t Mask = ((1U << Width) - 1) << Col->getZExtValue();
- E.UsageMask |= Mask << E.StartCol;
+ E.UsageMask |= Mask << (E.isAllocated() ? E.StartCol : 0);
if (!Row)
E.DynIndexMask |= Mask;
return Error::success();
@@ -312,7 +353,9 @@ static void buildDependencyMap(EntrySignature &Sig) {
// dependencies without incorrectly claiming that unknown dependencies are
// absent. Unused components and padding remain zero. Both DXIL and PSV use
// this same map; a more precise dependency analysis can refine it later.
- for (const auto &Input : Sig.Inputs)
+ for (const auto &Input : Sig.Inputs) {
+ if (!Input.isAllocated())
+ continue;
for (unsigned IR = 0; IR != Input.Rows; ++IR)
for (unsigned IC = 0; IC != 4; ++IC) {
if (!(Input.UsageMask & (1U << IC)))
@@ -327,6 +370,7 @@ static void buildDependencyMap(EntrySignature &Sig) {
Sig.InputOutputMap[Base + Bit / 32] |= 1U << (Bit % 32);
}
}
+ }
}
static Expected<ModuleSignatureInfo>
@@ -364,11 +408,12 @@ analyzeModule(Module &M, const ModuleMetadataInfo &MMI) {
};
if (Error Err =
parseSignature(Record->getOperand(1), Sig.Inputs, Info, Sig.Stage,
- IOType::In, Sig.UseNative16Bit, Sig.InputVectors))
+ IOType::In, MMI.ShaderModelVersion,
+ Sig.UseNative16Bit, Sig.InputVectors))
return AddContext(std::move(Err), "input");
- if (Error Err = parseSignature(Record->getOperand(2), Sig.Outputs, Info,
- Sig.Stage, IOType::Out, Sig.UseNative16Bit,
- Sig.OutputVectors))
+ if (Error Err = parseSignature(
+ Record->getOperand(2), Sig.Outputs, Info, Sig.Stage, IOType::Out,
+ MMI.ShaderModelVersion, Sig.UseNative16Bit, Sig.OutputVectors))
return AddContext(std::move(Err), "output");
for (const Instruction &I : instructions(F))
if (auto *II = dyn_cast<IntrinsicInst>(&I);
diff --git a/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
new file mode 100644
index 00000000000000..f0aa56910b5384
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
@@ -0,0 +1,148 @@
+; RUN: split-file %s %t
+; RUN: cat %t/common.ll %t/integer.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
+; RUN: cat %t/common.ll %t/cols.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
+; RUN: cat %t/common.ll %t/rows.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
+; RUN: cat %t/common.ll %t/index.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INDEX
+; RUN: cat %t/common.ll %t/constant.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INTERPOLATION
+; RUN: cat %t/common.ll %t/undefined.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INTERPOLATION
+; RUN: cat %t/common.ll %t/allocated.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ALLOCATED
+; RUN: cat %t/common.ll %t/duplicate-index.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=DUPLICATE
+; RUN: cat %t/common.ll %t/id.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ID
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/vertex.ll 2>&1 | FileCheck %s --check-prefix=STAGE
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/output.ll 2>&1 | FileCheck %s --check-prefix=STAGE
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/sm60.ll 2>&1 | FileCheck %s --check-prefix=SM
+; RUN: cat %t/access-common.ll %t/access-type.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-TYPE
+; RUN: cat %t/access-common.ll %t/access-col.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-COL
+; RUN: cat %t/access-common.ll %t/access-row.ll > %t/test.ll
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-ROW
+
+; TYPE: SV_Barycentrics requires one row of three 16- or 32-bit floating-point components
+; INDEX: SV_Barycentrics requires semantic index 0
+; INTERPOLATION: SV_Barycentrics requires perspective or noperspective interpolation
+; ALLOCATED: SV_Barycentrics must not have an allocated location
+; DUPLICATE: duplicate semantic name and index
+; ID: signature IDs must be dense and in list order
+; STAGE: invalid or unsupported semantic for this stage and signature category
+; SM: SV_Barycentrics requires shader model 6.1
+; ACCESS-TYPE: input signature element 0 ('SV_Barycentrics'): signature access type disagrees with its element
+; ACCESS-COL: input signature element 0 ('SV_Barycentrics'): signature access has an invalid component index
+; ACCESS-ROW: input signature element 0 ('SV_Barycentrics'): signature access has an invalid row index
+
+;--- common.ll
+; Individual cases supply the element list so malformed unallocated elements
+; must undergo the same semantic validation as packed elements.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!3 = !{i32 0}
+
+;--- integer.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 5, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- cols.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 2, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- rows.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !5, i32 2, i32 2, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!5 = !{i32 0, i32 1}
+
+;--- index.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !5, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!5 = !{i32 1}
+
+;--- constant.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 1, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- undefined.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 0, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- allocated.ll
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 0, i8 0, i8 0, i8 0, i32 0}
+
+;--- duplicate-index.ll
+!1 = !{!2, !5}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!5 = !{i32 1, !"sv_barycentrics", i32 9, i32 28, !3, i32 4, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- id.ll
+; An unallocated element still occupies ID 0, so the next ID must be 1.
+!1 = !{!2, !5}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!5 = !{i32 2, !"A", i32 9, i32 0, !3, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+
+;--- vertex.ll
+target triple = "dxil-pc-shadermodel6.1-vertex"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="vertex" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+;--- output.ll
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, null, !1}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+;--- sm60.ll
+target triple = "dxil-pc-shadermodel6.0-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+;--- access-common.ll
+target triple = "dxil-pc-shadermodel6.1-pixel"
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+;--- access-type.ll
+define void @main() #0 {
+ %x = call half @llvm.dx.load.input.f16(i32 0, i32 0, i8 0, i32 poison)
+ ret void
+}
+
+;--- access-col.ll
+define void @main() #0 {
+ %x = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 3, i32 poison)
+ ret void
+}
+
+;--- access-row.ll
+define void @main() #0 {
+ %x = call float @llvm.dx.load.input.f32(i32 0, i32 1, i8 0, i32 poison)
+ ret void
+}
>From d72f07f24e260113dec088b248eb2f4fdbb9e437 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:17 +0000
Subject: [PATCH 06/29] update serialization for unallocated signature elements
---
.../Target/DirectX/DXILSignatureAnalysis.cpp | 17 +++-
.../SemanticSignatures-barycentrics-half.ll | 78 +++++++++++++++++++
.../SemanticSignatures-barycentrics.ll | 72 +++++++++++++++++
3 files changed, 163 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index 7ad0a602665b5f..2da5eb99c0f18a 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -471,7 +471,8 @@ static MDNode *emitSignature(LLVMContext &Ctx,
if (E.UsageMask &&
(ValidatorVersion.empty() || ValidatorVersion == VersionTuple(0, 0) ||
ValidatorVersion >= VersionTuple(1, 5)))
- Props.append({I32(3), I32(E.UsageMask >> E.StartCol)});
+ Props.append(
+ {I32(3), I32(E.UsageMask >> (E.isAllocated() ? E.StartCol : 0))});
Nodes.push_back(MDNode::get(
Ctx, {I32(E.SigId), MDString::get(Ctx, E.SemanticName),
I8(static_cast<uint8_t>(E.CompType)),
@@ -526,6 +527,8 @@ static dxbc::D3DSystemValue getSystemValue(dxbc::PSV::SemanticKind Kind) {
return dxbc::D3DSystemValue::Target;
case KindTy::ShadingRate:
return dxbc::D3DSystemValue::ShadingRate;
+ case KindTy::Barycentrics:
+ return dxbc::D3DSystemValue::Barycentrics;
default:
llvm_unreachable("validated vertex/pixel signature semantic");
}
@@ -556,6 +559,8 @@ static StringRef getContainerSemanticName(const SemanticSignatureElement &E) {
return "SV_Target";
case Kind::ShadingRate:
return "SV_ShadingRate";
+ case Kind::Barycentrics:
+ return "SV_Barycentrics";
default:
llvm_unreachable("validated vertex/pixel signature semantic");
}
@@ -573,7 +578,8 @@ static void buildSignature(mcdxbc::Signature &Sig,
for (auto [Row, Index] : enumerate(E.SemanticIndices))
Sig.addParam(E.GSStream, getContainerSemanticName(E), Index,
getSystemValue(E.SemanticKind),
- getComponentType(E.CompType, Legacy), E.StartRow + Row, Mask,
+ getComponentType(E.CompType, Legacy),
+ E.isAllocated() ? E.StartRow + Row : UnallocatedRow, Mask,
ExclusiveMask, E.getMinPrecision(!Native16));
}
}
@@ -587,8 +593,11 @@ static void buildPSVElements(SmallVectorImpl<mcdxbc::PSVSignatureElement> &Dest,
Dest.push_back({E.SemanticKind == dxbc::PSV::SemanticKind::Arbitrary
? E.SemanticName
: StringRef(),
- E.SemanticIndices, static_cast<uint8_t>(E.StartRow), E.Cols,
- E.StartCol, E.isAllocated(), E.SemanticKind,
+ E.SemanticIndices,
+ E.isAllocated() ? static_cast<uint8_t>(E.StartRow)
+ : uint8_t(0),
+ E.Cols, E.isAllocated() ? E.StartCol : uint8_t(0),
+ E.isAllocated(), E.SemanticKind,
static_cast<dxbc::PSV::ComponentType>(Type), E.InterpMode,
E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
}
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
new file mode 100644
index 00000000000000..0788318d185494
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
@@ -0,0 +1,78 @@
+; RUN: split-file %s %t
+; RUN: cat %t/common.ll %t/min.ll > %t/min-input.ll
+; RUN: cat %t/common.ll %t/native.ll > %t/native-input.ll
+; RUN: llc -filetype=obj %t/min-input.ll -o %t/min.dxbc
+; RUN: llc -filetype=obj %t/native-input.ll -o %t/native.dxbc
+; RUN: obj2yaml %t/min.dxbc | FileCheck %s --check-prefixes=PARTS,MIN
+; RUN: obj2yaml %t/native.dxbc | FileCheck %s --check-prefixes=PARTS,NATIVE
+; RUN: llvm-objcopy --dump-section=DXIL=%t/min.bc %t/min.dxbc
+; RUN: llvm-objcopy --dump-section=DXIL=%t/native.bc %t/native.dxbc
+; RUN: llvm-dis %t/min.bc -o - | FileCheck %s --check-prefixes=DXIL,MIN-MD
+; RUN: llvm-dis %t/native.bc -o - | FileCheck %s --check-prefixes=DXIL,NATIVE-MD
+
+; Each interpolation is tested in its own valid single-declaration signature.
+; F16 remains an ordinary loadInput overload in both precision modes. Its
+; unallocated location must not change component-relative masks or consume rows.
+; MIN: MinimumPrecision: true
+; MIN: NativeLowPrecision: false
+; NATIVE: MinimumPrecision: false
+; NATIVE: NativeLowPrecision: true
+; PARTS: Name: ISG1
+; PARTS: Name: SV_Barycentrics
+; PARTS-NEXT: Index: 0
+; PARTS-NEXT: SystemValue: Barycentrics
+; PARTS-NEXT: CompType: Float16
+; PARTS-NEXT: Register: 4294967295
+; PARTS-NEXT: Mask: 7
+; PARTS-NEXT: ExclusiveMask: 4
+; MIN-NEXT: MinPrecision: Float16
+; NATIVE-NEXT: MinPrecision: Default
+; PARTS: Name: PSV0
+; MIN: SampleFrequency: 1
+; NATIVE: SampleFrequency: 0
+; PARTS: SigInputVectors: 0
+; PARTS: SigOutputVectors: [ 1, 0, 0, 0 ]
+; PARTS: SigInputElements:
+; PARTS: Indices: [ 0 ]
+; PARTS-NEXT: StartRow: 0
+; PARTS-NEXT: Cols: 3
+; PARTS-NEXT: StartCol: 0
+; PARTS-NEXT: Allocated: false
+; PARTS-NEXT: Kind: Barycentrics
+; MIN: Interpolation: LinearSample
+; NATIVE: Interpolation: LinearNoperspectiveCentroid
+; PARTS: InputOutputMap:
+; PARTS-NEXT: - [ ]
+
+; DXIL: call half @dx.op.loadInput.f16(i32 4, i32 0, i32 0, i8 2, i32 {{.*}})
+; MIN-MD: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 6, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
+; NATIVE-MD: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 5, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
+; DXIL: ![[MASK]] = !{i32 3, i32 4}
+
+;--- common.ll
+target triple = "dxil-pc-shadermodel6.2-pixel"
+define void @main() #0 {
+ %b = call half @llvm.dx.load.input.f16(i32 0, i32 0, i8 2, i32 poison)
+ %f = fpext half %b to float
+ call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %f)
+ ret void
+}
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.valver = !{!9}
+!9 = !{i32 1, i32 8}
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, !2}
+!1 = !{!3}
+!2 = !{!4}
+!4 = !{i32 0, !"SV_Target", i32 9, i32 16, !5, i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!5 = !{i32 0}
+
+;--- min.ll
+!llvm.module.flags = !{!6}
+!6 = !{i32 1, !"dx.nativelowprec", i32 0}
+!3 = !{i32 0, !"SV_Barycentrics", i32 8, i32 28, !5, i32 6, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+
+;--- native.ll
+!llvm.module.flags = !{!6}
+!6 = !{i32 1, !"dx.nativelowprec", i32 1}
+!3 = !{i32 0, !"SV_Barycentrics", i32 8, i32 28, !5, i32 5, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
new file mode 100644
index 00000000000000..278b1e9ef13bd8
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
@@ -0,0 +1,72 @@
+; RUN: opt -disable-output -passes='print<dxil-signature>' %s 2>&1 | FileCheck %s --check-prefix=ANALYSIS
+; RUN: llc -filetype=obj %s -o %t.dxbc
+; RUN: obj2yaml %t.dxbc | FileCheck %s --check-prefix=PARTS
+; RUN: llvm-objcopy --dump-section=DXIL=%t.bc %t.dxbc
+; RUN: llvm-dis %t.bc -o - | FileCheck %s --check-prefixes=MD,DXIL
+
+; Barycentrics keep signature IDs and ordinary loadInput accesses, but do not
+; consume rows or participate in the packed input/output dependency table.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+
+define void @main() #0 {
+ %b = call <3 x float> @llvm.dx.load.input.v3f32(i32 0, i32 0, i8 0, i32 poison)
+ %x = extractelement <3 x float> %b, i32 0
+ %y = extractelement <3 x float> %b, i32 1
+ %z = extractelement <3 x float> %b, i32 2
+ %a = call float @llvm.dx.load.input.f32(i32 1, i32 0, i8 3, i32 poison)
+ %xy = fadd float %x, %y
+ %xyz = fadd float %xy, %z
+ %result = fadd float %xyz, %a
+ call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %result)
+ ret void
+}
+attributes #0 = { "hlsl.shader"="pixel" }
+
+!dx.valver = !{!10}
+!10 = !{i32 1, i32 8}
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, !2}
+!1 = !{!3, !4}
+!2 = !{!6}
+!3 = !{i32 0, !"sv_barycentrics", i32 9, i32 28, !7, i32 7, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!4 = !{i32 1, !"A", i32 9, i32 0, !7, i32 2, i32 1, i8 4, i32 0, i8 0, i8 0, i8 0, i32 0}
+!6 = !{i32 0, !"SV_Target", i32 9, i32 16, !7, i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!7 = !{i32 0}
+
+; ANALYSIS: Inputs: 2 elements, 1 vectors
+; ANALYSIS-NEXT: 0: sv_barycentrics rows=1 cols=3 at 4294967295:255 usage=7 dynamic=0
+; ANALYSIS-NEXT: 1: A rows=1 cols=4 at 0:0 usage=8 dynamic=0
+; ANALYSIS-NEXT: Outputs: 1 elements, 1 vectors
+
+; DXIL: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 {{.*}})
+; DXIL: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1, i32 {{.*}})
+; DXIL: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 2, i32 {{.*}})
+; DXIL: call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 3, i32 {{.*}})
+; MD: !dx.viewIdState = !{![[STATE:[0-9]+]]}
+; MD: !dx.entryPoints =
+; MD-DAG: ![[STATE]] = !{[6 x i32] [i32 4, i32 4, i32 0, i32 0, i32 0, i32 1]}
+; MD-DAG: !{i32 0, !"sv_barycentrics", i8 9, i8 28, !{{[0-9]+}}, i8 7, i32 1, i8 3, i32 -1, i8 -1, ![[P:[0-9]+]]}
+; MD-DAG: ![[P]] = !{i32 3, i32 7}
+
+; PARTS: Name: ISG1
+; PARTS: Name: SV_Barycentrics
+; PARTS-NEXT: Index: 0
+; PARTS-NEXT: SystemValue: Barycentrics
+; PARTS-NEXT: CompType: Float32
+; PARTS-NEXT: Register: 4294967295
+; PARTS-NEXT: Mask: 7
+; PARTS-NEXT: ExclusiveMask: 7
+; PARTS: Name: PSV0
+; PARTS: SampleFrequency: 1
+; PARTS: SigInputVectors: 1
+; PARTS-NEXT: SigOutputVectors: [ 1, 0, 0, 0 ]
+; PARTS: SigInputElements:
+; PARTS: Indices: [ 0 ]
+; PARTS-NEXT: StartRow: 0
+; PARTS-NEXT: Cols: 3
+; PARTS-NEXT: StartCol: 0
+; PARTS-NEXT: Allocated: false
+; PARTS-NEXT: Kind: Barycentrics
+; PARTS: Interpolation: LinearNoperspectiveSample
+; PARTS: InputOutputMap:
+; PARTS-NEXT: - [ 0x0, 0x0, 0x0, 0x1 ]
>From 1de003d16d6872254053cecf903056d5172b790d Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:17 +0000
Subject: [PATCH 07/29] get the barycentrics shader feature flag
---
llvm/docs/DirectX/SemanticSignatures.md | 11 ++--
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 3 +
.../SemanticSignatures-barycentrics.ll | 1 +
.../DirectX/ShaderFlags/barycentrics.ll | 55 +++++++++++++++++++
4 files changed, 66 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
diff --git a/llvm/docs/DirectX/SemanticSignatures.md b/llvm/docs/DirectX/SemanticSignatures.md
index 25733981296fd6..cddc64c757dbf5 100644
--- a/llvm/docs/DirectX/SemanticSignatures.md
+++ b/llvm/docs/DirectX/SemanticSignatures.md
@@ -139,10 +139,13 @@ columns. An element occupies a rectangle of `Rows` consecutive registers and
The packing helper classifies each element from its semantic kind, shader stage,
and I/O type. Elements with the `NotAllocated` interpretation are accessed by
-other means and retain the unallocated row and column sentinels. The remaining
-interpretations accepted by a packing algorithm are assigned locations
-according to that algorithm's rules. If an eligible element cannot be placed,
-packing returns a `SignaturePackingError` identifying the element that failed.
+dedicated intrinsics and do not appear in input/output signature metadata.
+Elements with the `NotPacked` interpretation, remain in the signature and use
+ordinary `llvm.dx.load.input` accesses, but retain the unallocated row and
+column sentinels. Neither interpretation reserves registers. The remaining
+interpretations accepted by a packing algorithm are assigned locations according
+to that algorithm's rules. If an eligible element cannot be placed, packing
+returns a `SignaturePackingError` identifying the element that failed.
The packing APIs are declared in [SemanticSignaturePacking.h], and the
in-memory element representation they operate on is declared in
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 49c21ea7731f65..f09d1fd38f19f4 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -449,6 +449,9 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
// An unused signature element still contributes to the shader's type
// requirements even when no instruction uses that component type.
if (const EntrySignature *Sig = Signatures.get(F)) {
+ CSF.Barycentrics |= llvm::any_of(Sig->Inputs, [](const auto &E) {
+ return E.SemanticKind == dxbc::PSV::SemanticKind::Barycentrics;
+ });
auto HasLowPrecision = [](const auto &Elements) {
return llvm::any_of(Elements, [](const auto &E) {
return E.CompType == ElementType::F16 ||
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
index 278b1e9ef13bd8..557369fcda72c3 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
@@ -47,6 +47,7 @@ attributes #0 = { "hlsl.shader"="pixel" }
; MD-DAG: ![[STATE]] = !{[6 x i32] [i32 4, i32 4, i32 0, i32 0, i32 0, i32 1]}
; MD-DAG: !{i32 0, !"sv_barycentrics", i8 9, i8 28, !{{[0-9]+}}, i8 7, i32 1, i8 3, i32 -1, i8 -1, ![[P:[0-9]+]]}
; MD-DAG: ![[P]] = !{i32 3, i32 7}
+; MD-DAG: !{i32 0, i64 4194304}
; PARTS: Name: ISG1
; PARTS: Name: SV_Barycentrics
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
new file mode 100644
index 00000000000000..0625e5686914f3
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
@@ -0,0 +1,55 @@
+; RUN: split-file %s %t
+; RUN: opt -disable-output -passes=print-dx-shader-flags %t/library.ll 2>&1 | FileCheck %s --check-prefix=LIB
+; RUN: opt -S -passes=dxil-translate-metadata %t/library.ll | FileCheck %s --check-prefix=MD
+; RUN: llc -filetype=obj %t/unused.ll -o %t.dxbc
+; RUN: obj2yaml %t.dxbc | FileCheck %s --check-prefix=OBJ
+
+;--- library.ll
+; An unused declaration requires Barycentrics, but must not affect unrelated
+; library entries or helper functions.
+target triple = "dxil-pc-shadermodel6.8-library"
+define void @barycentric() #0 { ret void }
+define void @ordinary() #0 { ret void }
+define void @vertex() #1 { ret void }
+define void @helper() { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+attributes #1 = { "hlsl.shader"="vertex" }
+!dx.semantic.signatures = !{!0, !4, !5}
+!0 = !{ptr @barycentric, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 3, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+!4 = !{ptr @ordinary, null, null}
+!5 = !{ptr @vertex, null, null}
+
+; LIB: Combined Shader Flags for Module
+; LIB-NEXT: ; Shader Flags Value: 0x00400000
+; LIB: ; Barycentrics
+; LIB: Function barycentric : 0x00400000
+; LIB: Function ordinary : 0x00000000
+; LIB: Function vertex : 0x00000000
+; LIB: Function helper : 0x00000000
+; MD: !dx.entryPoints = !{![[LIBREC:[0-9]+]], ![[BARY:[0-9]+]], ![[ORD:[0-9]+]], ![[VS:[0-9]+]]}
+; MD-DAG: ![[LIBREC]] = !{null, !"", null, null, ![[LPROPS:[0-9]+]]}
+; MD-DAG: ![[LPROPS]] = !{i32 0, i64 4194304}
+; MD-DAG: ![[BARY]] = !{ptr @barycentric, !"barycentric", !{{[0-9]+}}, null, ![[BPROPS:[0-9]+]]}
+; MD-DAG: ![[ORD]] = !{ptr @ordinary, !"ordinary", null, null, ![[BPROPS]]}
+; MD-DAG: ![[VS]] = !{ptr @vertex, !"vertex", null, null, ![[VPROPS:[0-9]+]]}
+; MD-DAG: ![[BPROPS]] = !{i32 8, i32 0}
+; MD-DAG: ![[VPROPS]] = !{i32 8, i32 1}
+
+;--- unused.ll
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+; OBJ: Name: SFI0
+; OBJ: Barycentrics: true
+; OBJ: Name: ISG1
+; OBJ: Name: SV_Barycentrics
+; OBJ: ExclusiveMask: 0
>From d336b81c280f5b20058f4bc99faf71d6b77804fd Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:24 +0000
Subject: [PATCH 08/29] add spirv requirements
---
.../SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp | 3 +-
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 8 ++---
.../builtin-names.ll | 33 +++++++++++++++++++
3 files changed, 38 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
index efad2df822812c..0e64bbe70c2cf8 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
@@ -220,8 +220,7 @@ bool getSpirvBuiltInIdByName(llvm::StringRef Name,
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndMnemonic(
- SPIRV::OperandCategory::BuiltInOperand,
- Name.drop_front(Prefix.length()));
+ SPIRV::OperandCategory::BuiltInOperand, Name.drop_front(Prefix.length()));
if (!Lookup)
return false;
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 3fad7549702784..7d6162cdab3723 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -565,7 +565,7 @@ defm GroupNonUniformPartitionedNV : CapabilityOperand<5297, 0, 0, [], []>;
defm VulkanMemoryModelKHR : CapabilityOperand<5345, 0, 0, [], []>;
defm VulkanMemoryModelDeviceScopeKHR : CapabilityOperand<5346, 0, 0, [], []>;
defm ImageFootprintNV : CapabilityOperand<5282, 0, 0, [], []>;
-defm FragmentBarycentricNV : CapabilityOperand<5284, 0, 0, [], []>;
+defm FragmentBarycentricKHR : CapabilityOperand<5284, 0, 0, [SPV_KHR_fragment_shader_barycentric], [Shader]>;
defm ComputeDerivativeGroupQuadsNV : CapabilityOperand<5288, 0, 0, [], []>;
defm DemoteToHelperInvocation : CapabilityOperand<5379, 0x10600, 0, [SPV_EXT_demote_to_helper_invocation], []>;
defm ComputeDerivativeGroupLinearNV : CapabilityOperand<5350, 0, 0, [], []>;
@@ -1424,7 +1424,7 @@ defm ViewportRelativeNV : DecorationOperand<5252, 0, 0, [], [ShaderViewportMaskN
defm SecondaryViewportRelativeNV : DecorationOperand<5256, 0, 0, [], [ShaderStereoViewNV]>;
defm PerPrimitiveNV : DecorationOperand<5271, 0, 0, [], [MeshShadingNV]>;
defm PerViewNV : DecorationOperand<5272, 0, 0, [], [MeshShadingNV]>;
-defm PerVertexNV : DecorationOperand<5273, 0, 0, [], [FragmentBarycentricNV]>;
+defm PerVertexNV : DecorationOperand<5273, 0, 0, [], [FragmentBarycentricKHR]>;
defm NonUniformEXT : DecorationOperand<5300, 0, 0, [], [ShaderNonUniformEXT]>;
defm CountBuffer : DecorationOperand<5634, 0, 0, [], []>;
defm UserSemantic : DecorationOperand<5635, 0, 0, [], []>;
@@ -1548,8 +1548,8 @@ defm CullDistancePerViewNV : BuiltInOperand<5278, 0, 0, [], [MeshShadingNV]>;
defm LayerPerViewNV : BuiltInOperand<5279, 0, 0, [], [MeshShadingNV]>;
defm MeshViewCountNV : BuiltInOperand<5280, 0, 0, [], [MeshShadingNV]>;
defm MeshViewIndices : BuiltInOperand<5281, 0, 0, [], [MeshShadingNV]>;
-defm BaryCoordNV : BuiltInOperand<5286, 0, 0, [], [FragmentBarycentricNV]>;
-defm BaryCoordNoPerspNV : BuiltInOperand<5287, 0, 0, [], [FragmentBarycentricNV]>;
+defm BaryCoordKHR : BuiltInOperand<5286, 0, 0, [SPV_KHR_fragment_shader_barycentric], [FragmentBarycentricKHR]>;
+defm BaryCoordNoPerspKHR : BuiltInOperand<5287, 0, 0, [SPV_KHR_fragment_shader_barycentric], [FragmentBarycentricKHR]>;
defm FragSizeEXT : BuiltInOperand<5292, 0, 0, [], [FragmentDensityEXT]>;
defm FragInvocationCountEXT : BuiltInOperand<5293, 0, 0, [], [FragmentDensityEXT]>;
defm LaunchIdNV : BuiltInOperand<5319, 0, 0, [], [RayTracingNV]>;
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
new file mode 100644
index 00000000000000..093b822f3b7ff5
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
@@ -0,0 +1,33 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - | FileCheck %s --implicit-check-not='OpCapability FragmentBarycentricNV' --implicit-check-not='BuiltIn BaryCoordNV' --implicit-check-not='BuiltIn BaryCoordNoPerspNV'
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; SPIR-V-friendly IR names identify the same KHR built-ins as numeric
+; BuiltIn decorations.
+; CHECK-DAG: OpCapability FragmentBarycentricKHR
+; CHECK-DAG: OpExtension "SPV_KHR_fragment_shader_barycentric"
+; CHECK-DAG: OpDecorate %[[#NOPERSP:]] BuiltIn BaryCoordNoPerspKHR
+; CHECK-DAG: OpDecorate %[[#BARY:]] BuiltIn BaryCoordKHR
+; CHECK-DAG: %[[#FLOAT:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#FLOAT3:]] = OpTypeVector %[[#FLOAT]] 3
+; CHECK-DAG: %[[#INPUT:]] = OpTypePointer Input %[[#FLOAT3]]
+; CHECK-DAG: %[[#NOPERSP]] = OpVariable %[[#INPUT]] Input
+; CHECK-DAG: %[[#BARY]] = OpVariable %[[#INPUT]] Input
+
+ at __spirv_BuiltInBaryCoordNoPerspKHR = external hidden addrspace(7) constant <3 x float>
+ at __spirv_BuiltInBaryCoordKHR = external hidden addrspace(7) constant <3 x float>
+ at target = external hidden addrspace(8) global <3 x float>, !spirv.Decorations !0
+
+define void @main() #0 {
+; CHECK: OpLoad %[[#FLOAT3]] %[[#NOPERSP]]
+; CHECK: OpLoad %[[#FLOAT3]] %[[#BARY]]
+ %noperspective = load <3 x float>, ptr addrspace(7) @__spirv_BuiltInBaryCoordNoPerspKHR, align 16
+ %perspective = load <3 x float>, ptr addrspace(7) @__spirv_BuiltInBaryCoordKHR, align 16
+ %sum = fadd <3 x float> %noperspective, %perspective
+ store <3 x float> %sum, ptr addrspace(8) @target, align 16
+ ret void
+}
+
+attributes #0 = { "hlsl.shader"="pixel" }
+
+!0 = !{!1}
+!1 = !{i32 30, i32 0}
>From 03e6aa5e643a8983de2e6089dbea1c5bf00464cf Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Thu, 15 Oct 2026 19:30:24 +0000
Subject: [PATCH 09/29] add spirv backend diags
---
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 8 ++++
.../barycentrics.ll | 45 +++++++++++++++++++
.../builtin-names.ll | 2 +
3 files changed, 55 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/barycentrics.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index b8363d283f6f1d..2430d86b16a14a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1136,6 +1136,14 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
if (Dec == SPIRV::Decoration::BuiltIn) {
int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
+ if ((BuiltIn == SPIRV::BuiltIn::BaryCoordKHR ||
+ BuiltIn == SPIRV::BuiltIn::BaryCoordNoPerspKHR) &&
+ !ST.canUseExtension(
+ SPIRV::Extension::SPV_KHR_fragment_shader_barycentric))
+ report_fatal_error(
+ "Barycentric built-ins require the following SPIR-V extension: "
+ "SPV_KHR_fragment_shader_barycentric",
+ false);
Reqs.addRequirements(getSymbolicOperandRequirements(
SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
} else if (Dec == SPIRV::Decoration::LinkageAttributes) {
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/barycentrics.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/barycentrics.ll
new file mode 100644
index 00000000000000..f71214dc2b3708
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/barycentrics.ll
@@ -0,0 +1,45 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - | FileCheck %s --implicit-check-not='OpCapability FragmentBarycentricNV' --implicit-check-not='BuiltIn BaryCoordNV' --implicit-check-not='BuiltIn BaryCoordNoPerspNV'
+; RUN: not llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=-SPV_KHR_fragment_shader_barycentric %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERROR
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; Exercise the decorated input loads emitted for SV_Barycentrics, including both
+; perspective modes and centroid/sample interpolation in one fragment shader.
+; ERROR: LLVM ERROR: Barycentric built-ins require the following SPIR-V extension: SPV_KHR_fragment_shader_barycentric
+
+; CHECK-DAG: OpCapability FragmentBarycentricKHR
+; CHECK-DAG: OpCapability SampleRateShading
+; CHECK-DAG: OpExtension "SPV_KHR_fragment_shader_barycentric"
+; CHECK-DAG: OpDecorate %[[#BARY:]] BuiltIn BaryCoordKHR
+; CHECK-DAG: OpDecorate %[[#BARY]] Centroid
+; CHECK-DAG: OpDecorate %[[#NOPERSP:]] BuiltIn BaryCoordNoPerspKHR
+; CHECK-DAG: OpDecorate %[[#NOPERSP]] Sample
+; CHECK-DAG: %[[#FLOAT:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#FLOAT3:]] = OpTypeVector %[[#FLOAT]] 3
+; CHECK-DAG: %[[#INPUT:]] = OpTypePointer Input %[[#FLOAT3]]
+; CHECK-DAG: %[[#BARY]] = OpVariable %[[#INPUT]] Input
+; CHECK-DAG: %[[#NOPERSP]] = OpVariable %[[#INPUT]] Input
+
+ at SV_Barycentrics = external hidden thread_local addrspace(7) externally_initialized constant <3 x float>, !spirv.Decorations !0
+ at SV_BarycentricsNoPersp = external hidden thread_local addrspace(7) externally_initialized constant <3 x float>, !spirv.Decorations !2
+ at SV_Target = external hidden thread_local addrspace(8) global <3 x float>, !spirv.Decorations !4
+
+define void @main() #0 {
+; CHECK: OpLoad %[[#FLOAT3]] %[[#BARY]]
+; CHECK: OpLoad %[[#FLOAT3]] %[[#NOPERSP]]
+ %perspective = load <3 x float>, ptr addrspace(7) @SV_Barycentrics, align 16
+ %noperspective = load <3 x float>, ptr addrspace(7) @SV_BarycentricsNoPersp, align 16
+ %sum = fadd <3 x float> %perspective, %noperspective
+ store <3 x float> %sum, ptr addrspace(8) @SV_Target, align 16
+ ret void
+}
+
+attributes #0 = { "hlsl.shader"="pixel" }
+
+!0 = !{!1, !6}
+!1 = !{i32 11, i32 5286}
+!2 = !{!3, !7}
+!3 = !{i32 11, i32 5287}
+!4 = !{!5}
+!5 = !{i32 30, i32 0}
+!6 = !{i32 16} ; Centroid
+!7 = !{i32 17} ; Sample
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
index 093b822f3b7ff5..77d417b2657d73 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names.ll
@@ -1,8 +1,10 @@
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - | FileCheck %s --implicit-check-not='OpCapability FragmentBarycentricNV' --implicit-check-not='BuiltIn BaryCoordNV' --implicit-check-not='BuiltIn BaryCoordNoPerspNV'
+; RUN: not llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERROR
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
; SPIR-V-friendly IR names identify the same KHR built-ins as numeric
; BuiltIn decorations.
+; ERROR: LLVM ERROR: Barycentric built-ins require the following SPIR-V extension: SPV_KHR_fragment_shader_barycentric
; CHECK-DAG: OpCapability FragmentBarycentricKHR
; CHECK-DAG: OpExtension "SPV_KHR_fragment_shader_barycentric"
; CHECK-DAG: OpDecorate %[[#NOPERSP:]] BuiltIn BaryCoordNoPerspKHR
>From f160d25c4adcf2005ce1ca73c92a27f5b0624a79 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Mon, 19 Oct 2026 17:26:00 +0000
Subject: [PATCH 10/29] clang format
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 4 +-
clang/lib/Sema/SemaHLSL.cpp | 7 ++--
.../Target/DirectX/DXILSignatureAnalysis.cpp | 42 +++++++++----------
.../SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp | 3 +-
.../Frontend/HLSLSemanticStagesTest.cpp | 4 +-
5 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 4375a7275dd660..8ed3c85914210d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1094,7 +1094,6 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
return B.CreateTrunc(B.CreateCall(F, {B.getInt32(0)}), Ty);
}
-
// A fragment shader input interface variable whose base type is an integer or
// a 64-bit float (double) cannot be interpolated by the rasterizer. The Vulkan
// specification requires these variables to be decorated with Flat (see
@@ -1542,7 +1541,8 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
return Barycentrics;
}
if (CGM.getTarget().getTriple().isDXIL())
- return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature);
+ return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index,
+ Signature);
break;
case llvm::dxbc::PSV::SemanticKind::GroupIndex: {
assert(llvm::is_contained({llvm::Triple::Compute, llvm::Triple::Mesh,
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 14a810ac2ce6aa..2eb97f144afded 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -918,7 +918,8 @@ bool SemaHLSL::checkInterpolationModifiers(
if (Modifiers == InterpolationModifier::NoInterpolation) {
if (!Semantic)
return true;
- SemanticKind Kind = llvm::hlsl::getSemanticKind(Semantic->getSemanticName());
+ SemanticKind Kind =
+ llvm::hlsl::getSemanticKind(Semantic->getSemanticName());
if (Kind != SemanticKind::Position && Kind != SemanticKind::Barycentrics)
return true;
Diag(A->getLocation(), diag::err_hlsl_interpolation_semantic)
@@ -1278,8 +1279,8 @@ void SemaHLSL::checkSemanticAnnotation(
diagnoseSemanticShaderModel(SemanticAttr, Kind);
}
-void SemaHLSL::diagnoseSemanticShaderModel(
- const HLSLAppliedSemanticAttr *A, SemanticKind Kind) {
+void SemaHLSL::diagnoseSemanticShaderModel(const HLSLAppliedSemanticAttr *A,
+ SemanticKind Kind) {
const auto &Triple = getASTContext().getTargetInfo().getTriple();
if (!Triple.isDXIL())
return;
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index 2da5eb99c0f18a..3da8841cf04a17 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -225,8 +225,8 @@ static Error parseSignature(Metadata *MD,
if (E.SemanticKind == dxbc::PSV::SemanticKind::Barycentrics) {
using Mode = dxbc::PSV::InterpolationMode;
if (E.InterpMode == Mode::Undefined || E.InterpMode == Mode::Constant)
- return signatureError(
- "SV_Barycentrics requires perspective or noperspective interpolation");
+ return signatureError("SV_Barycentrics requires perspective or "
+ "noperspective interpolation");
}
if (Stage == Triple::Vertex && IO == IOType::In &&
@@ -254,15 +254,18 @@ static Error parseSignature(Metadata *MD,
for (unsigned Row = E.StartRow; Row != E.StartRow + E.Rows; ++Row) {
if (AllocatedColumns[Row] & Mask)
return signatureError("signature elements overlap at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ Twine(Row) + " (element " + Twine(E.SigId) +
+ ")");
if (AllocatedColumns[Row] && RowModes[Row] != E.InterpMode)
- return signatureError("signature elements have different interpolation "
- "modes at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ return signatureError(
+ "signature elements have different interpolation "
+ "modes at row " +
+ Twine(Row) + " (element " + Twine(E.SigId) + ")");
if (AllocatedColumns[Row] && RowNative16[Row] != IsNative16)
return signatureError("signature elements have different component "
"widths at row " +
- Twine(Row) + " (element " + Twine(E.SigId) + ")");
+ Twine(Row) + " (element " + Twine(E.SigId) +
+ ")");
AllocatedColumns[Row] |= Mask;
RowModes[Row] = E.InterpMode;
RowNative16[Row] = IsNative16;
@@ -406,10 +409,9 @@ analyzeModule(Module &M, const ModuleMetadataInfo &MMI) {
return signatureError("entry '" + F->getName() + "' " + Category +
" signature: " + toString(std::move(Err)));
};
- if (Error Err =
- parseSignature(Record->getOperand(1), Sig.Inputs, Info, Sig.Stage,
- IOType::In, MMI.ShaderModelVersion,
- Sig.UseNative16Bit, Sig.InputVectors))
+ if (Error Err = parseSignature(
+ Record->getOperand(1), Sig.Inputs, Info, Sig.Stage, IOType::In,
+ MMI.ShaderModelVersion, Sig.UseNative16Bit, Sig.InputVectors))
return AddContext(std::move(Err), "input");
if (Error Err = parseSignature(
Record->getOperand(2), Sig.Outputs, Info, Sig.Stage, IOType::Out,
@@ -590,16 +592,14 @@ static void buildPSVElements(SmallVectorImpl<mcdxbc::PSVSignatureElement> &Dest,
for (const auto &E : Elements) {
auto Type = getComponentType(E.CompType, Legacy);
// SigComponentType and PSV ComponentType share COMPONENT_TYPE definitions.
- Dest.push_back({E.SemanticKind == dxbc::PSV::SemanticKind::Arbitrary
- ? E.SemanticName
- : StringRef(),
- E.SemanticIndices,
- E.isAllocated() ? static_cast<uint8_t>(E.StartRow)
- : uint8_t(0),
- E.Cols, E.isAllocated() ? E.StartCol : uint8_t(0),
- E.isAllocated(), E.SemanticKind,
- static_cast<dxbc::PSV::ComponentType>(Type), E.InterpMode,
- E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
+ Dest.push_back(
+ {E.SemanticKind == dxbc::PSV::SemanticKind::Arbitrary ? E.SemanticName
+ : StringRef(),
+ E.SemanticIndices,
+ E.isAllocated() ? static_cast<uint8_t>(E.StartRow) : uint8_t(0),
+ E.Cols, E.isAllocated() ? E.StartCol : uint8_t(0), E.isAllocated(),
+ E.SemanticKind, static_cast<dxbc::PSV::ComponentType>(Type),
+ E.InterpMode, E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
}
}
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
index 0e64bbe70c2cf8..efad2df822812c 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
@@ -220,7 +220,8 @@ bool getSpirvBuiltInIdByName(llvm::StringRef Name,
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndMnemonic(
- SPIRV::OperandCategory::BuiltInOperand, Name.drop_front(Prefix.length()));
+ SPIRV::OperandCategory::BuiltInOperand,
+ Name.drop_front(Prefix.length()));
if (!Lookup)
return false;
diff --git a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
index 3e6249ff5183b4..14114b0ffc59d2 100644
--- a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
@@ -157,8 +157,8 @@ TEST(HLSLSemanticStagesTest, ShadingRateSignaturePoints) {
TEST(HLSLSemanticStagesTest, BarycentricsAreUnpackedPixelInputs) {
for (Triple::EnvironmentType Stage : AllStages)
- for (IOType IO : {IOType::In, IOType::Out,
- IOType::PatchConstantOrPrimitive})
+ for (IOType IO :
+ {IOType::In, IOType::Out, IOType::PatchConstantOrPrimitive})
EXPECT_EQ(getInterpretationKind(SemanticKind::Barycentrics, Stage, IO),
Stage == Triple::Pixel && IO == IOType::In
? SemanticInterpretation::NotPacked
>From cca5251f8c5dd84aadbee88734483411c10d554e Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:03:24 +0000
Subject: [PATCH 11/29] review: assert declared mask shift fits within a
register row
---
llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index 70407b28e82be7..ae557b9985d41e 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -23,6 +23,7 @@
#include "llvm/Support/DXILABI.h"
#include "llvm/Support/Error.h"
#include "llvm/TargetParser/Triple.h"
+#include <cassert>
#include <cstdint>
namespace llvm {
@@ -164,6 +165,8 @@ struct SemanticSignatureElement {
uint8_t getDeclaredMask() const {
unsigned Column = isAllocated() ? StartCol : 0;
+ assert(Cols >= 1 && Column + Cols <= 4 &&
+ "declared components must fit within one register row");
return static_cast<uint8_t>(((1U << Cols) - 1U) << Column);
}
>From df42c584ff6f3446c151e37b82b023f899b8df3e Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:04:23 +0000
Subject: [PATCH 12/29] review: add getStartColOrZero helper for unallocated
element masks
---
llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h | 6 +++++-
llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp | 7 +++----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
index ae557b9985d41e..90b7241d4d21d4 100644
--- a/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
+++ b/llvm/include/llvm/Frontend/HLSL/SemanticSignatures.h
@@ -163,8 +163,12 @@ struct SemanticSignatureElement {
return StartRow != UnallocatedRow && StartCol != UnallocatedCol;
}
+ // Register column of the element's first component. Unallocated elements
+ // have no register, so their masks are relative to component 0.
+ uint8_t getStartColOrZero() const { return isAllocated() ? StartCol : 0; }
+
uint8_t getDeclaredMask() const {
- unsigned Column = isAllocated() ? StartCol : 0;
+ unsigned Column = getStartColOrZero();
assert(Cols >= 1 && Column + Cols <= 4 &&
"declared components must fit within one register row");
return static_cast<uint8_t>(((1U << Cols) - 1U) << Column);
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index 3da8841cf04a17..674d561aade86d 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -340,7 +340,7 @@ static Error analyzeAccess(const IntrinsicInst &I, EntrySignature &Sig) {
if (!CorrectType)
return AccessError("signature access type disagrees with its element");
uint8_t Mask = ((1U << Width) - 1) << Col->getZExtValue();
- E.UsageMask |= Mask << (E.isAllocated() ? E.StartCol : 0);
+ E.UsageMask |= Mask << E.getStartColOrZero();
if (!Row)
E.DynIndexMask |= Mask;
return Error::success();
@@ -473,8 +473,7 @@ static MDNode *emitSignature(LLVMContext &Ctx,
if (E.UsageMask &&
(ValidatorVersion.empty() || ValidatorVersion == VersionTuple(0, 0) ||
ValidatorVersion >= VersionTuple(1, 5)))
- Props.append(
- {I32(3), I32(E.UsageMask >> (E.isAllocated() ? E.StartCol : 0))});
+ Props.append({I32(3), I32(E.UsageMask >> E.getStartColOrZero())});
Nodes.push_back(MDNode::get(
Ctx, {I32(E.SigId), MDString::get(Ctx, E.SemanticName),
I8(static_cast<uint8_t>(E.CompType)),
@@ -597,7 +596,7 @@ static void buildPSVElements(SmallVectorImpl<mcdxbc::PSVSignatureElement> &Dest,
: StringRef(),
E.SemanticIndices,
E.isAllocated() ? static_cast<uint8_t>(E.StartRow) : uint8_t(0),
- E.Cols, E.isAllocated() ? E.StartCol : uint8_t(0), E.isAllocated(),
+ E.Cols, E.getStartColOrZero(), E.isAllocated(),
E.SemanticKind, static_cast<dxbc::PSV::ComponentType>(Type),
E.InterpMode, E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
}
>From ee7619cce7799a74186e9d5a0fd9171339c699d9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:10:34 +0000
Subject: [PATCH 13/29] review: exclude unpacked elements from the signature
element limit
---
.../Target/DirectX/DXILSignatureAnalysis.cpp | 6 +-
...ic-signatures-barycentrics-max-elements.ll | 542 ++++++++++++++++++
2 files changed, 546 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-max-elements.ll
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index 674d561aade86d..e6562f558d8dca 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -154,10 +154,10 @@ static Error parseSignature(Metadata *MD,
auto *List = dyn_cast<MDNode>(MD);
if (!List)
return signatureError("expected a signature element list or null");
- if (List->getNumOperands() > 128)
- return signatureError("too many signature elements");
std::set<std::pair<std::string, uint32_t>> Semantics;
+ constexpr unsigned MaxAllocatedElements = MaxSignatureRows * 4;
+ unsigned NumAllocated = 0;
std::array<uint8_t, MaxSignatureRows> AllocatedColumns = {};
std::array<dxbc::PSV::InterpolationMode, MaxSignatureRows> RowModes = {};
std::array<bool, MaxSignatureRows> RowNative16 = {};
@@ -245,6 +245,8 @@ static Error parseSignature(Metadata *MD,
"integer pixel inputs require constant interpolation");
if (E.isAllocated()) {
+ if (++NumAllocated > MaxAllocatedElements)
+ return signatureError("too many signature elements");
// Co-packed elements must obey row constraints, even when their component
// masks do not overlap. Min-precision types occupy 32-bit components.
bool IsNative16 = Native16 && (E.CompType == ElementType::F16 ||
diff --git a/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-max-elements.ll b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-max-elements.ll
new file mode 100644
index 00000000000000..bc75b88596ff9c
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-max-elements.ll
@@ -0,0 +1,542 @@
+; RUN: split-file %s %t
+; RUN: opt -disable-output -passes='print<dxil-signature>' %t/barycentrics.ll 2>&1 | FileCheck %s --check-prefix=CHECK-BARYCENTRICS
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/packed.ll 2>&1 | FileCheck %s --check-prefix=CHECK-PACKED
+
+; Each packed scalar occupies one of the 128 components of the 32-row register
+; file. SV_Barycentrics is not packed, so it does not count towards the limit.
+
+;--- barycentrics.ll
+; CHECK-BARYCENTRICS: Inputs: 129 elements, 32 vectors
+; CHECK-BARYCENTRICS: 128: SV_Barycentrics rows=1 cols=3 at 4294967295:255
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!2 = !{i32 0}
+!1 = !{!10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45, !46, !47, !48, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !62, !63, !64, !65, !66, !67, !68, !69, !70, !71, !72, !73, !74, !75, !76, !77, !78, !79, !80, !81, !82, !83, !84, !85, !86, !87, !88, !89, !90, !91, !92, !93, !94, !95, !96, !97, !98, !99, !100, !101, !102, !103, !104, !105, !106, !107, !108, !109, !110, !111, !112, !113, !114, !115, !116, !117, !118, !119, !120, !121, !122, !123, !124, !125, !126, !127, !128, !129, !130, !131, !132, !133, !134, !135, !136, !137, !3}
+!3 = !{i32 128, !"SV_Barycentrics", i32 9, i32 28, !2, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!10 = !{i32 0, !"A", i32 9, i32 0, !138, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!138 = !{i32 0}
+!11 = !{i32 1, !"A", i32 9, i32 0, !139, i32 2, i32 1, i8 1, i32 0, i8 1, i8 0, i8 0, i32 0}
+!139 = !{i32 1}
+!12 = !{i32 2, !"A", i32 9, i32 0, !140, i32 2, i32 1, i8 1, i32 0, i8 2, i8 0, i8 0, i32 0}
+!140 = !{i32 2}
+!13 = !{i32 3, !"A", i32 9, i32 0, !141, i32 2, i32 1, i8 1, i32 0, i8 3, i8 0, i8 0, i32 0}
+!141 = !{i32 3}
+!14 = !{i32 4, !"A", i32 9, i32 0, !142, i32 2, i32 1, i8 1, i32 1, i8 0, i8 0, i8 0, i32 0}
+!142 = !{i32 4}
+!15 = !{i32 5, !"A", i32 9, i32 0, !143, i32 2, i32 1, i8 1, i32 1, i8 1, i8 0, i8 0, i32 0}
+!143 = !{i32 5}
+!16 = !{i32 6, !"A", i32 9, i32 0, !144, i32 2, i32 1, i8 1, i32 1, i8 2, i8 0, i8 0, i32 0}
+!144 = !{i32 6}
+!17 = !{i32 7, !"A", i32 9, i32 0, !145, i32 2, i32 1, i8 1, i32 1, i8 3, i8 0, i8 0, i32 0}
+!145 = !{i32 7}
+!18 = !{i32 8, !"A", i32 9, i32 0, !146, i32 2, i32 1, i8 1, i32 2, i8 0, i8 0, i8 0, i32 0}
+!146 = !{i32 8}
+!19 = !{i32 9, !"A", i32 9, i32 0, !147, i32 2, i32 1, i8 1, i32 2, i8 1, i8 0, i8 0, i32 0}
+!147 = !{i32 9}
+!20 = !{i32 10, !"A", i32 9, i32 0, !148, i32 2, i32 1, i8 1, i32 2, i8 2, i8 0, i8 0, i32 0}
+!148 = !{i32 10}
+!21 = !{i32 11, !"A", i32 9, i32 0, !149, i32 2, i32 1, i8 1, i32 2, i8 3, i8 0, i8 0, i32 0}
+!149 = !{i32 11}
+!22 = !{i32 12, !"A", i32 9, i32 0, !150, i32 2, i32 1, i8 1, i32 3, i8 0, i8 0, i8 0, i32 0}
+!150 = !{i32 12}
+!23 = !{i32 13, !"A", i32 9, i32 0, !151, i32 2, i32 1, i8 1, i32 3, i8 1, i8 0, i8 0, i32 0}
+!151 = !{i32 13}
+!24 = !{i32 14, !"A", i32 9, i32 0, !152, i32 2, i32 1, i8 1, i32 3, i8 2, i8 0, i8 0, i32 0}
+!152 = !{i32 14}
+!25 = !{i32 15, !"A", i32 9, i32 0, !153, i32 2, i32 1, i8 1, i32 3, i8 3, i8 0, i8 0, i32 0}
+!153 = !{i32 15}
+!26 = !{i32 16, !"A", i32 9, i32 0, !154, i32 2, i32 1, i8 1, i32 4, i8 0, i8 0, i8 0, i32 0}
+!154 = !{i32 16}
+!27 = !{i32 17, !"A", i32 9, i32 0, !155, i32 2, i32 1, i8 1, i32 4, i8 1, i8 0, i8 0, i32 0}
+!155 = !{i32 17}
+!28 = !{i32 18, !"A", i32 9, i32 0, !156, i32 2, i32 1, i8 1, i32 4, i8 2, i8 0, i8 0, i32 0}
+!156 = !{i32 18}
+!29 = !{i32 19, !"A", i32 9, i32 0, !157, i32 2, i32 1, i8 1, i32 4, i8 3, i8 0, i8 0, i32 0}
+!157 = !{i32 19}
+!30 = !{i32 20, !"A", i32 9, i32 0, !158, i32 2, i32 1, i8 1, i32 5, i8 0, i8 0, i8 0, i32 0}
+!158 = !{i32 20}
+!31 = !{i32 21, !"A", i32 9, i32 0, !159, i32 2, i32 1, i8 1, i32 5, i8 1, i8 0, i8 0, i32 0}
+!159 = !{i32 21}
+!32 = !{i32 22, !"A", i32 9, i32 0, !160, i32 2, i32 1, i8 1, i32 5, i8 2, i8 0, i8 0, i32 0}
+!160 = !{i32 22}
+!33 = !{i32 23, !"A", i32 9, i32 0, !161, i32 2, i32 1, i8 1, i32 5, i8 3, i8 0, i8 0, i32 0}
+!161 = !{i32 23}
+!34 = !{i32 24, !"A", i32 9, i32 0, !162, i32 2, i32 1, i8 1, i32 6, i8 0, i8 0, i8 0, i32 0}
+!162 = !{i32 24}
+!35 = !{i32 25, !"A", i32 9, i32 0, !163, i32 2, i32 1, i8 1, i32 6, i8 1, i8 0, i8 0, i32 0}
+!163 = !{i32 25}
+!36 = !{i32 26, !"A", i32 9, i32 0, !164, i32 2, i32 1, i8 1, i32 6, i8 2, i8 0, i8 0, i32 0}
+!164 = !{i32 26}
+!37 = !{i32 27, !"A", i32 9, i32 0, !165, i32 2, i32 1, i8 1, i32 6, i8 3, i8 0, i8 0, i32 0}
+!165 = !{i32 27}
+!38 = !{i32 28, !"A", i32 9, i32 0, !166, i32 2, i32 1, i8 1, i32 7, i8 0, i8 0, i8 0, i32 0}
+!166 = !{i32 28}
+!39 = !{i32 29, !"A", i32 9, i32 0, !167, i32 2, i32 1, i8 1, i32 7, i8 1, i8 0, i8 0, i32 0}
+!167 = !{i32 29}
+!40 = !{i32 30, !"A", i32 9, i32 0, !168, i32 2, i32 1, i8 1, i32 7, i8 2, i8 0, i8 0, i32 0}
+!168 = !{i32 30}
+!41 = !{i32 31, !"A", i32 9, i32 0, !169, i32 2, i32 1, i8 1, i32 7, i8 3, i8 0, i8 0, i32 0}
+!169 = !{i32 31}
+!42 = !{i32 32, !"A", i32 9, i32 0, !170, i32 2, i32 1, i8 1, i32 8, i8 0, i8 0, i8 0, i32 0}
+!170 = !{i32 32}
+!43 = !{i32 33, !"A", i32 9, i32 0, !171, i32 2, i32 1, i8 1, i32 8, i8 1, i8 0, i8 0, i32 0}
+!171 = !{i32 33}
+!44 = !{i32 34, !"A", i32 9, i32 0, !172, i32 2, i32 1, i8 1, i32 8, i8 2, i8 0, i8 0, i32 0}
+!172 = !{i32 34}
+!45 = !{i32 35, !"A", i32 9, i32 0, !173, i32 2, i32 1, i8 1, i32 8, i8 3, i8 0, i8 0, i32 0}
+!173 = !{i32 35}
+!46 = !{i32 36, !"A", i32 9, i32 0, !174, i32 2, i32 1, i8 1, i32 9, i8 0, i8 0, i8 0, i32 0}
+!174 = !{i32 36}
+!47 = !{i32 37, !"A", i32 9, i32 0, !175, i32 2, i32 1, i8 1, i32 9, i8 1, i8 0, i8 0, i32 0}
+!175 = !{i32 37}
+!48 = !{i32 38, !"A", i32 9, i32 0, !176, i32 2, i32 1, i8 1, i32 9, i8 2, i8 0, i8 0, i32 0}
+!176 = !{i32 38}
+!49 = !{i32 39, !"A", i32 9, i32 0, !177, i32 2, i32 1, i8 1, i32 9, i8 3, i8 0, i8 0, i32 0}
+!177 = !{i32 39}
+!50 = !{i32 40, !"A", i32 9, i32 0, !178, i32 2, i32 1, i8 1, i32 10, i8 0, i8 0, i8 0, i32 0}
+!178 = !{i32 40}
+!51 = !{i32 41, !"A", i32 9, i32 0, !179, i32 2, i32 1, i8 1, i32 10, i8 1, i8 0, i8 0, i32 0}
+!179 = !{i32 41}
+!52 = !{i32 42, !"A", i32 9, i32 0, !180, i32 2, i32 1, i8 1, i32 10, i8 2, i8 0, i8 0, i32 0}
+!180 = !{i32 42}
+!53 = !{i32 43, !"A", i32 9, i32 0, !181, i32 2, i32 1, i8 1, i32 10, i8 3, i8 0, i8 0, i32 0}
+!181 = !{i32 43}
+!54 = !{i32 44, !"A", i32 9, i32 0, !182, i32 2, i32 1, i8 1, i32 11, i8 0, i8 0, i8 0, i32 0}
+!182 = !{i32 44}
+!55 = !{i32 45, !"A", i32 9, i32 0, !183, i32 2, i32 1, i8 1, i32 11, i8 1, i8 0, i8 0, i32 0}
+!183 = !{i32 45}
+!56 = !{i32 46, !"A", i32 9, i32 0, !184, i32 2, i32 1, i8 1, i32 11, i8 2, i8 0, i8 0, i32 0}
+!184 = !{i32 46}
+!57 = !{i32 47, !"A", i32 9, i32 0, !185, i32 2, i32 1, i8 1, i32 11, i8 3, i8 0, i8 0, i32 0}
+!185 = !{i32 47}
+!58 = !{i32 48, !"A", i32 9, i32 0, !186, i32 2, i32 1, i8 1, i32 12, i8 0, i8 0, i8 0, i32 0}
+!186 = !{i32 48}
+!59 = !{i32 49, !"A", i32 9, i32 0, !187, i32 2, i32 1, i8 1, i32 12, i8 1, i8 0, i8 0, i32 0}
+!187 = !{i32 49}
+!60 = !{i32 50, !"A", i32 9, i32 0, !188, i32 2, i32 1, i8 1, i32 12, i8 2, i8 0, i8 0, i32 0}
+!188 = !{i32 50}
+!61 = !{i32 51, !"A", i32 9, i32 0, !189, i32 2, i32 1, i8 1, i32 12, i8 3, i8 0, i8 0, i32 0}
+!189 = !{i32 51}
+!62 = !{i32 52, !"A", i32 9, i32 0, !190, i32 2, i32 1, i8 1, i32 13, i8 0, i8 0, i8 0, i32 0}
+!190 = !{i32 52}
+!63 = !{i32 53, !"A", i32 9, i32 0, !191, i32 2, i32 1, i8 1, i32 13, i8 1, i8 0, i8 0, i32 0}
+!191 = !{i32 53}
+!64 = !{i32 54, !"A", i32 9, i32 0, !192, i32 2, i32 1, i8 1, i32 13, i8 2, i8 0, i8 0, i32 0}
+!192 = !{i32 54}
+!65 = !{i32 55, !"A", i32 9, i32 0, !193, i32 2, i32 1, i8 1, i32 13, i8 3, i8 0, i8 0, i32 0}
+!193 = !{i32 55}
+!66 = !{i32 56, !"A", i32 9, i32 0, !194, i32 2, i32 1, i8 1, i32 14, i8 0, i8 0, i8 0, i32 0}
+!194 = !{i32 56}
+!67 = !{i32 57, !"A", i32 9, i32 0, !195, i32 2, i32 1, i8 1, i32 14, i8 1, i8 0, i8 0, i32 0}
+!195 = !{i32 57}
+!68 = !{i32 58, !"A", i32 9, i32 0, !196, i32 2, i32 1, i8 1, i32 14, i8 2, i8 0, i8 0, i32 0}
+!196 = !{i32 58}
+!69 = !{i32 59, !"A", i32 9, i32 0, !197, i32 2, i32 1, i8 1, i32 14, i8 3, i8 0, i8 0, i32 0}
+!197 = !{i32 59}
+!70 = !{i32 60, !"A", i32 9, i32 0, !198, i32 2, i32 1, i8 1, i32 15, i8 0, i8 0, i8 0, i32 0}
+!198 = !{i32 60}
+!71 = !{i32 61, !"A", i32 9, i32 0, !199, i32 2, i32 1, i8 1, i32 15, i8 1, i8 0, i8 0, i32 0}
+!199 = !{i32 61}
+!72 = !{i32 62, !"A", i32 9, i32 0, !200, i32 2, i32 1, i8 1, i32 15, i8 2, i8 0, i8 0, i32 0}
+!200 = !{i32 62}
+!73 = !{i32 63, !"A", i32 9, i32 0, !201, i32 2, i32 1, i8 1, i32 15, i8 3, i8 0, i8 0, i32 0}
+!201 = !{i32 63}
+!74 = !{i32 64, !"A", i32 9, i32 0, !202, i32 2, i32 1, i8 1, i32 16, i8 0, i8 0, i8 0, i32 0}
+!202 = !{i32 64}
+!75 = !{i32 65, !"A", i32 9, i32 0, !203, i32 2, i32 1, i8 1, i32 16, i8 1, i8 0, i8 0, i32 0}
+!203 = !{i32 65}
+!76 = !{i32 66, !"A", i32 9, i32 0, !204, i32 2, i32 1, i8 1, i32 16, i8 2, i8 0, i8 0, i32 0}
+!204 = !{i32 66}
+!77 = !{i32 67, !"A", i32 9, i32 0, !205, i32 2, i32 1, i8 1, i32 16, i8 3, i8 0, i8 0, i32 0}
+!205 = !{i32 67}
+!78 = !{i32 68, !"A", i32 9, i32 0, !206, i32 2, i32 1, i8 1, i32 17, i8 0, i8 0, i8 0, i32 0}
+!206 = !{i32 68}
+!79 = !{i32 69, !"A", i32 9, i32 0, !207, i32 2, i32 1, i8 1, i32 17, i8 1, i8 0, i8 0, i32 0}
+!207 = !{i32 69}
+!80 = !{i32 70, !"A", i32 9, i32 0, !208, i32 2, i32 1, i8 1, i32 17, i8 2, i8 0, i8 0, i32 0}
+!208 = !{i32 70}
+!81 = !{i32 71, !"A", i32 9, i32 0, !209, i32 2, i32 1, i8 1, i32 17, i8 3, i8 0, i8 0, i32 0}
+!209 = !{i32 71}
+!82 = !{i32 72, !"A", i32 9, i32 0, !210, i32 2, i32 1, i8 1, i32 18, i8 0, i8 0, i8 0, i32 0}
+!210 = !{i32 72}
+!83 = !{i32 73, !"A", i32 9, i32 0, !211, i32 2, i32 1, i8 1, i32 18, i8 1, i8 0, i8 0, i32 0}
+!211 = !{i32 73}
+!84 = !{i32 74, !"A", i32 9, i32 0, !212, i32 2, i32 1, i8 1, i32 18, i8 2, i8 0, i8 0, i32 0}
+!212 = !{i32 74}
+!85 = !{i32 75, !"A", i32 9, i32 0, !213, i32 2, i32 1, i8 1, i32 18, i8 3, i8 0, i8 0, i32 0}
+!213 = !{i32 75}
+!86 = !{i32 76, !"A", i32 9, i32 0, !214, i32 2, i32 1, i8 1, i32 19, i8 0, i8 0, i8 0, i32 0}
+!214 = !{i32 76}
+!87 = !{i32 77, !"A", i32 9, i32 0, !215, i32 2, i32 1, i8 1, i32 19, i8 1, i8 0, i8 0, i32 0}
+!215 = !{i32 77}
+!88 = !{i32 78, !"A", i32 9, i32 0, !216, i32 2, i32 1, i8 1, i32 19, i8 2, i8 0, i8 0, i32 0}
+!216 = !{i32 78}
+!89 = !{i32 79, !"A", i32 9, i32 0, !217, i32 2, i32 1, i8 1, i32 19, i8 3, i8 0, i8 0, i32 0}
+!217 = !{i32 79}
+!90 = !{i32 80, !"A", i32 9, i32 0, !218, i32 2, i32 1, i8 1, i32 20, i8 0, i8 0, i8 0, i32 0}
+!218 = !{i32 80}
+!91 = !{i32 81, !"A", i32 9, i32 0, !219, i32 2, i32 1, i8 1, i32 20, i8 1, i8 0, i8 0, i32 0}
+!219 = !{i32 81}
+!92 = !{i32 82, !"A", i32 9, i32 0, !220, i32 2, i32 1, i8 1, i32 20, i8 2, i8 0, i8 0, i32 0}
+!220 = !{i32 82}
+!93 = !{i32 83, !"A", i32 9, i32 0, !221, i32 2, i32 1, i8 1, i32 20, i8 3, i8 0, i8 0, i32 0}
+!221 = !{i32 83}
+!94 = !{i32 84, !"A", i32 9, i32 0, !222, i32 2, i32 1, i8 1, i32 21, i8 0, i8 0, i8 0, i32 0}
+!222 = !{i32 84}
+!95 = !{i32 85, !"A", i32 9, i32 0, !223, i32 2, i32 1, i8 1, i32 21, i8 1, i8 0, i8 0, i32 0}
+!223 = !{i32 85}
+!96 = !{i32 86, !"A", i32 9, i32 0, !224, i32 2, i32 1, i8 1, i32 21, i8 2, i8 0, i8 0, i32 0}
+!224 = !{i32 86}
+!97 = !{i32 87, !"A", i32 9, i32 0, !225, i32 2, i32 1, i8 1, i32 21, i8 3, i8 0, i8 0, i32 0}
+!225 = !{i32 87}
+!98 = !{i32 88, !"A", i32 9, i32 0, !226, i32 2, i32 1, i8 1, i32 22, i8 0, i8 0, i8 0, i32 0}
+!226 = !{i32 88}
+!99 = !{i32 89, !"A", i32 9, i32 0, !227, i32 2, i32 1, i8 1, i32 22, i8 1, i8 0, i8 0, i32 0}
+!227 = !{i32 89}
+!100 = !{i32 90, !"A", i32 9, i32 0, !228, i32 2, i32 1, i8 1, i32 22, i8 2, i8 0, i8 0, i32 0}
+!228 = !{i32 90}
+!101 = !{i32 91, !"A", i32 9, i32 0, !229, i32 2, i32 1, i8 1, i32 22, i8 3, i8 0, i8 0, i32 0}
+!229 = !{i32 91}
+!102 = !{i32 92, !"A", i32 9, i32 0, !230, i32 2, i32 1, i8 1, i32 23, i8 0, i8 0, i8 0, i32 0}
+!230 = !{i32 92}
+!103 = !{i32 93, !"A", i32 9, i32 0, !231, i32 2, i32 1, i8 1, i32 23, i8 1, i8 0, i8 0, i32 0}
+!231 = !{i32 93}
+!104 = !{i32 94, !"A", i32 9, i32 0, !232, i32 2, i32 1, i8 1, i32 23, i8 2, i8 0, i8 0, i32 0}
+!232 = !{i32 94}
+!105 = !{i32 95, !"A", i32 9, i32 0, !233, i32 2, i32 1, i8 1, i32 23, i8 3, i8 0, i8 0, i32 0}
+!233 = !{i32 95}
+!106 = !{i32 96, !"A", i32 9, i32 0, !234, i32 2, i32 1, i8 1, i32 24, i8 0, i8 0, i8 0, i32 0}
+!234 = !{i32 96}
+!107 = !{i32 97, !"A", i32 9, i32 0, !235, i32 2, i32 1, i8 1, i32 24, i8 1, i8 0, i8 0, i32 0}
+!235 = !{i32 97}
+!108 = !{i32 98, !"A", i32 9, i32 0, !236, i32 2, i32 1, i8 1, i32 24, i8 2, i8 0, i8 0, i32 0}
+!236 = !{i32 98}
+!109 = !{i32 99, !"A", i32 9, i32 0, !237, i32 2, i32 1, i8 1, i32 24, i8 3, i8 0, i8 0, i32 0}
+!237 = !{i32 99}
+!110 = !{i32 100, !"A", i32 9, i32 0, !238, i32 2, i32 1, i8 1, i32 25, i8 0, i8 0, i8 0, i32 0}
+!238 = !{i32 100}
+!111 = !{i32 101, !"A", i32 9, i32 0, !239, i32 2, i32 1, i8 1, i32 25, i8 1, i8 0, i8 0, i32 0}
+!239 = !{i32 101}
+!112 = !{i32 102, !"A", i32 9, i32 0, !240, i32 2, i32 1, i8 1, i32 25, i8 2, i8 0, i8 0, i32 0}
+!240 = !{i32 102}
+!113 = !{i32 103, !"A", i32 9, i32 0, !241, i32 2, i32 1, i8 1, i32 25, i8 3, i8 0, i8 0, i32 0}
+!241 = !{i32 103}
+!114 = !{i32 104, !"A", i32 9, i32 0, !242, i32 2, i32 1, i8 1, i32 26, i8 0, i8 0, i8 0, i32 0}
+!242 = !{i32 104}
+!115 = !{i32 105, !"A", i32 9, i32 0, !243, i32 2, i32 1, i8 1, i32 26, i8 1, i8 0, i8 0, i32 0}
+!243 = !{i32 105}
+!116 = !{i32 106, !"A", i32 9, i32 0, !244, i32 2, i32 1, i8 1, i32 26, i8 2, i8 0, i8 0, i32 0}
+!244 = !{i32 106}
+!117 = !{i32 107, !"A", i32 9, i32 0, !245, i32 2, i32 1, i8 1, i32 26, i8 3, i8 0, i8 0, i32 0}
+!245 = !{i32 107}
+!118 = !{i32 108, !"A", i32 9, i32 0, !246, i32 2, i32 1, i8 1, i32 27, i8 0, i8 0, i8 0, i32 0}
+!246 = !{i32 108}
+!119 = !{i32 109, !"A", i32 9, i32 0, !247, i32 2, i32 1, i8 1, i32 27, i8 1, i8 0, i8 0, i32 0}
+!247 = !{i32 109}
+!120 = !{i32 110, !"A", i32 9, i32 0, !248, i32 2, i32 1, i8 1, i32 27, i8 2, i8 0, i8 0, i32 0}
+!248 = !{i32 110}
+!121 = !{i32 111, !"A", i32 9, i32 0, !249, i32 2, i32 1, i8 1, i32 27, i8 3, i8 0, i8 0, i32 0}
+!249 = !{i32 111}
+!122 = !{i32 112, !"A", i32 9, i32 0, !250, i32 2, i32 1, i8 1, i32 28, i8 0, i8 0, i8 0, i32 0}
+!250 = !{i32 112}
+!123 = !{i32 113, !"A", i32 9, i32 0, !251, i32 2, i32 1, i8 1, i32 28, i8 1, i8 0, i8 0, i32 0}
+!251 = !{i32 113}
+!124 = !{i32 114, !"A", i32 9, i32 0, !252, i32 2, i32 1, i8 1, i32 28, i8 2, i8 0, i8 0, i32 0}
+!252 = !{i32 114}
+!125 = !{i32 115, !"A", i32 9, i32 0, !253, i32 2, i32 1, i8 1, i32 28, i8 3, i8 0, i8 0, i32 0}
+!253 = !{i32 115}
+!126 = !{i32 116, !"A", i32 9, i32 0, !254, i32 2, i32 1, i8 1, i32 29, i8 0, i8 0, i8 0, i32 0}
+!254 = !{i32 116}
+!127 = !{i32 117, !"A", i32 9, i32 0, !255, i32 2, i32 1, i8 1, i32 29, i8 1, i8 0, i8 0, i32 0}
+!255 = !{i32 117}
+!128 = !{i32 118, !"A", i32 9, i32 0, !256, i32 2, i32 1, i8 1, i32 29, i8 2, i8 0, i8 0, i32 0}
+!256 = !{i32 118}
+!129 = !{i32 119, !"A", i32 9, i32 0, !257, i32 2, i32 1, i8 1, i32 29, i8 3, i8 0, i8 0, i32 0}
+!257 = !{i32 119}
+!130 = !{i32 120, !"A", i32 9, i32 0, !258, i32 2, i32 1, i8 1, i32 30, i8 0, i8 0, i8 0, i32 0}
+!258 = !{i32 120}
+!131 = !{i32 121, !"A", i32 9, i32 0, !259, i32 2, i32 1, i8 1, i32 30, i8 1, i8 0, i8 0, i32 0}
+!259 = !{i32 121}
+!132 = !{i32 122, !"A", i32 9, i32 0, !260, i32 2, i32 1, i8 1, i32 30, i8 2, i8 0, i8 0, i32 0}
+!260 = !{i32 122}
+!133 = !{i32 123, !"A", i32 9, i32 0, !261, i32 2, i32 1, i8 1, i32 30, i8 3, i8 0, i8 0, i32 0}
+!261 = !{i32 123}
+!134 = !{i32 124, !"A", i32 9, i32 0, !262, i32 2, i32 1, i8 1, i32 31, i8 0, i8 0, i8 0, i32 0}
+!262 = !{i32 124}
+!135 = !{i32 125, !"A", i32 9, i32 0, !263, i32 2, i32 1, i8 1, i32 31, i8 1, i8 0, i8 0, i32 0}
+!263 = !{i32 125}
+!136 = !{i32 126, !"A", i32 9, i32 0, !264, i32 2, i32 1, i8 1, i32 31, i8 2, i8 0, i8 0, i32 0}
+!264 = !{i32 126}
+!137 = !{i32 127, !"A", i32 9, i32 0, !265, i32 2, i32 1, i8 1, i32 31, i8 3, i8 0, i8 0, i32 0}
+!265 = !{i32 127}
+
+;--- packed.ll
+; CHECK-PACKED: entry 'main' input signature: too many signature elements
+; The 129th packed scalar has no free component left.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!3 = !{i32 128, !"B", i32 9, i32 0, !2, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!2 = !{i32 0}
+!1 = !{!10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45, !46, !47, !48, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !62, !63, !64, !65, !66, !67, !68, !69, !70, !71, !72, !73, !74, !75, !76, !77, !78, !79, !80, !81, !82, !83, !84, !85, !86, !87, !88, !89, !90, !91, !92, !93, !94, !95, !96, !97, !98, !99, !100, !101, !102, !103, !104, !105, !106, !107, !108, !109, !110, !111, !112, !113, !114, !115, !116, !117, !118, !119, !120, !121, !122, !123, !124, !125, !126, !127, !128, !129, !130, !131, !132, !133, !134, !135, !136, !137, !3}
+!10 = !{i32 0, !"A", i32 9, i32 0, !138, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!138 = !{i32 0}
+!11 = !{i32 1, !"A", i32 9, i32 0, !139, i32 2, i32 1, i8 1, i32 0, i8 1, i8 0, i8 0, i32 0}
+!139 = !{i32 1}
+!12 = !{i32 2, !"A", i32 9, i32 0, !140, i32 2, i32 1, i8 1, i32 0, i8 2, i8 0, i8 0, i32 0}
+!140 = !{i32 2}
+!13 = !{i32 3, !"A", i32 9, i32 0, !141, i32 2, i32 1, i8 1, i32 0, i8 3, i8 0, i8 0, i32 0}
+!141 = !{i32 3}
+!14 = !{i32 4, !"A", i32 9, i32 0, !142, i32 2, i32 1, i8 1, i32 1, i8 0, i8 0, i8 0, i32 0}
+!142 = !{i32 4}
+!15 = !{i32 5, !"A", i32 9, i32 0, !143, i32 2, i32 1, i8 1, i32 1, i8 1, i8 0, i8 0, i32 0}
+!143 = !{i32 5}
+!16 = !{i32 6, !"A", i32 9, i32 0, !144, i32 2, i32 1, i8 1, i32 1, i8 2, i8 0, i8 0, i32 0}
+!144 = !{i32 6}
+!17 = !{i32 7, !"A", i32 9, i32 0, !145, i32 2, i32 1, i8 1, i32 1, i8 3, i8 0, i8 0, i32 0}
+!145 = !{i32 7}
+!18 = !{i32 8, !"A", i32 9, i32 0, !146, i32 2, i32 1, i8 1, i32 2, i8 0, i8 0, i8 0, i32 0}
+!146 = !{i32 8}
+!19 = !{i32 9, !"A", i32 9, i32 0, !147, i32 2, i32 1, i8 1, i32 2, i8 1, i8 0, i8 0, i32 0}
+!147 = !{i32 9}
+!20 = !{i32 10, !"A", i32 9, i32 0, !148, i32 2, i32 1, i8 1, i32 2, i8 2, i8 0, i8 0, i32 0}
+!148 = !{i32 10}
+!21 = !{i32 11, !"A", i32 9, i32 0, !149, i32 2, i32 1, i8 1, i32 2, i8 3, i8 0, i8 0, i32 0}
+!149 = !{i32 11}
+!22 = !{i32 12, !"A", i32 9, i32 0, !150, i32 2, i32 1, i8 1, i32 3, i8 0, i8 0, i8 0, i32 0}
+!150 = !{i32 12}
+!23 = !{i32 13, !"A", i32 9, i32 0, !151, i32 2, i32 1, i8 1, i32 3, i8 1, i8 0, i8 0, i32 0}
+!151 = !{i32 13}
+!24 = !{i32 14, !"A", i32 9, i32 0, !152, i32 2, i32 1, i8 1, i32 3, i8 2, i8 0, i8 0, i32 0}
+!152 = !{i32 14}
+!25 = !{i32 15, !"A", i32 9, i32 0, !153, i32 2, i32 1, i8 1, i32 3, i8 3, i8 0, i8 0, i32 0}
+!153 = !{i32 15}
+!26 = !{i32 16, !"A", i32 9, i32 0, !154, i32 2, i32 1, i8 1, i32 4, i8 0, i8 0, i8 0, i32 0}
+!154 = !{i32 16}
+!27 = !{i32 17, !"A", i32 9, i32 0, !155, i32 2, i32 1, i8 1, i32 4, i8 1, i8 0, i8 0, i32 0}
+!155 = !{i32 17}
+!28 = !{i32 18, !"A", i32 9, i32 0, !156, i32 2, i32 1, i8 1, i32 4, i8 2, i8 0, i8 0, i32 0}
+!156 = !{i32 18}
+!29 = !{i32 19, !"A", i32 9, i32 0, !157, i32 2, i32 1, i8 1, i32 4, i8 3, i8 0, i8 0, i32 0}
+!157 = !{i32 19}
+!30 = !{i32 20, !"A", i32 9, i32 0, !158, i32 2, i32 1, i8 1, i32 5, i8 0, i8 0, i8 0, i32 0}
+!158 = !{i32 20}
+!31 = !{i32 21, !"A", i32 9, i32 0, !159, i32 2, i32 1, i8 1, i32 5, i8 1, i8 0, i8 0, i32 0}
+!159 = !{i32 21}
+!32 = !{i32 22, !"A", i32 9, i32 0, !160, i32 2, i32 1, i8 1, i32 5, i8 2, i8 0, i8 0, i32 0}
+!160 = !{i32 22}
+!33 = !{i32 23, !"A", i32 9, i32 0, !161, i32 2, i32 1, i8 1, i32 5, i8 3, i8 0, i8 0, i32 0}
+!161 = !{i32 23}
+!34 = !{i32 24, !"A", i32 9, i32 0, !162, i32 2, i32 1, i8 1, i32 6, i8 0, i8 0, i8 0, i32 0}
+!162 = !{i32 24}
+!35 = !{i32 25, !"A", i32 9, i32 0, !163, i32 2, i32 1, i8 1, i32 6, i8 1, i8 0, i8 0, i32 0}
+!163 = !{i32 25}
+!36 = !{i32 26, !"A", i32 9, i32 0, !164, i32 2, i32 1, i8 1, i32 6, i8 2, i8 0, i8 0, i32 0}
+!164 = !{i32 26}
+!37 = !{i32 27, !"A", i32 9, i32 0, !165, i32 2, i32 1, i8 1, i32 6, i8 3, i8 0, i8 0, i32 0}
+!165 = !{i32 27}
+!38 = !{i32 28, !"A", i32 9, i32 0, !166, i32 2, i32 1, i8 1, i32 7, i8 0, i8 0, i8 0, i32 0}
+!166 = !{i32 28}
+!39 = !{i32 29, !"A", i32 9, i32 0, !167, i32 2, i32 1, i8 1, i32 7, i8 1, i8 0, i8 0, i32 0}
+!167 = !{i32 29}
+!40 = !{i32 30, !"A", i32 9, i32 0, !168, i32 2, i32 1, i8 1, i32 7, i8 2, i8 0, i8 0, i32 0}
+!168 = !{i32 30}
+!41 = !{i32 31, !"A", i32 9, i32 0, !169, i32 2, i32 1, i8 1, i32 7, i8 3, i8 0, i8 0, i32 0}
+!169 = !{i32 31}
+!42 = !{i32 32, !"A", i32 9, i32 0, !170, i32 2, i32 1, i8 1, i32 8, i8 0, i8 0, i8 0, i32 0}
+!170 = !{i32 32}
+!43 = !{i32 33, !"A", i32 9, i32 0, !171, i32 2, i32 1, i8 1, i32 8, i8 1, i8 0, i8 0, i32 0}
+!171 = !{i32 33}
+!44 = !{i32 34, !"A", i32 9, i32 0, !172, i32 2, i32 1, i8 1, i32 8, i8 2, i8 0, i8 0, i32 0}
+!172 = !{i32 34}
+!45 = !{i32 35, !"A", i32 9, i32 0, !173, i32 2, i32 1, i8 1, i32 8, i8 3, i8 0, i8 0, i32 0}
+!173 = !{i32 35}
+!46 = !{i32 36, !"A", i32 9, i32 0, !174, i32 2, i32 1, i8 1, i32 9, i8 0, i8 0, i8 0, i32 0}
+!174 = !{i32 36}
+!47 = !{i32 37, !"A", i32 9, i32 0, !175, i32 2, i32 1, i8 1, i32 9, i8 1, i8 0, i8 0, i32 0}
+!175 = !{i32 37}
+!48 = !{i32 38, !"A", i32 9, i32 0, !176, i32 2, i32 1, i8 1, i32 9, i8 2, i8 0, i8 0, i32 0}
+!176 = !{i32 38}
+!49 = !{i32 39, !"A", i32 9, i32 0, !177, i32 2, i32 1, i8 1, i32 9, i8 3, i8 0, i8 0, i32 0}
+!177 = !{i32 39}
+!50 = !{i32 40, !"A", i32 9, i32 0, !178, i32 2, i32 1, i8 1, i32 10, i8 0, i8 0, i8 0, i32 0}
+!178 = !{i32 40}
+!51 = !{i32 41, !"A", i32 9, i32 0, !179, i32 2, i32 1, i8 1, i32 10, i8 1, i8 0, i8 0, i32 0}
+!179 = !{i32 41}
+!52 = !{i32 42, !"A", i32 9, i32 0, !180, i32 2, i32 1, i8 1, i32 10, i8 2, i8 0, i8 0, i32 0}
+!180 = !{i32 42}
+!53 = !{i32 43, !"A", i32 9, i32 0, !181, i32 2, i32 1, i8 1, i32 10, i8 3, i8 0, i8 0, i32 0}
+!181 = !{i32 43}
+!54 = !{i32 44, !"A", i32 9, i32 0, !182, i32 2, i32 1, i8 1, i32 11, i8 0, i8 0, i8 0, i32 0}
+!182 = !{i32 44}
+!55 = !{i32 45, !"A", i32 9, i32 0, !183, i32 2, i32 1, i8 1, i32 11, i8 1, i8 0, i8 0, i32 0}
+!183 = !{i32 45}
+!56 = !{i32 46, !"A", i32 9, i32 0, !184, i32 2, i32 1, i8 1, i32 11, i8 2, i8 0, i8 0, i32 0}
+!184 = !{i32 46}
+!57 = !{i32 47, !"A", i32 9, i32 0, !185, i32 2, i32 1, i8 1, i32 11, i8 3, i8 0, i8 0, i32 0}
+!185 = !{i32 47}
+!58 = !{i32 48, !"A", i32 9, i32 0, !186, i32 2, i32 1, i8 1, i32 12, i8 0, i8 0, i8 0, i32 0}
+!186 = !{i32 48}
+!59 = !{i32 49, !"A", i32 9, i32 0, !187, i32 2, i32 1, i8 1, i32 12, i8 1, i8 0, i8 0, i32 0}
+!187 = !{i32 49}
+!60 = !{i32 50, !"A", i32 9, i32 0, !188, i32 2, i32 1, i8 1, i32 12, i8 2, i8 0, i8 0, i32 0}
+!188 = !{i32 50}
+!61 = !{i32 51, !"A", i32 9, i32 0, !189, i32 2, i32 1, i8 1, i32 12, i8 3, i8 0, i8 0, i32 0}
+!189 = !{i32 51}
+!62 = !{i32 52, !"A", i32 9, i32 0, !190, i32 2, i32 1, i8 1, i32 13, i8 0, i8 0, i8 0, i32 0}
+!190 = !{i32 52}
+!63 = !{i32 53, !"A", i32 9, i32 0, !191, i32 2, i32 1, i8 1, i32 13, i8 1, i8 0, i8 0, i32 0}
+!191 = !{i32 53}
+!64 = !{i32 54, !"A", i32 9, i32 0, !192, i32 2, i32 1, i8 1, i32 13, i8 2, i8 0, i8 0, i32 0}
+!192 = !{i32 54}
+!65 = !{i32 55, !"A", i32 9, i32 0, !193, i32 2, i32 1, i8 1, i32 13, i8 3, i8 0, i8 0, i32 0}
+!193 = !{i32 55}
+!66 = !{i32 56, !"A", i32 9, i32 0, !194, i32 2, i32 1, i8 1, i32 14, i8 0, i8 0, i8 0, i32 0}
+!194 = !{i32 56}
+!67 = !{i32 57, !"A", i32 9, i32 0, !195, i32 2, i32 1, i8 1, i32 14, i8 1, i8 0, i8 0, i32 0}
+!195 = !{i32 57}
+!68 = !{i32 58, !"A", i32 9, i32 0, !196, i32 2, i32 1, i8 1, i32 14, i8 2, i8 0, i8 0, i32 0}
+!196 = !{i32 58}
+!69 = !{i32 59, !"A", i32 9, i32 0, !197, i32 2, i32 1, i8 1, i32 14, i8 3, i8 0, i8 0, i32 0}
+!197 = !{i32 59}
+!70 = !{i32 60, !"A", i32 9, i32 0, !198, i32 2, i32 1, i8 1, i32 15, i8 0, i8 0, i8 0, i32 0}
+!198 = !{i32 60}
+!71 = !{i32 61, !"A", i32 9, i32 0, !199, i32 2, i32 1, i8 1, i32 15, i8 1, i8 0, i8 0, i32 0}
+!199 = !{i32 61}
+!72 = !{i32 62, !"A", i32 9, i32 0, !200, i32 2, i32 1, i8 1, i32 15, i8 2, i8 0, i8 0, i32 0}
+!200 = !{i32 62}
+!73 = !{i32 63, !"A", i32 9, i32 0, !201, i32 2, i32 1, i8 1, i32 15, i8 3, i8 0, i8 0, i32 0}
+!201 = !{i32 63}
+!74 = !{i32 64, !"A", i32 9, i32 0, !202, i32 2, i32 1, i8 1, i32 16, i8 0, i8 0, i8 0, i32 0}
+!202 = !{i32 64}
+!75 = !{i32 65, !"A", i32 9, i32 0, !203, i32 2, i32 1, i8 1, i32 16, i8 1, i8 0, i8 0, i32 0}
+!203 = !{i32 65}
+!76 = !{i32 66, !"A", i32 9, i32 0, !204, i32 2, i32 1, i8 1, i32 16, i8 2, i8 0, i8 0, i32 0}
+!204 = !{i32 66}
+!77 = !{i32 67, !"A", i32 9, i32 0, !205, i32 2, i32 1, i8 1, i32 16, i8 3, i8 0, i8 0, i32 0}
+!205 = !{i32 67}
+!78 = !{i32 68, !"A", i32 9, i32 0, !206, i32 2, i32 1, i8 1, i32 17, i8 0, i8 0, i8 0, i32 0}
+!206 = !{i32 68}
+!79 = !{i32 69, !"A", i32 9, i32 0, !207, i32 2, i32 1, i8 1, i32 17, i8 1, i8 0, i8 0, i32 0}
+!207 = !{i32 69}
+!80 = !{i32 70, !"A", i32 9, i32 0, !208, i32 2, i32 1, i8 1, i32 17, i8 2, i8 0, i8 0, i32 0}
+!208 = !{i32 70}
+!81 = !{i32 71, !"A", i32 9, i32 0, !209, i32 2, i32 1, i8 1, i32 17, i8 3, i8 0, i8 0, i32 0}
+!209 = !{i32 71}
+!82 = !{i32 72, !"A", i32 9, i32 0, !210, i32 2, i32 1, i8 1, i32 18, i8 0, i8 0, i8 0, i32 0}
+!210 = !{i32 72}
+!83 = !{i32 73, !"A", i32 9, i32 0, !211, i32 2, i32 1, i8 1, i32 18, i8 1, i8 0, i8 0, i32 0}
+!211 = !{i32 73}
+!84 = !{i32 74, !"A", i32 9, i32 0, !212, i32 2, i32 1, i8 1, i32 18, i8 2, i8 0, i8 0, i32 0}
+!212 = !{i32 74}
+!85 = !{i32 75, !"A", i32 9, i32 0, !213, i32 2, i32 1, i8 1, i32 18, i8 3, i8 0, i8 0, i32 0}
+!213 = !{i32 75}
+!86 = !{i32 76, !"A", i32 9, i32 0, !214, i32 2, i32 1, i8 1, i32 19, i8 0, i8 0, i8 0, i32 0}
+!214 = !{i32 76}
+!87 = !{i32 77, !"A", i32 9, i32 0, !215, i32 2, i32 1, i8 1, i32 19, i8 1, i8 0, i8 0, i32 0}
+!215 = !{i32 77}
+!88 = !{i32 78, !"A", i32 9, i32 0, !216, i32 2, i32 1, i8 1, i32 19, i8 2, i8 0, i8 0, i32 0}
+!216 = !{i32 78}
+!89 = !{i32 79, !"A", i32 9, i32 0, !217, i32 2, i32 1, i8 1, i32 19, i8 3, i8 0, i8 0, i32 0}
+!217 = !{i32 79}
+!90 = !{i32 80, !"A", i32 9, i32 0, !218, i32 2, i32 1, i8 1, i32 20, i8 0, i8 0, i8 0, i32 0}
+!218 = !{i32 80}
+!91 = !{i32 81, !"A", i32 9, i32 0, !219, i32 2, i32 1, i8 1, i32 20, i8 1, i8 0, i8 0, i32 0}
+!219 = !{i32 81}
+!92 = !{i32 82, !"A", i32 9, i32 0, !220, i32 2, i32 1, i8 1, i32 20, i8 2, i8 0, i8 0, i32 0}
+!220 = !{i32 82}
+!93 = !{i32 83, !"A", i32 9, i32 0, !221, i32 2, i32 1, i8 1, i32 20, i8 3, i8 0, i8 0, i32 0}
+!221 = !{i32 83}
+!94 = !{i32 84, !"A", i32 9, i32 0, !222, i32 2, i32 1, i8 1, i32 21, i8 0, i8 0, i8 0, i32 0}
+!222 = !{i32 84}
+!95 = !{i32 85, !"A", i32 9, i32 0, !223, i32 2, i32 1, i8 1, i32 21, i8 1, i8 0, i8 0, i32 0}
+!223 = !{i32 85}
+!96 = !{i32 86, !"A", i32 9, i32 0, !224, i32 2, i32 1, i8 1, i32 21, i8 2, i8 0, i8 0, i32 0}
+!224 = !{i32 86}
+!97 = !{i32 87, !"A", i32 9, i32 0, !225, i32 2, i32 1, i8 1, i32 21, i8 3, i8 0, i8 0, i32 0}
+!225 = !{i32 87}
+!98 = !{i32 88, !"A", i32 9, i32 0, !226, i32 2, i32 1, i8 1, i32 22, i8 0, i8 0, i8 0, i32 0}
+!226 = !{i32 88}
+!99 = !{i32 89, !"A", i32 9, i32 0, !227, i32 2, i32 1, i8 1, i32 22, i8 1, i8 0, i8 0, i32 0}
+!227 = !{i32 89}
+!100 = !{i32 90, !"A", i32 9, i32 0, !228, i32 2, i32 1, i8 1, i32 22, i8 2, i8 0, i8 0, i32 0}
+!228 = !{i32 90}
+!101 = !{i32 91, !"A", i32 9, i32 0, !229, i32 2, i32 1, i8 1, i32 22, i8 3, i8 0, i8 0, i32 0}
+!229 = !{i32 91}
+!102 = !{i32 92, !"A", i32 9, i32 0, !230, i32 2, i32 1, i8 1, i32 23, i8 0, i8 0, i8 0, i32 0}
+!230 = !{i32 92}
+!103 = !{i32 93, !"A", i32 9, i32 0, !231, i32 2, i32 1, i8 1, i32 23, i8 1, i8 0, i8 0, i32 0}
+!231 = !{i32 93}
+!104 = !{i32 94, !"A", i32 9, i32 0, !232, i32 2, i32 1, i8 1, i32 23, i8 2, i8 0, i8 0, i32 0}
+!232 = !{i32 94}
+!105 = !{i32 95, !"A", i32 9, i32 0, !233, i32 2, i32 1, i8 1, i32 23, i8 3, i8 0, i8 0, i32 0}
+!233 = !{i32 95}
+!106 = !{i32 96, !"A", i32 9, i32 0, !234, i32 2, i32 1, i8 1, i32 24, i8 0, i8 0, i8 0, i32 0}
+!234 = !{i32 96}
+!107 = !{i32 97, !"A", i32 9, i32 0, !235, i32 2, i32 1, i8 1, i32 24, i8 1, i8 0, i8 0, i32 0}
+!235 = !{i32 97}
+!108 = !{i32 98, !"A", i32 9, i32 0, !236, i32 2, i32 1, i8 1, i32 24, i8 2, i8 0, i8 0, i32 0}
+!236 = !{i32 98}
+!109 = !{i32 99, !"A", i32 9, i32 0, !237, i32 2, i32 1, i8 1, i32 24, i8 3, i8 0, i8 0, i32 0}
+!237 = !{i32 99}
+!110 = !{i32 100, !"A", i32 9, i32 0, !238, i32 2, i32 1, i8 1, i32 25, i8 0, i8 0, i8 0, i32 0}
+!238 = !{i32 100}
+!111 = !{i32 101, !"A", i32 9, i32 0, !239, i32 2, i32 1, i8 1, i32 25, i8 1, i8 0, i8 0, i32 0}
+!239 = !{i32 101}
+!112 = !{i32 102, !"A", i32 9, i32 0, !240, i32 2, i32 1, i8 1, i32 25, i8 2, i8 0, i8 0, i32 0}
+!240 = !{i32 102}
+!113 = !{i32 103, !"A", i32 9, i32 0, !241, i32 2, i32 1, i8 1, i32 25, i8 3, i8 0, i8 0, i32 0}
+!241 = !{i32 103}
+!114 = !{i32 104, !"A", i32 9, i32 0, !242, i32 2, i32 1, i8 1, i32 26, i8 0, i8 0, i8 0, i32 0}
+!242 = !{i32 104}
+!115 = !{i32 105, !"A", i32 9, i32 0, !243, i32 2, i32 1, i8 1, i32 26, i8 1, i8 0, i8 0, i32 0}
+!243 = !{i32 105}
+!116 = !{i32 106, !"A", i32 9, i32 0, !244, i32 2, i32 1, i8 1, i32 26, i8 2, i8 0, i8 0, i32 0}
+!244 = !{i32 106}
+!117 = !{i32 107, !"A", i32 9, i32 0, !245, i32 2, i32 1, i8 1, i32 26, i8 3, i8 0, i8 0, i32 0}
+!245 = !{i32 107}
+!118 = !{i32 108, !"A", i32 9, i32 0, !246, i32 2, i32 1, i8 1, i32 27, i8 0, i8 0, i8 0, i32 0}
+!246 = !{i32 108}
+!119 = !{i32 109, !"A", i32 9, i32 0, !247, i32 2, i32 1, i8 1, i32 27, i8 1, i8 0, i8 0, i32 0}
+!247 = !{i32 109}
+!120 = !{i32 110, !"A", i32 9, i32 0, !248, i32 2, i32 1, i8 1, i32 27, i8 2, i8 0, i8 0, i32 0}
+!248 = !{i32 110}
+!121 = !{i32 111, !"A", i32 9, i32 0, !249, i32 2, i32 1, i8 1, i32 27, i8 3, i8 0, i8 0, i32 0}
+!249 = !{i32 111}
+!122 = !{i32 112, !"A", i32 9, i32 0, !250, i32 2, i32 1, i8 1, i32 28, i8 0, i8 0, i8 0, i32 0}
+!250 = !{i32 112}
+!123 = !{i32 113, !"A", i32 9, i32 0, !251, i32 2, i32 1, i8 1, i32 28, i8 1, i8 0, i8 0, i32 0}
+!251 = !{i32 113}
+!124 = !{i32 114, !"A", i32 9, i32 0, !252, i32 2, i32 1, i8 1, i32 28, i8 2, i8 0, i8 0, i32 0}
+!252 = !{i32 114}
+!125 = !{i32 115, !"A", i32 9, i32 0, !253, i32 2, i32 1, i8 1, i32 28, i8 3, i8 0, i8 0, i32 0}
+!253 = !{i32 115}
+!126 = !{i32 116, !"A", i32 9, i32 0, !254, i32 2, i32 1, i8 1, i32 29, i8 0, i8 0, i8 0, i32 0}
+!254 = !{i32 116}
+!127 = !{i32 117, !"A", i32 9, i32 0, !255, i32 2, i32 1, i8 1, i32 29, i8 1, i8 0, i8 0, i32 0}
+!255 = !{i32 117}
+!128 = !{i32 118, !"A", i32 9, i32 0, !256, i32 2, i32 1, i8 1, i32 29, i8 2, i8 0, i8 0, i32 0}
+!256 = !{i32 118}
+!129 = !{i32 119, !"A", i32 9, i32 0, !257, i32 2, i32 1, i8 1, i32 29, i8 3, i8 0, i8 0, i32 0}
+!257 = !{i32 119}
+!130 = !{i32 120, !"A", i32 9, i32 0, !258, i32 2, i32 1, i8 1, i32 30, i8 0, i8 0, i8 0, i32 0}
+!258 = !{i32 120}
+!131 = !{i32 121, !"A", i32 9, i32 0, !259, i32 2, i32 1, i8 1, i32 30, i8 1, i8 0, i8 0, i32 0}
+!259 = !{i32 121}
+!132 = !{i32 122, !"A", i32 9, i32 0, !260, i32 2, i32 1, i8 1, i32 30, i8 2, i8 0, i8 0, i32 0}
+!260 = !{i32 122}
+!133 = !{i32 123, !"A", i32 9, i32 0, !261, i32 2, i32 1, i8 1, i32 30, i8 3, i8 0, i8 0, i32 0}
+!261 = !{i32 123}
+!134 = !{i32 124, !"A", i32 9, i32 0, !262, i32 2, i32 1, i8 1, i32 31, i8 0, i8 0, i8 0, i32 0}
+!262 = !{i32 124}
+!135 = !{i32 125, !"A", i32 9, i32 0, !263, i32 2, i32 1, i8 1, i32 31, i8 1, i8 0, i8 0, i32 0}
+!263 = !{i32 125}
+!136 = !{i32 126, !"A", i32 9, i32 0, !264, i32 2, i32 1, i8 1, i32 31, i8 2, i8 0, i8 0, i32 0}
+!264 = !{i32 126}
+!137 = !{i32 127, !"A", i32 9, i32 0, !265, i32 2, i32 1, i8 1, i32 31, i8 3, i8 0, i8 0, i32 0}
+!265 = !{i32 127}
>From 6260d02e98bfc2c1baa14d938ad7b0eaf165b608 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:11:00 +0000
Subject: [PATCH 14/29] review: test each SV_Barycentrics interpolation keyword
for DXIL and SPIR-V
---
.../semantics/SV_Barycentrics-half.ps.hlsl | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
index f61da29007dd8a..7b22e06dff284f 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Barycentrics-half.ps.hlsl
@@ -1,20 +1,25 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=DXIL
-// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,PERSPECTIVE
-// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -DAFFINE -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,AFFINE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,DXIL-PERSPECTIVE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-pixel -fnative-half-type -finclude-default-header -DINTERPOLATION=linear -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,DXIL-PERSPECTIVE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-pixel -fnative-half-type -finclude-default-header -DINTERPOLATION=noperspective -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=DXIL,DXIL-AFFINE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-PERSPECTIVE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -DINTERPOLATION=linear -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-PERSPECTIVE
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -fnative-half-type -finclude-default-header -DINTERPOLATION=noperspective -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=SPIRV,SPIRV-AFFINE
-#ifdef AFFINE
-#define INTERPOLATION noperspective
-#else
-#define INTERPOLATION linear
+#ifndef INTERPOLATION
+#define INTERPOLATION
#endif
half4 main(INTERPOLATION half3 barycentrics : SV_Barycentrics) : SV_Target {
return half4(barycentrics, 1);
}
+// Without a keyword, SV_Barycentrics uses perspective-correct interpolation.
+
// DXIL-LABEL: define void @main()
// DXIL: call <3 x half> @llvm.dx.load.input.v3f16(i32 0, i32 0, i8 0, i32 poison)
// DXIL-NOT: @llvm.dx.load.input.v3f32
+// DXIL-PERSPECTIVE: !{i32 0, !"SV_Barycentrics", i32 8, i32 28, !{{[0-9]+}}, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+// DXIL-AFFINE: !{i32 0, !"SV_Barycentrics", i32 8, i32 28, !{{[0-9]+}}, i32 4, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
// The SPIR-V built-in must remain float3, not half3. Only the loaded value
// is truncated to the HLSL input's component type.
@@ -23,5 +28,5 @@ half4 main(INTERPOLATION half3 barycentrics : SV_Barycentrics) : SV_Target {
// SPIRV: [[BARY32:%.*]] = load <3 x float>, ptr addrspace(7) @SV_Barycentrics
// SPIRV-NEXT: [[BARY16:%.*]] = fptrunc <3 x float> [[BARY32]] to <3 x half>
// SPIRV: ![[BARY]] = !{![[BUILTIN:[0-9]+]]}
-// PERSPECTIVE: ![[BUILTIN]] = !{i32 11, i32 5286}
-// AFFINE: ![[BUILTIN]] = !{i32 11, i32 5287}
+// SPIRV-PERSPECTIVE: ![[BUILTIN]] = !{i32 11, i32 5286}
+// SPIRV-AFFINE: ![[BUILTIN]] = !{i32 11, i32 5287}
>From e5853804ed8c5da25a0c75b89fe90c0a4f65f5b9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:11:12 +0000
Subject: [PATCH 15/29] review: use CHECK- prefixes in the half barycentrics
container test
---
.../SemanticSignatures-barycentrics-half.ll | 76 +++++++++----------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
index 0788318d185494..2d4e1a5184d720 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
@@ -3,51 +3,51 @@
; RUN: cat %t/common.ll %t/native.ll > %t/native-input.ll
; RUN: llc -filetype=obj %t/min-input.ll -o %t/min.dxbc
; RUN: llc -filetype=obj %t/native-input.ll -o %t/native.dxbc
-; RUN: obj2yaml %t/min.dxbc | FileCheck %s --check-prefixes=PARTS,MIN
-; RUN: obj2yaml %t/native.dxbc | FileCheck %s --check-prefixes=PARTS,NATIVE
+; RUN: obj2yaml %t/min.dxbc | FileCheck %s --check-prefixes=CHECK-YAML,CHECK-YAML-MIN
+; RUN: obj2yaml %t/native.dxbc | FileCheck %s --check-prefixes=CHECK-YAML,CHECK-YAML-NATIVE
; RUN: llvm-objcopy --dump-section=DXIL=%t/min.bc %t/min.dxbc
; RUN: llvm-objcopy --dump-section=DXIL=%t/native.bc %t/native.dxbc
-; RUN: llvm-dis %t/min.bc -o - | FileCheck %s --check-prefixes=DXIL,MIN-MD
-; RUN: llvm-dis %t/native.bc -o - | FileCheck %s --check-prefixes=DXIL,NATIVE-MD
+; RUN: llvm-dis %t/min.bc -o - | FileCheck %s --check-prefixes=CHECK-DXIL,CHECK-DXIL-MIN
+; RUN: llvm-dis %t/native.bc -o - | FileCheck %s --check-prefixes=CHECK-DXIL,CHECK-DXIL-NATIVE
; Each interpolation is tested in its own valid single-declaration signature.
; F16 remains an ordinary loadInput overload in both precision modes. Its
; unallocated location must not change component-relative masks or consume rows.
-; MIN: MinimumPrecision: true
-; MIN: NativeLowPrecision: false
-; NATIVE: MinimumPrecision: false
-; NATIVE: NativeLowPrecision: true
-; PARTS: Name: ISG1
-; PARTS: Name: SV_Barycentrics
-; PARTS-NEXT: Index: 0
-; PARTS-NEXT: SystemValue: Barycentrics
-; PARTS-NEXT: CompType: Float16
-; PARTS-NEXT: Register: 4294967295
-; PARTS-NEXT: Mask: 7
-; PARTS-NEXT: ExclusiveMask: 4
-; MIN-NEXT: MinPrecision: Float16
-; NATIVE-NEXT: MinPrecision: Default
-; PARTS: Name: PSV0
-; MIN: SampleFrequency: 1
-; NATIVE: SampleFrequency: 0
-; PARTS: SigInputVectors: 0
-; PARTS: SigOutputVectors: [ 1, 0, 0, 0 ]
-; PARTS: SigInputElements:
-; PARTS: Indices: [ 0 ]
-; PARTS-NEXT: StartRow: 0
-; PARTS-NEXT: Cols: 3
-; PARTS-NEXT: StartCol: 0
-; PARTS-NEXT: Allocated: false
-; PARTS-NEXT: Kind: Barycentrics
-; MIN: Interpolation: LinearSample
-; NATIVE: Interpolation: LinearNoperspectiveCentroid
-; PARTS: InputOutputMap:
-; PARTS-NEXT: - [ ]
+; CHECK-YAML-MIN: MinimumPrecision: true
+; CHECK-YAML-MIN: NativeLowPrecision: false
+; CHECK-YAML-NATIVE: MinimumPrecision: false
+; CHECK-YAML-NATIVE: NativeLowPrecision: true
+; CHECK-YAML: Name: ISG1
+; CHECK-YAML: Name: SV_Barycentrics
+; CHECK-YAML-NEXT: Index: 0
+; CHECK-YAML-NEXT: SystemValue: Barycentrics
+; CHECK-YAML-NEXT: CompType: Float16
+; CHECK-YAML-NEXT: Register: 4294967295
+; CHECK-YAML-NEXT: Mask: 7
+; CHECK-YAML-NEXT: ExclusiveMask: 4
+; CHECK-YAML-MIN-NEXT: MinPrecision: Float16
+; CHECK-YAML-NATIVE-NEXT: MinPrecision: Default
+; CHECK-YAML: Name: PSV0
+; CHECK-YAML-MIN: SampleFrequency: 1
+; CHECK-YAML-NATIVE: SampleFrequency: 0
+; CHECK-YAML: SigInputVectors: 0
+; CHECK-YAML: SigOutputVectors: [ 1, 0, 0, 0 ]
+; CHECK-YAML: SigInputElements:
+; CHECK-YAML: Indices: [ 0 ]
+; CHECK-YAML-NEXT: StartRow: 0
+; CHECK-YAML-NEXT: Cols: 3
+; CHECK-YAML-NEXT: StartCol: 0
+; CHECK-YAML-NEXT: Allocated: false
+; CHECK-YAML-NEXT: Kind: Barycentrics
+; CHECK-YAML-MIN: Interpolation: LinearSample
+; CHECK-YAML-NATIVE: Interpolation: LinearNoperspectiveCentroid
+; CHECK-YAML: InputOutputMap:
+; CHECK-YAML-NEXT: - [ ]
-; DXIL: call half @dx.op.loadInput.f16(i32 4, i32 0, i32 0, i8 2, i32 {{.*}})
-; MIN-MD: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 6, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
-; NATIVE-MD: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 5, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
-; DXIL: ![[MASK]] = !{i32 3, i32 4}
+; CHECK-DXIL: call half @dx.op.loadInput.f16(i32 4, i32 0, i32 0, i8 2, i32 {{.*}})
+; CHECK-DXIL-MIN: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 6, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
+; CHECK-DXIL-NATIVE: !{i32 0, !"SV_Barycentrics", i8 8, i8 28, !{{[0-9]+}}, i8 5, i32 1, i8 3, i32 -1, i8 -1, ![[MASK:[0-9]+]]}
+; CHECK-DXIL: ![[MASK]] = !{i32 3, i32 4}
;--- common.ll
target triple = "dxil-pc-shadermodel6.2-pixel"
>From d04bc5cc806e971c11235e200fb76718c4ff83a2 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:11:33 +0000
Subject: [PATCH 16/29] review: align CHECK-NEXT groups in barycentrics
container tests
---
.../SemanticSignatures-barycentrics-half.ll | 6 +++---
.../ContainerData/SemanticSignatures-barycentrics.ll | 10 +++++-----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
index 2d4e1a5184d720..a58cee276a4852 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics-half.ll
@@ -18,7 +18,7 @@
; CHECK-YAML-NATIVE: MinimumPrecision: false
; CHECK-YAML-NATIVE: NativeLowPrecision: true
; CHECK-YAML: Name: ISG1
-; CHECK-YAML: Name: SV_Barycentrics
+; CHECK-YAML: Name: SV_Barycentrics
; CHECK-YAML-NEXT: Index: 0
; CHECK-YAML-NEXT: SystemValue: Barycentrics
; CHECK-YAML-NEXT: CompType: Float16
@@ -33,7 +33,7 @@
; CHECK-YAML: SigInputVectors: 0
; CHECK-YAML: SigOutputVectors: [ 1, 0, 0, 0 ]
; CHECK-YAML: SigInputElements:
-; CHECK-YAML: Indices: [ 0 ]
+; CHECK-YAML: Indices: [ 0 ]
; CHECK-YAML-NEXT: StartRow: 0
; CHECK-YAML-NEXT: Cols: 3
; CHECK-YAML-NEXT: StartCol: 0
@@ -41,7 +41,7 @@
; CHECK-YAML-NEXT: Kind: Barycentrics
; CHECK-YAML-MIN: Interpolation: LinearSample
; CHECK-YAML-NATIVE: Interpolation: LinearNoperspectiveCentroid
-; CHECK-YAML: InputOutputMap:
+; CHECK-YAML: InputOutputMap:
; CHECK-YAML-NEXT: - [ ]
; CHECK-DXIL: call half @dx.op.loadInput.f16(i32 4, i32 0, i32 0, i8 2, i32 {{.*}})
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
index 557369fcda72c3..382d4da2edd59d 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SemanticSignatures-barycentrics.ll
@@ -33,7 +33,7 @@ attributes #0 = { "hlsl.shader"="pixel" }
!6 = !{i32 0, !"SV_Target", i32 9, i32 16, !7, i32 0, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
!7 = !{i32 0}
-; ANALYSIS: Inputs: 2 elements, 1 vectors
+; ANALYSIS: Inputs: 2 elements, 1 vectors
; ANALYSIS-NEXT: 0: sv_barycentrics rows=1 cols=3 at 4294967295:255 usage=7 dynamic=0
; ANALYSIS-NEXT: 1: A rows=1 cols=4 at 0:0 usage=8 dynamic=0
; ANALYSIS-NEXT: Outputs: 1 elements, 1 vectors
@@ -50,7 +50,7 @@ attributes #0 = { "hlsl.shader"="pixel" }
; MD-DAG: !{i32 0, i64 4194304}
; PARTS: Name: ISG1
-; PARTS: Name: SV_Barycentrics
+; PARTS: Name: SV_Barycentrics
; PARTS-NEXT: Index: 0
; PARTS-NEXT: SystemValue: Barycentrics
; PARTS-NEXT: CompType: Float32
@@ -59,15 +59,15 @@ attributes #0 = { "hlsl.shader"="pixel" }
; PARTS-NEXT: ExclusiveMask: 7
; PARTS: Name: PSV0
; PARTS: SampleFrequency: 1
-; PARTS: SigInputVectors: 1
+; PARTS: SigInputVectors: 1
; PARTS-NEXT: SigOutputVectors: [ 1, 0, 0, 0 ]
; PARTS: SigInputElements:
-; PARTS: Indices: [ 0 ]
+; PARTS: Indices: [ 0 ]
; PARTS-NEXT: StartRow: 0
; PARTS-NEXT: Cols: 3
; PARTS-NEXT: StartCol: 0
; PARTS-NEXT: Allocated: false
; PARTS-NEXT: Kind: Barycentrics
; PARTS: Interpolation: LinearNoperspectiveSample
-; PARTS: InputOutputMap:
+; PARTS: InputOutputMap:
; PARTS-NEXT: - [ 0x0, 0x0, 0x0, 0x1 ]
>From 75609b18a959e397f917cf9038487f6e470552ab Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:12:16 +0000
Subject: [PATCH 17/29] review: make each barycentrics error case a
self-contained module
---
...semantic-signatures-barycentrics-errors.ll | 185 ++++++++++++------
1 file changed, 124 insertions(+), 61 deletions(-)
diff --git a/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
index f0aa56910b5384..18512971114f40 100644
--- a/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
+++ b/llvm/test/CodeGen/DirectX/Metadata/semantic-signatures-barycentrics-errors.ll
@@ -1,96 +1,137 @@
; RUN: split-file %s %t
-; RUN: cat %t/common.ll %t/integer.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
-; RUN: cat %t/common.ll %t/cols.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
-; RUN: cat %t/common.ll %t/rows.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=TYPE
-; RUN: cat %t/common.ll %t/index.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INDEX
-; RUN: cat %t/common.ll %t/constant.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INTERPOLATION
-; RUN: cat %t/common.ll %t/undefined.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=INTERPOLATION
-; RUN: cat %t/common.ll %t/allocated.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ALLOCATED
-; RUN: cat %t/common.ll %t/duplicate-index.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=DUPLICATE
-; RUN: cat %t/common.ll %t/id.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ID
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/vertex.ll 2>&1 | FileCheck %s --check-prefix=STAGE
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/output.ll 2>&1 | FileCheck %s --check-prefix=STAGE
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/sm60.ll 2>&1 | FileCheck %s --check-prefix=SM
-; RUN: cat %t/access-common.ll %t/access-type.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-TYPE
-; RUN: cat %t/access-common.ll %t/access-col.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-COL
-; RUN: cat %t/access-common.ll %t/access-row.ll > %t/test.ll
-; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/test.ll 2>&1 | FileCheck %s --check-prefix=ACCESS-ROW
-
-; TYPE: SV_Barycentrics requires one row of three 16- or 32-bit floating-point components
-; INDEX: SV_Barycentrics requires semantic index 0
-; INTERPOLATION: SV_Barycentrics requires perspective or noperspective interpolation
-; ALLOCATED: SV_Barycentrics must not have an allocated location
-; DUPLICATE: duplicate semantic name and index
-; ID: signature IDs must be dense and in list order
-; STAGE: invalid or unsupported semantic for this stage and signature category
-; SM: SV_Barycentrics requires shader model 6.1
-; ACCESS-TYPE: input signature element 0 ('SV_Barycentrics'): signature access type disagrees with its element
-; ACCESS-COL: input signature element 0 ('SV_Barycentrics'): signature access has an invalid component index
-; ACCESS-ROW: input signature element 0 ('SV_Barycentrics'): signature access has an invalid row index
-
-;--- common.ll
-; Individual cases supply the element list so malformed unallocated elements
-; must undergo the same semantic validation as packed elements.
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/integer.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/cols.ll 2>&1 | FileCheck %s --check-prefix=CHECK-COLS
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/rows.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ROWS
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/index.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INDEX
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/constant.ll 2>&1 | FileCheck %s --check-prefix=CHECK-CONSTANT
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/undefined.ll 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/allocated.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ALLOCATED
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/duplicate-index.ll 2>&1 | FileCheck %s --check-prefix=CHECK-DUPLICATE-INDEX
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/id.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ID
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/vertex.ll 2>&1 | FileCheck %s --check-prefix=CHECK-VERTEX
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/output.ll 2>&1 | FileCheck %s --check-prefix=CHECK-OUTPUT
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/sm60.ll 2>&1 | FileCheck %s --check-prefix=CHECK-SM60
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/access-type.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ACCESS-TYPE
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/access-col.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ACCESS-COL
+; RUN: not opt -disable-output -passes=dxil-translate-metadata %t/access-row.ll 2>&1 | FileCheck %s --check-prefix=CHECK-ACCESS-ROW
+
+; Each case is a complete module with one invalid SV_Barycentrics declaration.
+; Unallocated elements must undergo the same semantic validation as packed
+; elements.
+
+;--- integer.ll
+; CHECK-INTEGER: SV_Barycentrics requires one row of three 16- or 32-bit floating-point components
+; Integer component type.
target triple = "dxil-pc-shadermodel6.1-pixel"
define void @main() #0 { ret void }
attributes #0 = { "hlsl.shader"="pixel" }
!dx.semantic.signatures = !{!0}
!0 = !{ptr @main, !1, null}
-!3 = !{i32 0}
-
-;--- integer.ll
!1 = !{!2}
!2 = !{i32 0, !"SV_Barycentrics", i32 5, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- cols.ll
+; CHECK-COLS: SV_Barycentrics requires one row of three 16- or 32-bit floating-point components
+; Two columns instead of three.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 2, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- rows.ll
+; CHECK-ROWS: SV_Barycentrics requires one row of three 16- or 32-bit floating-point components
+; Two rows instead of one.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
-!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !5, i32 2, i32 2, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-!5 = !{i32 0, i32 1}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 2, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0, i32 1}
;--- index.ll
+; CHECK-INDEX: SV_Barycentrics requires semantic index 0
+; Semantic index 1.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
-!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !5, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-!5 = !{i32 1}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 1}
;--- constant.ll
+; CHECK-CONSTANT: SV_Barycentrics requires perspective or noperspective interpolation
+; Constant interpolation.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 1, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- undefined.ll
+; CHECK-UNDEFINED: SV_Barycentrics requires perspective or noperspective interpolation
+; Undefined interpolation.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 0, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- allocated.ll
+; CHECK-ALLOCATED: SV_Barycentrics must not have an allocated location
+; Allocated at row 0, column 0.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
!1 = !{!2}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 0, i8 0, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- duplicate-index.ll
-!1 = !{!2, !5}
+; CHECK-DUPLICATE-INDEX: duplicate semantic name and index
+; Index 0 is declared twice, with differently cased names.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2, !4}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-!5 = !{i32 1, !"sv_barycentrics", i32 9, i32 28, !3, i32 4, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+!4 = !{i32 1, !"sv_barycentrics", i32 9, i32 28, !3, i32 4, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
;--- id.ll
+; CHECK-ID: signature IDs must be dense and in list order
; An unallocated element still occupies ID 0, so the next ID must be 1.
-!1 = !{!2, !5}
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2, !4}
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-!5 = !{i32 2, !"A", i32 9, i32 0, !3, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+!4 = !{i32 2, !"A", i32 9, i32 0, !3, i32 2, i32 1, i8 1, i32 0, i8 0, i8 0, i8 0, i32 0}
;--- vertex.ll
+; CHECK-VERTEX: invalid or unsupported semantic for this stage and signature category
+; Vertex shader input.
target triple = "dxil-pc-shadermodel6.1-vertex"
define void @main() #0 { ret void }
attributes #0 = { "hlsl.shader"="vertex" }
@@ -101,6 +142,8 @@ attributes #0 = { "hlsl.shader"="vertex" }
!3 = !{i32 0}
;--- output.ll
+; CHECK-OUTPUT: invalid or unsupported semantic for this stage and signature category
+; Pixel shader output.
target triple = "dxil-pc-shadermodel6.1-pixel"
define void @main() #0 { ret void }
attributes #0 = { "hlsl.shader"="pixel" }
@@ -111,6 +154,8 @@ attributes #0 = { "hlsl.shader"="pixel" }
!3 = !{i32 0}
;--- sm60.ll
+; CHECK-SM60: SV_Barycentrics requires shader model 6.1
+; Shader model 6.0.
target triple = "dxil-pc-shadermodel6.0-pixel"
define void @main() #0 { ret void }
attributes #0 = { "hlsl.shader"="pixel" }
@@ -120,8 +165,14 @@ attributes #0 = { "hlsl.shader"="pixel" }
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
!3 = !{i32 0}
-;--- access-common.ll
+;--- access-type.ll
+; CHECK-ACCESS-TYPE: input signature element 0 ('SV_Barycentrics'): signature access type disagrees with its element
+; A half load from a float element.
target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 {
+ %x = call half @llvm.dx.load.input.f16(i32 0, i32 0, i8 0, i32 poison)
+ ret void
+}
attributes #0 = { "hlsl.shader"="pixel" }
!dx.semantic.signatures = !{!0}
!0 = !{ptr @main, !1, null}
@@ -129,20 +180,32 @@ attributes #0 = { "hlsl.shader"="pixel" }
!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
!3 = !{i32 0}
-;--- access-type.ll
-define void @main() #0 {
- %x = call half @llvm.dx.load.input.f16(i32 0, i32 0, i8 0, i32 poison)
- ret void
-}
-
;--- access-col.ll
+; CHECK-ACCESS-COL: input signature element 0 ('SV_Barycentrics'): signature access has an invalid component index
+; Component 3 of a three-component element.
+target triple = "dxil-pc-shadermodel6.1-pixel"
define void @main() #0 {
%x = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 3, i32 poison)
ret void
}
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
;--- access-row.ll
+; CHECK-ACCESS-ROW: input signature element 0 ('SV_Barycentrics'): signature access has an invalid row index
+; Row 1 of a single-row element.
+target triple = "dxil-pc-shadermodel6.1-pixel"
define void @main() #0 {
%x = call float @llvm.dx.load.input.f32(i32 0, i32 1, i8 0, i32 poison)
ret void
}
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
>From 42e1541dcc90a7b4c156a974951d7935909c3d95 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:12:31 +0000
Subject: [PATCH 18/29] review: split barycentrics shader flags test into two
files
---
.../ShaderFlags/barycentrics-obj-test.ll | 18 ++++++++++++++
.../DirectX/ShaderFlags/barycentrics.ll | 24 ++-----------------
2 files changed, 20 insertions(+), 22 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics-obj-test.ll
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics-obj-test.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics-obj-test.ll
new file mode 100644
index 00000000000000..7c72a1835431a6
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics-obj-test.ll
@@ -0,0 +1,18 @@
+; RUN: llc -filetype=obj %s -o %t.dxbc
+; RUN: obj2yaml %t.dxbc | FileCheck %s
+
+; An unused SV_Barycentrics input still sets the Barycentrics feature flag.
+target triple = "dxil-pc-shadermodel6.1-pixel"
+define void @main() #0 { ret void }
+attributes #0 = { "hlsl.shader"="pixel" }
+!dx.semantic.signatures = !{!0}
+!0 = !{ptr @main, !1, null}
+!1 = !{!2}
+!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
+!3 = !{i32 0}
+
+; CHECK: Name: SFI0
+; CHECK: Barycentrics: true
+; CHECK: Name: ISG1
+; CHECK: Name: SV_Barycentrics
+; CHECK: ExclusiveMask: 0
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
index 0625e5686914f3..5ca80ed4d20d65 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/barycentrics.ll
@@ -1,10 +1,6 @@
-; RUN: split-file %s %t
-; RUN: opt -disable-output -passes=print-dx-shader-flags %t/library.ll 2>&1 | FileCheck %s --check-prefix=LIB
-; RUN: opt -S -passes=dxil-translate-metadata %t/library.ll | FileCheck %s --check-prefix=MD
-; RUN: llc -filetype=obj %t/unused.ll -o %t.dxbc
-; RUN: obj2yaml %t.dxbc | FileCheck %s --check-prefix=OBJ
+; RUN: opt -disable-output -passes=print-dx-shader-flags %s 2>&1 | FileCheck %s --check-prefix=LIB
+; RUN: opt -S -passes=dxil-translate-metadata %s | FileCheck %s --check-prefix=MD
-;--- library.ll
; An unused declaration requires Barycentrics, but must not affect unrelated
; library entries or helper functions.
target triple = "dxil-pc-shadermodel6.8-library"
@@ -37,19 +33,3 @@ attributes #1 = { "hlsl.shader"="vertex" }
; MD-DAG: ![[VS]] = !{ptr @vertex, !"vertex", null, null, ![[VPROPS:[0-9]+]]}
; MD-DAG: ![[BPROPS]] = !{i32 8, i32 0}
; MD-DAG: ![[VPROPS]] = !{i32 8, i32 1}
-
-;--- unused.ll
-target triple = "dxil-pc-shadermodel6.1-pixel"
-define void @main() #0 { ret void }
-attributes #0 = { "hlsl.shader"="pixel" }
-!dx.semantic.signatures = !{!0}
-!0 = !{ptr @main, !1, null}
-!1 = !{!2}
-!2 = !{i32 0, !"SV_Barycentrics", i32 9, i32 28, !3, i32 2, i32 1, i8 3, i32 -1, i8 -1, i8 0, i8 0, i32 0}
-!3 = !{i32 0}
-
-; OBJ: Name: SFI0
-; OBJ: Barycentrics: true
-; OBJ: Name: ISG1
-; OBJ: Name: SV_Barycentrics
-; OBJ: ExclusiveMask: 0
>From 5c704d577fc305318d51ae54a2f60435baa42657 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:12:39 +0000
Subject: [PATCH 19/29] review: note that Sema diagnoses SV_Barycentrics in
other stages
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 8ed3c85914210d..d7a38dfe432ebe 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1507,7 +1507,8 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
switch (SemanticKind) {
case llvm::dxbc::PSV::SemanticKind::Barycentrics:
assert(Stage == llvm::Triple::Pixel &&
- "SV_Barycentrics is only available as a pixel shader input");
+ "SV_Barycentrics is in an unavailable stage and should have been "
+ "diagnosed by Sema");
if (CGM.getTarget().getTriple().isSPIRV()) {
using llvm::dxbc::PSV::InterpolationMode;
// Perspective is encoded by the built-in; only sampling decorations
>From bd73bc8f91d30a53fbd2a8153f130e386e58a7f4 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:13:17 +0000
Subject: [PATCH 20/29] review: keep NV barycentric built-in names as aliases
---
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 4 +++
.../builtin-names-nv.ll | 35 +++++++++++++++++++
2 files changed, 39 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names-nv.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 7d6162cdab3723..85cdb8aaa41600 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -1550,6 +1550,10 @@ defm MeshViewCountNV : BuiltInOperand<5280, 0, 0, [], [MeshShadingNV]>;
defm MeshViewIndices : BuiltInOperand<5281, 0, 0, [], [MeshShadingNV]>;
defm BaryCoordKHR : BuiltInOperand<5286, 0, 0, [SPV_KHR_fragment_shader_barycentric], [FragmentBarycentricKHR]>;
defm BaryCoordNoPerspKHR : BuiltInOperand<5287, 0, 0, [SPV_KHR_fragment_shader_barycentric], [FragmentBarycentricKHR]>;
+// NV aliases keep their names recognized. Requirements are looked up by value,
+// so they come from the KHR records above.
+defm BaryCoordNV : BuiltInOperand<5286, 0, 0, [], []>;
+defm BaryCoordNoPerspNV : BuiltInOperand<5287, 0, 0, [], []>;
defm FragSizeEXT : BuiltInOperand<5292, 0, 0, [], [FragmentDensityEXT]>;
defm FragInvocationCountEXT : BuiltInOperand<5293, 0, 0, [], [FragmentDensityEXT]>;
defm LaunchIdNV : BuiltInOperand<5319, 0, 0, [], [RayTracingNV]>;
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names-nv.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names-nv.ll
new file mode 100644
index 00000000000000..31ddb9dbca5e5f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_fragment_shader_barycentric/builtin-names-nv.ll
@@ -0,0 +1,35 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - | FileCheck %s --implicit-check-not='BuiltIn BaryCoordNV' --implicit-check-not='BuiltIn BaryCoordNoPerspNV'
+; RUN: not llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel -spirv-ext=+SPV_KHR_fragment_shader_barycentric %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; The NV built-in names are aliases of the KHR built-ins, so they are still
+; recognized and get the same decorations and requirements.
+; CHECK-ERROR: LLVM ERROR: Barycentric built-ins require the following SPIR-V extension: SPV_KHR_fragment_shader_barycentric
+; CHECK-DAG: OpCapability FragmentBarycentricKHR
+; CHECK-DAG: OpExtension "SPV_KHR_fragment_shader_barycentric"
+; CHECK-DAG: OpDecorate %[[#NOPERSP:]] BuiltIn BaryCoordNoPerspKHR
+; CHECK-DAG: OpDecorate %[[#BARY:]] BuiltIn BaryCoordKHR
+; CHECK-DAG: %[[#FLOAT:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#FLOAT3:]] = OpTypeVector %[[#FLOAT]] 3
+; CHECK-DAG: %[[#INPUT:]] = OpTypePointer Input %[[#FLOAT3]]
+; CHECK-DAG: %[[#NOPERSP]] = OpVariable %[[#INPUT]] Input
+; CHECK-DAG: %[[#BARY]] = OpVariable %[[#INPUT]] Input
+
+ at __spirv_BuiltInBaryCoordNoPerspNV = external hidden addrspace(7) constant <3 x float>
+ at __spirv_BuiltInBaryCoordNV = external hidden addrspace(7) constant <3 x float>
+ at target = external hidden addrspace(8) global <3 x float>, !spirv.Decorations !0
+
+define void @main() #0 {
+; CHECK: OpLoad %[[#FLOAT3]] %[[#NOPERSP]]
+; CHECK: OpLoad %[[#FLOAT3]] %[[#BARY]]
+ %noperspective = load <3 x float>, ptr addrspace(7) @__spirv_BuiltInBaryCoordNoPerspNV, align 16
+ %perspective = load <3 x float>, ptr addrspace(7) @__spirv_BuiltInBaryCoordNV, align 16
+ %sum = fadd <3 x float> %noperspective, %perspective
+ store <3 x float> %sum, ptr addrspace(8) @target, align 16
+ ret void
+}
+
+attributes #0 = { "hlsl.shader"="pixel" }
+
+!0 = !{!1}
+!1 = !{i32 30, i32 0}
>From 03cfed0210ec4a20739b794c5026abf928229178 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 20 Oct 2026 20:48:01 +0000
Subject: [PATCH 21/29] clang format
---
llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
index e6562f558d8dca..d652ac24321fb7 100644
--- a/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DXILSignatureAnalysis.cpp
@@ -598,9 +598,9 @@ static void buildPSVElements(SmallVectorImpl<mcdxbc::PSVSignatureElement> &Dest,
: StringRef(),
E.SemanticIndices,
E.isAllocated() ? static_cast<uint8_t>(E.StartRow) : uint8_t(0),
- E.Cols, E.getStartColOrZero(), E.isAllocated(),
- E.SemanticKind, static_cast<dxbc::PSV::ComponentType>(Type),
- E.InterpMode, E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
+ E.Cols, E.getStartColOrZero(), E.isAllocated(), E.SemanticKind,
+ static_cast<dxbc::PSV::ComponentType>(Type), E.InterpMode,
+ E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
}
}
>From 23ea4df7932d214fff286c20a656c91d5f587c06 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:30:02 +0000
Subject: [PATCH 22/29] review: use llvm::hlsl::InterpolationMode for
SV_Barycentrics lowering
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index d7a38dfe432ebe..b74682d4b5f2e0 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1510,7 +1510,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
"SV_Barycentrics is in an unavailable stage and should have been "
"diagnosed by Sema");
if (CGM.getTarget().getTriple().isSPIRV()) {
- using llvm::dxbc::PSV::InterpolationMode;
+ using llvm::hlsl::InterpolationMode;
// Perspective is encoded by the built-in; only sampling decorations
// belong on the interface variable.
bool NoPerspective = false;
>From ea6646ea14ec8a9fbb91bffb72d677551a142b34 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:30:14 +0000
Subject: [PATCH 23/29] review: load SV_Barycentrics through
createSPIRVInputLoad with SPIRVInterfaceDecoration::BuiltIn
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index b74682d4b5f2e0..229bec71bb50ee 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1532,8 +1532,9 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
}
// SPIR-V barycentric built-ins are float3, even for half3 inputs.
llvm::Type *BuiltinType = llvm::FixedVectorType::get(CGM.FloatTy, 3);
- llvm::Value *Barycentrics = createSPIRVBuiltinLoad(
+ llvm::Value *Barycentrics = createSPIRVInputLoad(
B, CGM.getModule(), BuiltinType, Semantic->getSemanticName(),
+ llvm::hlsl::SPIRVInterfaceDecoration::BuiltIn,
NoPerspective ? /* BuiltIn::BaryCoordNoPerspKHR */ 5287
: /* BuiltIn::BaryCoordKHR */ 5286,
InterpMode);
>From 151cce491aeeac842ef92070836219a6d5451d95 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:30:31 +0000
Subject: [PATCH 24/29] review: use err_hlsl_semantic_in_wrong_shader_model for
SV_Barycentrics
---
clang/lib/Sema/SemaHLSL.cpp | 2 +-
clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2eb97f144afded..32a3d08bb2c797 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1288,7 +1288,7 @@ void SemaHLSL::diagnoseSemanticShaderModel(const HLSLAppliedSemanticAttr *A,
switch (Kind) {
case SemanticKind::Barycentrics:
if (Triple.getOSVersion() < VersionTuple(6, 1))
- Diag(A->getLoc(), diag::err_hlsl_attribute_in_wrong_shader_model)
+ Diag(A->getLoc(), diag::err_hlsl_semantic_in_wrong_shader_model)
<< A->getAttrName() << "6.1";
return;
default:
diff --git a/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl b/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
index f947d3709a83b2..8f97ea322588f8 100644
--- a/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
+++ b/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
@@ -3,4 +3,4 @@
// valid-no-diagnostics
float4 main(float3 b : SV_Barycentrics) : SV_Target { return float4(b, 1); }
-// old-error at -1 {{attribute 'SV_Barycentrics' requires shader model 6.1 or greater}}
+// old-error at -1 {{semantic 'SV_Barycentrics' requires shader model 6.1 or greater}}
>From d266f1c9cbf8a63818b1fdb90229611f297bba53 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:30:52 +0000
Subject: [PATCH 25/29] review: move the SV_ShadingRate shader model check into
diagnoseSemanticShaderModel
---
clang/lib/Sema/SemaHLSL.cpp | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 32a3d08bb2c797..f3fd1fb68c0727 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1256,17 +1256,6 @@ void SemaHLSL::checkSemanticAnnotation(
return;
}
- // DXIL only: SV_ShadingRate requires shader model 6.4.
- if (Kind == SemanticKind::ShadingRate) {
- const llvm::Triple &TT = getASTContext().getTargetInfo().getTriple();
- if (TT.isDXIL() && TT.getOSVersion() < VersionTuple(6, 4)) {
- Diag(SemanticAttr->getLoc(),
- diag::err_hlsl_semantic_in_wrong_shader_model)
- << SemanticAttr->getAttrName() << "6.4";
- return;
- }
- }
-
// A system-value name can have an arbitrary interpretation, for example
// SV_Position on a vertex input. Only the general type restrictions apply.
if (Interpretation == llvm::hlsl::SemanticInterpretation::Arbitrary) {
@@ -1291,6 +1280,11 @@ void SemaHLSL::diagnoseSemanticShaderModel(const HLSLAppliedSemanticAttr *A,
Diag(A->getLoc(), diag::err_hlsl_semantic_in_wrong_shader_model)
<< A->getAttrName() << "6.1";
return;
+ case SemanticKind::ShadingRate:
+ if (Triple.getOSVersion() < VersionTuple(6, 4))
+ Diag(A->getLoc(), diag::err_hlsl_semantic_in_wrong_shader_model)
+ << A->getAttrName() << "6.4";
+ return;
default:
return;
}
>From ac751f636e83245cb2988af5e5f017301874118f Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:31:10 +0000
Subject: [PATCH 26/29] review: use expectOnlySignaturePoints for the
SV_Barycentrics stages test
---
.../unittests/Frontend/HLSLSemanticStagesTest.cpp | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
index 14114b0ffc59d2..6454530ed824c7 100644
--- a/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
+++ b/llvm/unittests/Frontend/HLSLSemanticStagesTest.cpp
@@ -155,14 +155,13 @@ TEST(HLSLSemanticStagesTest, ShadingRateSignaturePoints) {
expectOnlySignaturePoints(SemanticKind::ShadingRate, Valid);
}
-TEST(HLSLSemanticStagesTest, BarycentricsAreUnpackedPixelInputs) {
- for (Triple::EnvironmentType Stage : AllStages)
- for (IOType IO :
- {IOType::In, IOType::Out, IOType::PatchConstantOrPrimitive})
- EXPECT_EQ(getInterpretationKind(SemanticKind::Barycentrics, Stage, IO),
- Stage == Triple::Pixel && IO == IOType::In
- ? SemanticInterpretation::NotPacked
- : SemanticInterpretation::Invalid);
+// SV_Barycentrics is generated by the rasterizer and read by the pixel shader.
+// Valid only on pixel inputs, where it is in the signature but not packed.
+TEST(HLSLSemanticStagesTest, BarycentricsSignaturePoints) {
+ const SignaturePoint Valid[] = {
+ {Triple::Pixel, IOType::In, SemanticInterpretation::NotPacked},
+ };
+ expectOnlySignaturePoints(SemanticKind::Barycentrics, Valid);
}
} // namespace
>From 50971dca370df83deb2395cf7f92d85908dba520 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:31:31 +0000
Subject: [PATCH 27/29] review: rename SV_Barycentrics Sema tests to the
<semantic>.<variant>.hlsl convention
---
...{SV_Barycentrics-shader-model.hlsl => barycentrics.model.hlsl} | 0
.../Semantics/{SV_Barycentrics.hlsl => barycentrics.ps.hlsl} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename clang/test/SemaHLSL/Semantics/{SV_Barycentrics-shader-model.hlsl => barycentrics.model.hlsl} (100%)
rename clang/test/SemaHLSL/Semantics/{SV_Barycentrics.hlsl => barycentrics.ps.hlsl} (100%)
diff --git a/clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl b/clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl
similarity index 100%
rename from clang/test/SemaHLSL/Semantics/SV_Barycentrics-shader-model.hlsl
rename to clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl
diff --git a/clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl b/clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl
similarity index 100%
rename from clang/test/SemaHLSL/Semantics/SV_Barycentrics.hlsl
rename to clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl
>From 593601d051bb281ccfc29b3d4aa2b007343fc416 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:31:36 +0000
Subject: [PATCH 28/29] review: check SV_Barycentrics shader model diagnostics
for SPIR-V in barycentrics.model.hlsl
---
.../SemaHLSL/Semantics/barycentrics.model.hlsl | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl b/clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl
index 8f97ea322588f8..9e52041e3f163f 100644
--- a/clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl
+++ b/clang/test/SemaHLSL/Semantics/barycentrics.model.hlsl
@@ -1,6 +1,14 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -finclude-default-header -fsyntax-only -verify=old %s
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-pixel -finclude-default-header -fsyntax-only -verify=valid %s
-// valid-no-diagnostics
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -finclude-default-header -x hlsl -verify=dxil -o - %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.1-library -finclude-default-header -x hlsl -verify=ok -o - %s
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -finclude-default-header -x hlsl -verify=ok -o - %s
-float4 main(float3 b : SV_Barycentrics) : SV_Target { return float4(b, 1); }
-// old-error at -1 {{semantic 'SV_Barycentrics' requires shader model 6.1 or greater}}
+// SV_Barycentrics requires shader model 6.1 for DXIL.
+// The shader model does not apply to SPIR-V, which is only run to check that no error is emitted.
+
+[shader("pixel")]
+float4 ps_in(float3 b : SV_Barycentrics) : SV_Target {
+// dxil-error at -1 {{semantic 'SV_Barycentrics' requires shader model 6.1 or greater}}
+ return float4(b, 1);
+}
+
+// ok-no-diagnostics
>From 33a7c900de898259d4bc2aad122807b15d03d1fe Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 23 Oct 2026 16:31:49 +0000
Subject: [PATCH 29/29] review: split SV_Barycentrics stage checks into
barycentrics.stages.hlsl
---
.../SemaHLSL/Semantics/barycentrics.ps.hlsl | 12 +++------
.../Semantics/barycentrics.stages.hlsl | 27 +++++++++++++++++++
2 files changed, 31 insertions(+), 8 deletions(-)
create mode 100644 clang/test/SemaHLSL/Semantics/barycentrics.stages.hlsl
diff --git a/clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl b/clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl
index dfc945e1f6e9e2..25de860b5dc454 100644
--- a/clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl
+++ b/clang/test/SemaHLSL/Semantics/barycentrics.ps.hlsl
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-library -fnative-half-type -fnative-int16-type -finclude-default-header -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -DSPIRV -fnative-half-type -fnative-int16-type -finclude-default-header -fsyntax-only -verify %s
+// Type, index and interpolation checks for SV_Barycentrics. These are
+// independent of the shader stage and IO direction, which are covered by
+// barycentrics.stages.hlsl.
+
[shader("pixel")]
float4 valid(float3 p : SV_Barycentrics0) : SV_Target {
return float4(p, 1);
@@ -66,14 +70,6 @@ void inherited_affine(noperspective Input i) {}
[shader("pixel")]
void field_override(linear AffineInput i) {}
-[shader("vertex")]
-float4 wrong_stage(float3 b : SV_Barycentrics) : SV_Position { return 0; }
-// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in vertex shader inputs}}
-
-[shader("pixel")]
-float3 wrong_output() : SV_Barycentrics { return 0; }
-// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in pixel shader outputs}}
-
#ifdef SPIRV
[shader("pixel")]
float4 explicit_location(float3 b : SV_Barycentrics,
diff --git a/clang/test/SemaHLSL/Semantics/barycentrics.stages.hlsl b/clang/test/SemaHLSL/Semantics/barycentrics.stages.hlsl
new file mode 100644
index 00000000000000..e8842dc902c381
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/barycentrics.stages.hlsl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-library -finclude-default-header -x hlsl -verify -o - %s
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -finclude-default-header -x hlsl -verify -o - %s
+
+// Stage and IO direction checks for SV_Barycentrics: only a pixel input.
+// Type, index and interpolation checks are covered by barycentrics.ps.hlsl.
+
+[shader("pixel")]
+float4 ok_ps_in(float3 b : SV_Barycentrics) : SV_Target {
+ return float4(b, 1);
+}
+
+[shader("vertex")]
+float4 wrong_stage(float3 b : SV_Barycentrics) : SV_Position { return 0; }
+// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in vertex shader inputs}}
+
+[shader("pixel")]
+float3 wrong_output() : SV_Barycentrics { return 0; }
+// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in pixel shader outputs}}
+
+static float3 g;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void bad_cs_in(float3 b : SV_Barycentrics) {
+// expected-error at -1 {{semantic 'SV_Barycentrics' is not supported in compute shader inputs}}
+ g = b;
+}
More information about the cfe-commits
mailing list