LLVM 24.0.0git
SemanticSignatures.cpp
Go to the documentation of this file.
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
15#include "llvm/ADT/Enum.h"
17#include "llvm/ADT/bit.h"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/Metadata.h"
20#include "llvm/IR/Type.h"
22#include <algorithm>
23#include <cassert>
24
25using namespace llvm;
26using namespace llvm::hlsl;
28
29namespace {
30
31// Inclusive upper bounds of the operand enums
32constexpr uint32_t MaxCompType =
34constexpr uint32_t MaxSemanticKind =
35 static_cast<uint32_t>(dxbc::PSV::SemanticKind::Invalid);
36constexpr uint32_t MaxInterpMode =
37 static_cast<uint32_t>(dxbc::PSV::InterpolationMode::Invalid);
38
39Error makeError(const Twine &Msg) {
41}
42
43Expected<uint64_t> extractInt(const MDNode *Node, unsigned OpId) {
44 auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(Node->getOperand(OpId));
45 if (!CI)
46 return makeError("expected integer operand " + Twine(OpId));
47 return CI->getZExtValue();
48}
49} // namespace
50
57
60 if (Modifiers == InterpolationModifier::None)
61 return InterpolationMode::Undefined;
62 if (any(Modifiers & InterpolationModifier::NoInterpolation))
64 ? InterpolationMode::Constant
65 : InterpolationMode::Invalid;
66
68 switch (getInterpolationSamplingLocation(Modifiers)) {
70 return NoPerspective ? InterpolationMode::LinearNoperspectiveSample
71 : InterpolationMode::LinearSample;
73 return NoPerspective ? InterpolationMode::LinearNoperspectiveCentroid
74 : InterpolationMode::LinearCentroid;
77 return NoPerspective ? InterpolationMode::LinearNoperspective
78 : InterpolationMode::Linear;
79 default:
80 llvm_unreachable("invalid interpolation sampling location");
81 }
82}
83
87 if (!((Stage == Triple::Pixel && IO == IOType::In) ||
88 (Stage == Triple::Vertex && IO == IOType::Out)))
89 return InterpolationMode::Undefined;
90
91 if (Mode == InterpolationMode::Undefined) {
92 switch (CompType) {
99 Mode = InterpolationMode::Linear;
100 break;
101 default:
102 Mode = InterpolationMode::Constant;
103 break;
104 }
105 }
106
107 if (Kind == dxbc::PSV::SemanticKind::Position) {
108 switch (Mode) {
109 case InterpolationMode::Linear:
110 return InterpolationMode::LinearNoperspective;
111 case InterpolationMode::LinearCentroid:
112 return InterpolationMode::LinearNoperspectiveCentroid;
113 case InterpolationMode::LinearSample:
114 return InterpolationMode::LinearNoperspectiveSample;
115 default:
116 break;
117 }
118 }
119 return Mode;
120}
121
123 if (!SemanticName.consume_front_insensitive("SV_"))
124 return dxbc::PSV::SemanticKind::Arbitrary;
125
126 for (const auto &Kind : dxbc::PSV::getSemanticKinds())
127 if (SemanticName.equals_insensitive(Kind.name()))
128 return Kind.value();
129
130 return dxbc::PSV::SemanticKind::Invalid;
131}
132
135 switch (SemanticKind) {
136 case dxbc::PSV::SemanticKind::Arbitrary: {
137 static constexpr IOType OutOrPatchConstant =
139 static constexpr SemanticStageInfo Stages[] = {
145 {Triple::Mesh, OutOrPatchConstant, SemanticInterpretation::Arbitrary},
146 };
147 return Stages;
148 }
149 case dxbc::PSV::SemanticKind::DispatchThreadID:
150 case dxbc::PSV::SemanticKind::GroupID:
151 case dxbc::PSV::SemanticKind::GroupIndex:
152 case dxbc::PSV::SemanticKind::GroupThreadID: {
153 static constexpr SemanticStageInfo Stages[] = {
158 };
159 return Stages;
160 }
161 case dxbc::PSV::SemanticKind::ViewID: {
162 static constexpr IOType InOrPatchConstant =
164 static constexpr SemanticStageInfo Stages[] = {
167 {Triple::Domain, InOrPatchConstant,
172 };
173 return Stages;
174 }
175 case dxbc::PSV::SemanticKind::StartVertexLocation:
176 case dxbc::PSV::SemanticKind::StartInstanceLocation: {
177 static constexpr SemanticStageInfo Stages[] = {
179 return Stages;
180 }
181 case dxbc::PSV::SemanticKind::SampleIndex: {
182 static constexpr SemanticStageInfo Stages[] = {
184 return Stages;
185 }
186 case dxbc::PSV::SemanticKind::Barycentrics: {
187 static constexpr SemanticStageInfo Stages[] = {
189 return Stages;
190 }
191 case dxbc::PSV::SemanticKind::Target: {
192 static constexpr SemanticStageInfo Stages[] = {
194 return Stages;
195 }
196 case dxbc::PSV::SemanticKind::VertexID:
197 case dxbc::PSV::SemanticKind::InstanceID: {
198 static constexpr SemanticStageInfo Stages[] = {
200 return Stages;
201 }
202 case dxbc::PSV::SemanticKind::PrimitiveID: {
203 static constexpr SemanticStageInfo Stages[] = {
205 return Stages;
206 }
207 case dxbc::PSV::SemanticKind::IsFrontFace: {
208 static constexpr SemanticStageInfo Stages[] = {
211 return Stages;
212 }
213 case dxbc::PSV::SemanticKind::ShadingRate: {
214 static constexpr SemanticStageInfo Stages[] = {
222 return Stages;
223 }
224 case dxbc::PSV::SemanticKind::Position: {
225 static constexpr SemanticStageInfo Stages[] = {
237 };
238 return Stages;
239 }
240 case dxbc::PSV::SemanticKind::ClipDistance:
241 case dxbc::PSV::SemanticKind::CullDistance: {
242 static constexpr SemanticStageInfo Stages[] = {
254 };
255 return Stages;
256 }
257 case dxbc::PSV::SemanticKind::TessFactor:
258 case dxbc::PSV::SemanticKind::InsideTessFactor: {
259 static constexpr SemanticStageInfo Stages[] = {
264 };
265 return Stages;
266 }
267 default:
268 return {};
269 }
270}
271
274 Triple::EnvironmentType ShaderStage, IOType IOTy) {
275 assert(llvm::has_single_bit(static_cast<unsigned>(IOTy)) &&
276 "a single IOType is expected, not a mask of IOTypes");
277 for (const SemanticStageInfo &Info : getAvailableStages(SemanticKind))
278 if (Info.Stage == ShaderStage && any(Info.AllowedIOTypesMask & IOTy))
279 return Info.Interpretation;
281}
282
285 // Operand positions within a signature element metadata node.
286 enum class OpIdx : unsigned {
287 SigId,
289 CompType,
293 Rows,
294 Cols,
295 StartRow,
296 StartCol,
297 UsageMask,
299 GSStream,
300 LastEntry = GSStream,
301 };
302 const unsigned NumElementOperands = to_underlying(OpIdx::LastEntry) + 1;
303
304 if (!Node)
305 return makeError("signature element node is null");
306 if (Node->getNumOperands() != NumElementOperands)
307 return makeError("signature element node has wrong number of operands");
308
310
311 Expected<uint64_t> SigId = extractInt(Node, to_underlying(OpIdx::SigId));
312 if (!SigId)
313 return SigId.takeError();
314 Elem.SigId = *SigId;
315
316 auto *Name =
317 dyn_cast<MDString>(Node->getOperand(to_underlying(OpIdx::SemanticName)));
318 if (!Name)
319 return makeError("expected semantic name string");
320 Elem.SemanticName = Name->getString();
321
323 extractInt(Node, to_underlying(OpIdx::CompType));
324 if (!CompType)
325 return CompType.takeError();
326 if (*CompType > MaxCompType)
327 return makeError("invalid component type");
328 Elem.CompType = static_cast<dxil::ElementType>(*CompType);
329
331 extractInt(Node, to_underlying(OpIdx::SemanticKind));
332 if (!SemanticKind)
333 return SemanticKind.takeError();
334 if (*SemanticKind > MaxSemanticKind)
335 return makeError("invalid semantic kind");
336 Elem.SemanticKind = static_cast<dxbc::PSV::SemanticKind>(*SemanticKind);
337
338 auto *Indices =
339 dyn_cast<MDNode>(Node->getOperand(to_underlying(OpIdx::SemanticIndices)));
340 if (!Indices)
341 return makeError("expected semantic indices node");
342 for (unsigned I = 0, E = Indices->getNumOperands(); I != E; ++I) {
343 Expected<uint64_t> Index = extractInt(Indices, I);
344 if (!Index)
345 return Index.takeError();
346 Elem.SemanticIndices.push_back(*Index);
347 }
348
350 extractInt(Node, to_underlying(OpIdx::InterpMode));
351 if (!InterpMode)
352 return InterpMode.takeError();
353 if (*InterpMode > MaxInterpMode)
354 return makeError("invalid interpolation mode");
355 Elem.InterpMode = static_cast<dxbc::PSV::InterpolationMode>(*InterpMode);
356
357 Expected<uint64_t> Rows = extractInt(Node, to_underlying(OpIdx::Rows));
358 if (!Rows)
359 return Rows.takeError();
360 Elem.Rows = *Rows;
361
362 Expected<uint64_t> Cols = extractInt(Node, to_underlying(OpIdx::Cols));
363 if (!Cols)
364 return Cols.takeError();
365 if (*Cols < 1 || *Cols > 4)
366 return makeError("number of components per row must be within 1-4");
367 Elem.Cols = *Cols;
368
370 extractInt(Node, to_underlying(OpIdx::StartRow));
371 if (!StartRow)
372 return StartRow.takeError();
373 Elem.StartRow = *StartRow;
374
376 extractInt(Node, to_underlying(OpIdx::StartCol));
377 if (!StartCol)
378 return StartCol.takeError();
379 if (*StartCol > 3 && *StartCol != UnallocatedCol)
380 return makeError("start column must be within 0-3 or unallocated");
381 Elem.StartCol = *StartCol;
382
383 // The row/col sentinels are always set together
384 if ((Elem.StartRow == UnallocatedRow) != (Elem.StartCol == UnallocatedCol))
385 return makeError("start row and column sentinels must be set together");
386
388 extractInt(Node, to_underlying(OpIdx::UsageMask));
389 if (!UsageMask)
390 return UsageMask.takeError();
391 if (*UsageMask > 0xF)
392 return makeError("usage mask must be a 4-bit value");
393 Elem.UsageMask = *UsageMask;
394
396 extractInt(Node, to_underlying(OpIdx::DynIndexMask));
397 if (!DynIndexMask)
398 return DynIndexMask.takeError();
399 if (*DynIndexMask > 0xF)
400 return makeError("dynamic index mask must be a 4-bit value");
402
404 extractInt(Node, to_underlying(OpIdx::GSStream));
405 if (!GSStream)
406 return GSStream.takeError();
407 if (*GSStream > 3)
408 return makeError("geometry shader stream index must be within 0-3");
409 Elem.GSStream = *GSStream;
410
411 if (Elem.SemanticIndices.size() != Elem.Rows)
412 return makeError(
413 "number of semantic indices must equal the number of rows");
414
415 return Elem;
416}
417
419 Type *I32Ty = Type::getInt32Ty(Ctx);
420 Type *I8Ty = Type::getInt8Ty(Ctx);
421 auto GetI32 = [&](uint32_t Val) -> Metadata * {
422 return ConstantAsMetadata::get(ConstantInt::get(I32Ty, Val));
423 };
424 auto GetI8 = [&](uint8_t Val) -> Metadata * {
425 return ConstantAsMetadata::get(ConstantInt::get(I8Ty, Val));
426 };
427
429 for (uint32_t Index : SemanticIndices)
430 IndexOps.push_back(GetI32(Index));
431
432 return MDNode::get(Ctx,
433 {GetI32(SigId), MDString::get(Ctx, SemanticName),
434 GetI32(static_cast<uint32_t>(CompType)),
435 GetI32(static_cast<uint32_t>(SemanticKind)),
436 MDNode::get(Ctx, IndexOps),
437 GetI32(static_cast<uint32_t>(InterpMode)), GetI32(Rows),
438 GetI8(Cols), GetI32(StartRow), GetI8(StartCol),
439 GetI8(UsageMask), GetI8(DynIndexMask), GetI32(GSStream)});
440}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define I(x, y, z)
Definition MD5.cpp:57
This file contains the declarations for metadata subclasses.
const char * Msg
This file contains library features backported from future STL versions.
This file implements the C++20 <bit> header.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:548
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
Metadata node.
Definition Metadata.h:1081
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1579
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:597
Root of the metadata hierarchy.
Definition Metadata.h:64
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool equals_insensitive(StringRef RHS) const
Check for string equality, ignoring case.
Definition StringRef.h:170
bool consume_front_insensitive(StringRef Prefix)
Returns true if this StringRef has the given prefix, ignoring case, and removes that prefix.
Definition StringRef.h:681
@ Amplification
Definition Triple.h:412
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI EnumStrings< SemanticKind, 1 > getSemanticKinds()
ElementType
The element type of an SRV or UAV resource.
Definition DXILABI.h:68
static constexpr uint32_t UnallocatedRow
LLVM_ABI SemanticInterpretation getInterpretationKind(dxbc::PSV::SemanticKind SemanticKind, Triple::EnvironmentType ShaderStage, IOType IOTy)
LLVM_ABI ArrayRef< SemanticStageInfo > getAvailableStages(dxbc::PSV::SemanticKind SemanticKind)
LLVM_ABI dxbc::PSV::InterpolationMode getInterpolationMode(InterpolationModifier Modifiers)
LLVM_ABI dxbc::PSV::InterpolationMode normalizeInterpolationMode(dxbc::PSV::InterpolationMode Mode, dxil::ElementType CompType, dxbc::PSV::SemanticKind Kind, Triple::EnvironmentType Stage, IOType IO)
LLVM_ABI InterpolationModifier getInterpolationSamplingLocation(InterpolationModifier Modifiers)
LLVM_ABI dxbc::PSV::SemanticKind getSemanticKind(StringRef SemanticName)
static constexpr uint8_t UnallocatedCol
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
Definition Metadata.h:720
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
constexpr bool has_single_bit(T Value) noexcept
Definition bit.h:149
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
static LLVM_ABI Expected< SemanticSignatureElement > fromMetadata(const MDNode *Node)
dxbc::PSV::InterpolationMode InterpMode
LLVM_ABI MDNode * toMetadata(LLVMContext &Ctx) const