1//===- SemanticSignaturePacking.cpp - HLSL signature packing helpers -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file This file implements helpers for packing HLSL semantic signatures.
10///
11//===----------------------------------------------------------------------===//
12
13#include "llvm/Frontend/HLSL/SemanticSignaturePacking.h"
14#include "llvm/ADT/STLExtras.h"
15#include <algorithm>
16#include <cassert>
17#include <cstdint>
18#include <limits>
19
20using namespace llvm;
21using namespace llvm::hlsl;
22
23char SignaturePackingError::ID;
24
25void SignaturePackingError::log(raw_ostream &OS) const {
26 switch (Kind) {
27 case SignatureOverflow:
28 OS << "signature elements do not fit in " << MaxSignatureRows << " rows";
29 break;
30 case SemanticIndexOutOfRange:
31 OS << "semantic index must be less than " << MaxSignatureRows;
32 break;
33 }
34 OS << " (element " << ElementIndex << ")";
35}
36
37Expected<unsigned> llvm::hlsl::packSignatureStacked(
38 MutableArrayRef<SemanticSignatureElement> Elements,
39 Triple::EnvironmentType ShaderStage, IOType IOTy) {
40 assert(ShaderStage == Triple::Vertex && IOTy == IOType::In &&
41 "stacked packing is only valid for a vertex shader input signature");
42
43 unsigned NextRow = 0;
44 for (auto &&[Index, Element] : enumerate(First&: Elements)) {
45 assert(Element.StartRow == UnallocatedRow &&
46 Element.StartCol == UnallocatedCol && "already allocated?");
47 assert(Element.Rows > 0 && "signature element must have at least one row");
48 assert(Element.Cols > 0 && Element.Cols <= MaxSignatureCols &&
49 "signature element must have between 1 and 4 columns");
50
51 SemanticInterpretation Interpretation =
52 getInterpretationKind(SemanticKind: Element.SemanticKind, ShaderStage, IOTy);
53 if (Interpretation == SemanticInterpretation::NotAllocated)
54 continue;
55
56 assert((Interpretation == SemanticInterpretation::Arbitrary ||
57 Interpretation == SemanticInterpretation::SV ||
58 Interpretation == SemanticInterpretation::SGV) &&
59 "unexpected semantic interpretation for stacked packing, should "
60 "have been diagnosed by Sema");
61
62 if (Element.Rows > MaxSignatureRows - NextRow)
63 return make_error<SignaturePackingError>(
64 Args: SignaturePackingError::SignatureOverflow,
65 Args: static_cast<unsigned>(Index));
66
67 Element.StartRow = NextRow;
68 Element.StartCol = 0;
69 NextRow += Element.Rows;
70 }
71
72 return NextRow;
73}
74
75Expected<unsigned> llvm::hlsl::packSignatureIndexed(
76 MutableArrayRef<SemanticSignatureElement> Elements,
77 Triple::EnvironmentType ShaderStage, IOType IOTy) {
78 assert(ShaderStage == Triple::Pixel && IOTy == IOType::Out &&
79 "indexed packing is only valid for a pixel shader output signature");
80
81 static_assert(MaxSignatureRows <= std::numeric_limits<uint32_t>::digits,
82 "row allocation mask is too small");
83 [[maybe_unused]] uint32_t AllocatedRows = 0;
84 unsigned NumRows = 0;
85 for (auto &&[Index, Element] : enumerate(First&: Elements)) {
86 assert(Element.StartRow == UnallocatedRow &&
87 Element.StartCol == UnallocatedCol && "already allocated?");
88 assert(Element.Rows > 0 && "signature element must have at least one row");
89 assert(Element.Cols > 0 && Element.Cols <= MaxSignatureCols &&
90 "signature element must have between 1 and 4 columns");
91
92 SemanticInterpretation Interpretation =
93 getInterpretationKind(SemanticKind: Element.SemanticKind, ShaderStage, IOTy);
94 if (Interpretation == SemanticInterpretation::NotAllocated)
95 continue;
96
97 assert(Interpretation == SemanticInterpretation::Target &&
98 "unexpected semantic interpretation for indexed packing, should "
99 "have been diagnosed by Sema");
100 assert(Element.Rows == 1 && Element.SemanticIndices.size() == 1 &&
101 "target elements must occupy one semantic row");
102
103 const uint32_t Row = Element.SemanticIndices.front();
104 if (Row >= MaxSignatureRows)
105 return make_error<SignaturePackingError>(
106 Args: SignaturePackingError::SemanticIndexOutOfRange,
107 Args: static_cast<unsigned>(Index));
108
109 const uint32_t RowMask = uint32_t{1} << Row;
110 assert(!(AllocatedRows & RowMask) &&
111 "target semantic indices must be unique, verified in SemaHLSL");
112 AllocatedRows |= RowMask;
113
114 Element.StartRow = Row;
115 Element.StartCol = 0;
116 NumRows = std::max(a: NumRows, b: Row + 1);
117 }
118
119 return NumRows;
120}
121