[llvm] [HLSLSemanticSignatures] Implement the optimal packing of elements (PR #218064)
Helena Kotas via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 21:03:00 PDT 2026
================
@@ -1547,6 +1795,239 @@ TEST_F(HLSLSemanticSignaturePackingTest,
}
}
+TEST_F(HLSLSemanticSignaturePackingTest, OptimizedPreservesPartialAllocation) {
+ // Declaration order is Small, Full, Last. Optimized packing places Full
+ // first, then fails on Small. Report Small's original index (zero), not its
+ // index in packing order (one). Preserve Full's allocation for ordinary
+ // elements, but leave the entire clip/cull phase unallocated on failure.
+ //
+ // struct VSOut {
+ // float2 Small : Small;
+ // float4 Full[32] : Full;
+ // float Last : Last;
+ // };
+ // The clip/cull case uses clip-distance semantics and Full[2] instead.
+ for (bool IsClipCull : {false, true}) {
+ SCOPED_TRACE(IsClipCull);
+ const auto Kind = IsClipCull ? dxbc::PSV::SemanticKind::ClipDistance
+ : dxbc::PSV::SemanticKind::Arbitrary;
+ const unsigned RowCount = IsClipCull ? MaxClipCullRows : MaxSignatureRows;
+ TestConfig Config(
+ Triple::Vertex, IOType::Out,
+ {{Kind, /*Rows=*/1, /*Cols=*/2, dxil::ElementType::F32,
+ dxbc::PSV::InterpolationMode::Linear},
+ {Kind, RowCount, /*Cols=*/MaxSignatureCols, dxil::ElementType::F32,
+ dxbc::PSV::InterpolationMode::Linear},
+ {Kind, /*Rows=*/1, /*Cols=*/1, dxil::ElementType::F32,
+ dxbc::PSV::InterpolationMode::Linear}});
+ verifyPackingError(PackingMethod::Optimized, Config,
+ IsClipCull ? SignaturePackingError::ClipCullOverflow
+ : SignaturePackingError::SignatureOverflow,
+ /*ExpectedElementIndex=*/0);
+
+ SmallVector<SemanticSignatureElement> Elements = makeSignature(Config);
+ EXPECT_THAT_EXPECTED(
+ pack(PackingMethod::Optimized, Elements, Config),
+ FailedWithMessage(
+ std::string(IsClipCull ? "clip/cull elements do not fit in "
+ : "signature elements do not fit in ") +
+ std::to_string(RowCount) + " rows (element 0)"));
+ EXPECT_EQ(Elements[1].StartRow, IsClipCull ? UnallocatedRow : 0u);
+ EXPECT_EQ(Elements[1].StartCol, IsClipCull ? UnallocatedCol : 0u);
+ for (unsigned I : {0u, 2u}) {
+ EXPECT_EQ(Elements[I].StartRow, UnallocatedRow) << "element " << I;
+ EXPECT_EQ(Elements[I].StartCol, UnallocatedCol) << "element " << I;
+ }
+ for (unsigned I = 0; I != Elements.size(); ++I) {
+ EXPECT_EQ(Elements[I].SigId, I) << "element " << I;
+ EXPECT_EQ(Elements[I].Rows, Config.Elements[I].Rows) << "element " << I;
+ EXPECT_EQ(Elements[I].Cols, Config.Elements[I].Cols) << "element " << I;
+ }
+ }
+}
+
+TEST_F(HLSLSemanticSignaturePackingTest,
+ OptimizedSingleRowClipCullFailureIsAtomic) {
+ // struct VSOut {
+ // float2 Clip1 : SV_ClipDistance1;
+ // float4 Fill[31] : FILL;
+ // float Cull : SV_CullDistance0;
+ // float3 Clip0 : SV_ClipDistance0;
+ // };
+ // The first bundle (Clip0 + Cull) fits in row 31, but Clip1's bundle fails.
+ // Neither bundle is published; only the preceding Fill allocation remains.
+ TestConfig Config(
+ Triple::Vertex, IOType::Out,
+ {{dxbc::PSV::SemanticKind::ClipDistance, /*Rows=*/1, /*Cols=*/2,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear,
+ /*SemanticIndex=*/1},
+ {dxbc::PSV::SemanticKind::Arbitrary, /*Rows=*/MaxSignatureRows - 1,
+ /*Cols=*/4, dxil::ElementType::F32,
+ dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::CullDistance, /*Rows=*/1, /*Cols=*/1,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::ClipDistance, /*Rows=*/1, /*Cols=*/3,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear}});
+ verifyPackingError(PackingMethod::Optimized, Config,
+ SignaturePackingError::SignatureOverflow,
+ /*ExpectedElementIndex=*/0);
+ SmallVector<SemanticSignatureElement> Elements = makeSignature(Config);
+ const SmallVector<SemanticSignatureElement> Before = Elements;
+ EXPECT_THAT_EXPECTED(pack(PackingMethod::Optimized, Elements, Config),
+ FailedWithMessage("signature elements do not fit in " +
+ std::to_string(MaxSignatureRows) +
+ " rows (element 0)"));
+ EXPECT_EQ(Elements[1].StartRow, 0u);
+ EXPECT_EQ(Elements[1].StartCol, 0u);
+ for (unsigned I : {0u, 2u, 3u}) {
+ EXPECT_EQ(Elements[I].StartRow, UnallocatedRow) << "element " << I;
+ EXPECT_EQ(Elements[I].StartCol, UnallocatedCol) << "element " << I;
+ }
+ for (unsigned I = 0; I != Elements.size(); ++I) {
+ SCOPED_TRACE(I);
+ verifyMetadata(Before[I], Elements[I]);
+ }
+}
+
+TEST_F(HLSLSemanticSignaturePackingTest,
+ OptimizedIndexedClipCullFailureIsAtomic) {
+ // struct VSOut {
+ // float2 Cull : SV_CullDistance0;
+ // float4 Fill[30] : FILL;
+ // float A[2] : A;
+ // float2 Clip[2] : SV_ClipDistance0;
+ // };
+ // The final pair fits Clip in yz but not Cull.xy. Do not retain Clip's
+ // speculative allocation. The error identifies Clip, first in group order.
+ TestConfig Config(
+ Triple::Vertex, IOType::Out,
+ {{dxbc::PSV::SemanticKind::CullDistance, /*Rows=*/1, /*Cols=*/2,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::Arbitrary, /*Rows=*/MaxSignatureRows - 2,
+ /*Cols=*/4, dxil::ElementType::F32,
+ dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::Arbitrary, /*Rows=*/2, /*Cols=*/1,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear},
+ {dxbc::PSV::SemanticKind::ClipDistance, /*Rows=*/2, /*Cols=*/2,
+ dxil::ElementType::F32, dxbc::PSV::InterpolationMode::Linear}});
+ verifyPackingError(PackingMethod::Optimized, Config,
+ SignaturePackingError::SignatureOverflow,
+ /*ExpectedElementIndex=*/3);
+ SmallVector<SemanticSignatureElement> Elements = makeSignature(Config);
+ const SmallVector<SemanticSignatureElement> Before = Elements;
+ EXPECT_THAT_EXPECTED(pack(PackingMethod::Optimized, Elements, Config),
+ FailedWithMessage("signature elements do not fit in " +
+ std::to_string(MaxSignatureRows) +
+ " rows (element 3)"));
+ EXPECT_EQ(Elements[1].StartRow, 0u);
+ EXPECT_EQ(Elements[1].StartCol, 0u);
+ EXPECT_EQ(Elements[2].StartRow, MaxSignatureRows - 2);
+ EXPECT_EQ(Elements[2].StartCol, 0u);
+ for (unsigned I : {0u, 3u}) {
+ EXPECT_EQ(Elements[I].StartRow, UnallocatedRow) << "element " << I;
+ EXPECT_EQ(Elements[I].StartCol, UnallocatedCol) << "element " << I;
+ }
+ for (unsigned I = 0; I != Elements.size(); ++I) {
+ SCOPED_TRACE(I);
+ verifyMetadata(Before[I], Elements[I]);
+ }
+}
+
+TEST_F(HLSLSemanticSignaturePackingTest,
+ OptimizedClipCullFailureIsAtomicAcrossStreams) {
+ const struct {
+ unsigned Rows;
+ unsigned Stream;
+ SignaturePackingError::ErrorKind Kind;
+ } Failures[] = {
+ {1, 1, SignaturePackingError::SignatureOverflow},
+ {3, 1, SignaturePackingError::ClipCullOverflow},
+ {1, MaxGeometryStreams, SignaturePackingError::InvalidGeometryStream}};
+ for (const auto &Failure : Failures) {
----------------
hekota wrote:
Could you please add a comment that shows what the struct to be packed looks like? It is missing here and in many other tests below.
https://github.com/llvm/llvm-project/pull/218064
More information about the llvm-commits
mailing list