1//===- SemanticSignatures.cpp - HLSL Semantic Signature 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 a library for working with HLSL shader input and
10/// output semantic signatures and their DirectX metadata representation.
11///
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Frontend/HLSL/SemanticSignatures.h"
15#include "llvm/ADT/Enum.h"
16#include "llvm/ADT/STLForwardCompat.h"
17#include "llvm/IR/Constants.h"
18#include "llvm/IR/Metadata.h"
19#include "llvm/IR/Type.h"
20
21using namespace llvm;
22using namespace llvm::hlsl;
23
24namespace {
25
26// Inclusive upper bounds of the operand enums
27constexpr uint32_t MaxCompType =
28 static_cast<uint32_t>(dxil::ElementType::LastEntry);
29constexpr uint32_t MaxSemanticKind =
30 static_cast<uint32_t>(dxbc::PSV::SemanticKind::Invalid);
31constexpr uint32_t MaxInterpMode =
32 static_cast<uint32_t>(dxbc::PSV::InterpolationMode::Invalid);
33
34Error makeError(const Twine &Msg) {
35 return createStringError(EC: inconvertibleErrorCode(), S: Msg);
36}
37
38Expected<uint64_t> extractInt(const MDNode *Node, unsigned OpId) {
39 auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD: Node->getOperand(I: OpId));
40 if (!CI)
41 return makeError(Msg: "expected integer operand " + Twine(OpId));
42 return CI->getZExtValue();
43}
44} // namespace
45
46dxbc::PSV::SemanticKind hlsl::getSemanticKind(StringRef SemanticName) {
47 if (!SemanticName.consume_front_insensitive(Prefix: "SV_"))
48 return dxbc::PSV::SemanticKind::Arbitrary;
49
50 for (const auto &Kind : dxbc::PSV::getSemanticKinds())
51 if (SemanticName.equals_insensitive(RHS: Kind.name()))
52 return Kind.value();
53
54 return dxbc::PSV::SemanticKind::Invalid;
55}
56
57Expected<SemanticSignatureElement>
58SemanticSignatureElement::fromMetadata(const MDNode *Node) {
59 // Operand positions within a signature element metadata node.
60 enum class OpIdx : unsigned {
61 SigId,
62 SemanticName,
63 CompType,
64 SemanticKind,
65 SemanticIndices,
66 InterpMode,
67 Rows,
68 Cols,
69 StartRow,
70 StartCol,
71 UsageMask,
72 DynIndexMask,
73 GSStream,
74 LastEntry = GSStream,
75 };
76 const unsigned NumElementOperands = to_underlying(E: OpIdx::LastEntry) + 1;
77
78 if (!Node)
79 return makeError(Msg: "signature element node is null");
80 if (Node->getNumOperands() != NumElementOperands)
81 return makeError(Msg: "signature element node has wrong number of operands");
82
83 SemanticSignatureElement Elem;
84
85 Expected<uint64_t> SigId = extractInt(Node, OpId: to_underlying(E: OpIdx::SigId));
86 if (!SigId)
87 return SigId.takeError();
88 Elem.SigId = *SigId;
89
90 auto *Name =
91 dyn_cast<MDString>(Val: Node->getOperand(I: to_underlying(E: OpIdx::SemanticName)));
92 if (!Name)
93 return makeError(Msg: "expected semantic name string");
94 Elem.SemanticName = Name->getString();
95
96 Expected<uint64_t> CompType =
97 extractInt(Node, OpId: to_underlying(E: OpIdx::CompType));
98 if (!CompType)
99 return CompType.takeError();
100 if (*CompType > MaxCompType)
101 return makeError(Msg: "invalid component type");
102 Elem.CompType = static_cast<dxil::ElementType>(*CompType);
103
104 Expected<uint64_t> SemanticKind =
105 extractInt(Node, OpId: to_underlying(E: OpIdx::SemanticKind));
106 if (!SemanticKind)
107 return SemanticKind.takeError();
108 if (*SemanticKind > MaxSemanticKind)
109 return makeError(Msg: "invalid semantic kind");
110 Elem.SemanticKind = static_cast<dxbc::PSV::SemanticKind>(*SemanticKind);
111
112 auto *Indices =
113 dyn_cast<MDNode>(Val: Node->getOperand(I: to_underlying(E: OpIdx::SemanticIndices)));
114 if (!Indices)
115 return makeError(Msg: "expected semantic indices node");
116 for (unsigned I = 0, E = Indices->getNumOperands(); I != E; ++I) {
117 Expected<uint64_t> Index = extractInt(Node: Indices, OpId: I);
118 if (!Index)
119 return Index.takeError();
120 Elem.SemanticIndices.push_back(Elt: *Index);
121 }
122
123 Expected<uint64_t> InterpMode =
124 extractInt(Node, OpId: to_underlying(E: OpIdx::InterpMode));
125 if (!InterpMode)
126 return InterpMode.takeError();
127 if (*InterpMode > MaxInterpMode)
128 return makeError(Msg: "invalid interpolation mode");
129 Elem.InterpMode = static_cast<dxbc::PSV::InterpolationMode>(*InterpMode);
130
131 Expected<uint64_t> Rows = extractInt(Node, OpId: to_underlying(E: OpIdx::Rows));
132 if (!Rows)
133 return Rows.takeError();
134 Elem.Rows = *Rows;
135
136 Expected<uint64_t> Cols = extractInt(Node, OpId: to_underlying(E: OpIdx::Cols));
137 if (!Cols)
138 return Cols.takeError();
139 if (*Cols < 1 || *Cols > 4)
140 return makeError(Msg: "number of components per row must be within 1-4");
141 Elem.Cols = *Cols;
142
143 Expected<uint64_t> StartRow =
144 extractInt(Node, OpId: to_underlying(E: OpIdx::StartRow));
145 if (!StartRow)
146 return StartRow.takeError();
147 Elem.StartRow = *StartRow;
148
149 Expected<uint64_t> StartCol =
150 extractInt(Node, OpId: to_underlying(E: OpIdx::StartCol));
151 if (!StartCol)
152 return StartCol.takeError();
153 if (*StartCol > 3 && *StartCol != UnallocatedCol)
154 return makeError(Msg: "start column must be within 0-3 or unallocated");
155 Elem.StartCol = *StartCol;
156
157 // The row/col sentinels are always set together
158 if ((Elem.StartRow == UnallocatedRow) != (Elem.StartCol == UnallocatedCol))
159 return makeError(Msg: "start row and column sentinels must be set together");
160
161 Expected<uint64_t> UsageMask =
162 extractInt(Node, OpId: to_underlying(E: OpIdx::UsageMask));
163 if (!UsageMask)
164 return UsageMask.takeError();
165 if (*UsageMask > 0xF)
166 return makeError(Msg: "usage mask must be a 4-bit value");
167 Elem.UsageMask = *UsageMask;
168
169 Expected<uint64_t> DynIndexMask =
170 extractInt(Node, OpId: to_underlying(E: OpIdx::DynIndexMask));
171 if (!DynIndexMask)
172 return DynIndexMask.takeError();
173 if (*DynIndexMask > 0xF)
174 return makeError(Msg: "dynamic index mask must be a 4-bit value");
175 Elem.DynIndexMask = *DynIndexMask;
176
177 Expected<uint64_t> GSStream =
178 extractInt(Node, OpId: to_underlying(E: OpIdx::GSStream));
179 if (!GSStream)
180 return GSStream.takeError();
181 if (*GSStream > 3)
182 return makeError(Msg: "geometry shader stream index must be within 0-3");
183 Elem.GSStream = *GSStream;
184
185 if (Elem.SemanticIndices.size() != Elem.Rows)
186 return makeError(
187 Msg: "number of semantic indices must equal the number of rows");
188
189 return Elem;
190}
191
192MDNode *SemanticSignatureElement::toMetadata(LLVMContext &Ctx) const {
193 Type *I32Ty = Type::getInt32Ty(C&: Ctx);
194 Type *I8Ty = Type::getInt8Ty(C&: Ctx);
195 auto GetI32 = [&](uint32_t Val) -> Metadata * {
196 return ConstantAsMetadata::get(C: ConstantInt::get(Ty: I32Ty, V: Val));
197 };
198 auto GetI8 = [&](uint8_t Val) -> Metadata * {
199 return ConstantAsMetadata::get(C: ConstantInt::get(Ty: I8Ty, V: Val));
200 };
201
202 SmallVector<Metadata *> IndexOps;
203 for (uint32_t Index : SemanticIndices)
204 IndexOps.push_back(Elt: GetI32(Index));
205
206 return MDNode::get(Context&: Ctx,
207 MDs: {GetI32(SigId), MDString::get(Context&: Ctx, Str: SemanticName),
208 GetI32(static_cast<uint32_t>(CompType)),
209 GetI32(static_cast<uint32_t>(SemanticKind)),
210 MDNode::get(Context&: Ctx, MDs: IndexOps),
211 GetI32(static_cast<uint32_t>(InterpMode)), GetI32(Rows),
212 GetI8(Cols), GetI32(StartRow), GetI8(StartCol),
213 GetI8(UsageMask), GetI8(DynIndexMask), GetI32(GSStream)});
214}
215