1//===- DXILSignatureAnalysis.cpp - Semantic signatures --------------------===//
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#include "DXILSignatureAnalysis.h"
10#include "DirectX.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/Analysis/DXILMetadataAnalysis.h"
14#include "llvm/Frontend/HLSL/SemanticSignaturePacking.h"
15#include "llvm/IR/Constants.h"
16#include "llvm/IR/InstIterator.h"
17#include "llvm/IR/IntrinsicInst.h"
18#include "llvm/IR/IntrinsicsDirectX.h"
19#include "llvm/IR/Module.h"
20#include "llvm/InitializePasses.h"
21#include "llvm/MC/DXContainerPSVInfo.h"
22#include "llvm/Support/Error.h"
23#include "llvm/Support/raw_ostream.h"
24#include <array>
25#include <set>
26
27using namespace llvm;
28using namespace llvm::dxil;
29using namespace llvm::hlsl;
30
31static Error signatureError(const Twine &Message) {
32 return createStringError(EC: inconvertibleErrorCode(), S: Message);
33}
34
35static bool isSignatureAccess(const IntrinsicInst &I) {
36 return I.getIntrinsicID() == Intrinsic::dx_load_input ||
37 I.getIntrinsicID() == Intrinsic::dx_store_output;
38}
39
40// Validate widths before fromMetadata extracts integer values or narrows them.
41static Error checkElementNode(const MDNode *Node) {
42 if (!Node || Node->getNumOperands() != 13)
43 return signatureError(Message: "expected a 13-operand signature element");
44 for (unsigned I = 0; I != 13; ++I) {
45 if (I == 1 || I == 4)
46 continue;
47 auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD: Node->getOperand(I));
48 unsigned Width = (I == 7 || (I >= 9 && I <= 11)) ? 8 : 32;
49 if (!CI || CI->getBitWidth() != Width)
50 return signatureError(Message: "expected i" + Twine(Width) + " at operand " +
51 Twine(I));
52 }
53 if (!isa_and_nonnull<MDString>(Val: Node->getOperand(I: 1)))
54 return signatureError(Message: "expected semantic name string");
55 auto *Indices = dyn_cast_or_null<MDNode>(Val: Node->getOperand(I: 4));
56 if (!Indices)
57 return signatureError(Message: "expected semantic indices node");
58 for (const MDOperand &Index : Indices->operands()) {
59 auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD: Index);
60 if (!CI || CI->getBitWidth() != 32)
61 return signatureError(Message: "expected i32 semantic index");
62 }
63 return Error::success();
64}
65
66static bool isIntegerComponent(ElementType Type) {
67 return Type == ElementType::I1 || Type == ElementType::I16 ||
68 Type == ElementType::U16 || Type == ElementType::I32 ||
69 Type == ElementType::U32;
70}
71
72static Error validateSemanticType(const SemanticSignatureElement &E) {
73 switch (E.SemanticKind) {
74 case dxbc::PSV::SemanticKind::Position:
75 if (E.Rows != 1 || E.Cols != 4 ||
76 (E.CompType != ElementType::F16 && E.CompType != ElementType::F32))
77 return signatureError(
78 Message: "SV_Position requires one row of four floating-point components");
79 break;
80 case dxbc::PSV::SemanticKind::VertexID:
81 if (E.Rows != 1 || E.Cols != 1 ||
82 (E.CompType != ElementType::I16 && E.CompType != ElementType::U16 &&
83 E.CompType != ElementType::I32 && E.CompType != ElementType::U32))
84 return signatureError(
85 Message: "SV_VertexID requires a scalar 16- or 32-bit integer");
86 break;
87 case dxbc::PSV::SemanticKind::InstanceID:
88 if (E.Rows != 1 || E.Cols != 1 ||
89 (E.CompType != ElementType::U16 && E.CompType != ElementType::U32))
90 return signatureError(
91 Message: "SV_InstanceID requires a scalar 16- or 32-bit unsigned integer");
92 break;
93 default:
94 break;
95 }
96 return Error::success();
97}
98
99static Error validateSemanticIndex(const SemanticSignatureElement &E) {
100 switch (E.SemanticKind) {
101 case dxbc::PSV::SemanticKind::Target:
102 if (E.Rows != 1 || E.SemanticIndices.front() >= 8)
103 return signatureError(
104 Message: "pixel targets require one row and an index within 0-7");
105 break;
106 case dxbc::PSV::SemanticKind::VertexID:
107 if (E.SemanticIndices.front() != 0)
108 return signatureError(Message: "SV_VertexID requires semantic index 0");
109 break;
110 default:
111 break;
112 }
113 return Error::success();
114}
115
116static Error parseSignature(Metadata *MD,
117 SmallVectorImpl<SemanticSignatureElement> &Out,
118 ModuleSignatureInfo &Info,
119 Triple::EnvironmentType Stage, IOType IO,
120 bool Native16, unsigned &Extent) {
121 if (!MD)
122 return Error::success();
123 auto *List = dyn_cast<MDNode>(Val: MD);
124 if (!List)
125 return signatureError(Message: "expected a signature element list or null");
126 if (List->getNumOperands() > 128)
127 return signatureError(Message: "too many signature elements");
128
129 std::set<std::pair<std::string, uint32_t>> Semantics;
130 std::array<uint8_t, MaxSignatureRows> AllocatedColumns = {};
131 std::array<dxbc::PSV::InterpolationMode, MaxSignatureRows> RowModes = {};
132 std::array<bool, MaxSignatureRows> RowNative16 = {};
133 for (const MDOperand &Op : List->operands()) {
134 auto *Node = dyn_cast_or_null<MDNode>(Val: Op);
135 if (Error Err = checkElementNode(Node))
136 return Err;
137 auto Parsed = SemanticSignatureElement::fromMetadata(Node);
138 if (!Parsed)
139 return Parsed.takeError();
140 SemanticSignatureElement E = std::move(*Parsed);
141 if (E.SigId != Out.size())
142 return signatureError(Message: "signature IDs must be dense and in list order");
143 if (Stage != Triple::Vertex && Stage != Triple::Pixel)
144 return signatureError(Message: "nonempty signatures are currently supported only "
145 "for vertex and pixel entries");
146 if (!E.Rows || E.Rows > MaxSignatureRows)
147 return signatureError(Message: "signature row count must be within 1-32");
148 if (E.SemanticName.empty() || E.SemanticName.contains(C: '\0'))
149 return signatureError(Message: "invalid semantic name");
150 if (E.CompType != ElementType::F16 && E.CompType != ElementType::F32 &&
151 !isIntegerComponent(Type: E.CompType))
152 return signatureError(Message: "unsupported signature component type");
153 if (E.GSStream != 0)
154 return signatureError(Message: "nonzero stream requires a geometry output");
155 auto NamedKind = getSemanticKind(SemanticName: E.SemanticName);
156 auto Interpretation = getInterpretationKind(SemanticKind: NamedKind, ShaderStage: Stage, IOTy: IO);
157 if (Interpretation == SemanticInterpretation::Invalid)
158 return signatureError(Message: "invalid or unsupported semantic for this stage "
159 "and signature category");
160 if (Interpretation == SemanticInterpretation::NotAllocated)
161 return signatureError(Message: "semantic accessed by a dedicated intrinsic must "
162 "not appear in an input/output signature");
163 auto ExpectedKind = Interpretation == SemanticInterpretation::Arbitrary
164 ? dxbc::PSV::SemanticKind::Arbitrary
165 : NamedKind;
166 if (E.SemanticKind != ExpectedKind)
167 return signatureError(Message: "semantic name and kind disagree at this signature "
168 "point");
169 if (!E.isAllocated())
170 return signatureError(Message: "signature element " + Twine(E.SigId) + " ('" +
171 E.SemanticName + "') has no allocated location");
172 if (E.StartRow >= MaxSignatureRows ||
173 E.Rows > MaxSignatureRows - E.StartRow || E.StartCol + E.Cols > 4)
174 return signatureError(
175 Message: "allocated signature element exceeds register bounds");
176 if (E.InterpMode == dxbc::PSV::InterpolationMode::Invalid)
177 return signatureError(Message: "invalid interpolation mode");
178
179 for (uint32_t Index : E.SemanticIndices)
180 if (!Semantics.emplace(args: E.SemanticName.upper(), args&: Index).second)
181 return signatureError(Message: "duplicate semantic name and index");
182 if (Error Err = validateSemanticType(E))
183 return Err;
184 if (Error Err = validateSemanticIndex(E))
185 return Err;
186
187 if (Stage == Triple::Vertex && IO == IOType::In &&
188 (E.StartRow != Extent || E.StartCol != 0))
189 return signatureError(Message: "vertex inputs require stacked locations in "
190 "signature order (element " +
191 Twine(E.SigId) + ")");
192 if (Interpretation == SemanticInterpretation::Target &&
193 (E.StartRow != E.SemanticIndices.front() || E.StartCol != 0))
194 return signatureError(Message: "pixel target location must match its semantic "
195 "index at column 0");
196 if (Stage == Triple::Pixel && IO == IOType::In &&
197 isIntegerComponent(Type: E.CompType) &&
198 E.InterpMode != dxbc::PSV::InterpolationMode::Constant)
199 return signatureError(
200 Message: "integer pixel inputs require constant interpolation");
201
202 // Co-packed elements must obey row constraints, even when their component
203 // masks do not overlap. Min-precision types occupy 32-bit components.
204 bool IsNative16 = Native16 && (E.CompType == ElementType::F16 ||
205 E.CompType == ElementType::I16 ||
206 E.CompType == ElementType::U16);
207 uint8_t Mask = E.getDeclaredMask();
208 for (unsigned Row = E.StartRow; Row != E.StartRow + E.Rows; ++Row) {
209 if (AllocatedColumns[Row] & Mask)
210 return signatureError(Message: "signature elements overlap at row " +
211 Twine(Row) + " (element " + Twine(E.SigId) + ")");
212 if (AllocatedColumns[Row] && RowModes[Row] != E.InterpMode)
213 return signatureError(Message: "signature elements have different interpolation "
214 "modes at row " +
215 Twine(Row) + " (element " + Twine(E.SigId) + ")");
216 if (AllocatedColumns[Row] && RowNative16[Row] != IsNative16)
217 return signatureError(Message: "signature elements have different component "
218 "widths at row " +
219 Twine(Row) + " (element " + Twine(E.SigId) + ")");
220 AllocatedColumns[Row] |= Mask;
221 RowModes[Row] = E.InterpMode;
222 RowNative16[Row] = IsNative16;
223 }
224 Extent = std::max(a: Extent, b: E.StartRow + E.Rows);
225 E.SemanticName = Info.Names.insert(key: E.SemanticName).first->getKey();
226
227 // Access masks will be recomputed so reset to 0 here.
228 E.UsageMask = 0;
229 E.DynIndexMask = 0;
230 Out.push_back(Elt: std::move(E));
231 }
232 return Error::success();
233}
234
235static Error analyzeAccess(const IntrinsicInst &I, EntrySignature &Sig) {
236 bool Input = I.getIntrinsicID() == Intrinsic::dx_load_input;
237 auto &Elements = Input ? Sig.Inputs : Sig.Outputs;
238 auto *ID = dyn_cast<ConstantInt>(Val: I.getArgOperand(i: 0));
239 auto *Col = dyn_cast<ConstantInt>(Val: I.getArgOperand(i: 2));
240 StringRef Category = Input ? "input" : "output";
241 if (!ID)
242 return signatureError(Message: Category +
243 " signature: signature access requires a constant "
244 "element ID");
245 if (ID->getZExtValue() >= Elements.size())
246 return signatureError(Message: Category +
247 " signature: signature access has an invalid element "
248 "ID " +
249 Twine(ID->getZExtValue()));
250 auto &E = Elements[ID->getZExtValue()];
251 auto AccessError = [&](const Twine &Message) {
252 return signatureError(Message: Category + " signature element " + Twine(E.SigId) +
253 " ('" + E.SemanticName + "'): " + Message);
254 };
255 Type *Ty = Input ? I.getType() : I.getArgOperand(i: 3)->getType();
256 unsigned Width = 1;
257 if (auto *VT = dyn_cast<FixedVectorType>(Val: Ty)) {
258 Width = VT->getNumElements();
259 Ty = VT->getElementType();
260 }
261 if (!Col || Col->getZExtValue() >= E.Cols ||
262 Width > E.Cols - Col->getZExtValue())
263 return AccessError("signature access has an invalid component index");
264 auto *Row = dyn_cast<ConstantInt>(Val: I.getArgOperand(i: 1));
265 if (Row && Row->getZExtValue() >= E.Rows)
266 return AccessError("signature access has an invalid row index");
267 if (!Row && E.Rows == 1)
268 return AccessError(
269 "dynamic indexing requires a multi-row signature element");
270 bool CorrectType = false;
271 switch (E.CompType) {
272 case ElementType::F16:
273 CorrectType = Ty->isHalfTy();
274 break;
275 case ElementType::F32:
276 CorrectType = Ty->isFloatTy();
277 break;
278 case ElementType::I16:
279 case ElementType::U16:
280 CorrectType = Ty->isIntegerTy(BitWidth: 16);
281 break;
282 case ElementType::I1:
283 // Boolean signature elements use the i32 load/store overload.
284 CorrectType = Ty->isIntegerTy(BitWidth: 32);
285 break;
286 case ElementType::I32:
287 case ElementType::U32:
288 CorrectType = Ty->isIntegerTy(BitWidth: 32);
289 break;
290 default:
291 llvm_unreachable("invalid signature component type");
292 }
293 if (!CorrectType)
294 return AccessError("signature access type disagrees with its element");
295 uint8_t Mask = ((1U << Width) - 1) << Col->getZExtValue();
296 E.UsageMask |= Mask << E.StartCol;
297 if (!Row)
298 E.DynIndexMask |= Mask;
299 return Error::success();
300}
301
302static void buildDependencyMap(EntrySignature &Sig) {
303 // Each output vector needs four component bits, so one 32-bit word holds
304 // eight vectors. Adding seven rounds up to include a partially filled word.
305 unsigned Words = (Sig.OutputVectors + 7) / 8;
306 Sig.InputOutputMap.assign(NumElts: Sig.InputVectors * 4 * Words, Elt: 0);
307 // Conservatively connect every accessed input component to every written
308 // output component. This includes control, memory, call, and dynamic-index
309 // dependencies without incorrectly claiming that unknown dependencies are
310 // absent. Unused components and padding remain zero. Both DXIL and PSV use
311 // this same map; a more precise dependency analysis can refine it later.
312 for (const auto &Input : Sig.Inputs)
313 for (unsigned IR = 0; IR != Input.Rows; ++IR)
314 for (unsigned IC = 0; IC != 4; ++IC) {
315 if (!(Input.UsageMask & (1U << IC)))
316 continue;
317 unsigned Base = ((Input.StartRow + IR) * 4 + IC) * Words;
318 for (const auto &Output : Sig.Outputs)
319 for (unsigned OR = 0; OR != Output.Rows; ++OR)
320 for (unsigned OC = 0; OC != 4; ++OC) {
321 if (!(Output.UsageMask & (1U << OC)))
322 continue;
323 unsigned Bit = (Output.StartRow + OR) * 4 + OC;
324 Sig.InputOutputMap[Base + Bit / 32] |= 1U << (Bit % 32);
325 }
326 }
327}
328
329static Expected<ModuleSignatureInfo>
330analyzeModule(Module &M, const ModuleMetadataInfo &MMI) {
331 ModuleSignatureInfo Info;
332 if (NamedMDNode *Table = M.getNamedMetadata(Name: "dx.semantic.signatures")) {
333 for (const MDNode *Record : Table->operands()) {
334 if (Record->getNumOperands() != 3)
335 return signatureError(
336 Message: "expected an entry/input/output signature triple");
337 auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Val: Record->getOperand(I: 0));
338 auto *F = VAM ? dyn_cast<Function>(Val: VAM->getValue()) : nullptr;
339 if (!F || F->getParent() != &M || F->isDeclaration())
340 return signatureError(
341 Message: "signature entry must be a defined function in the module");
342 auto EP =
343 llvm::find_if(Range: MMI.EntryPropertyVec,
344 P: [F](const EntryProperties &E) { return E.Entry == F; });
345 if (EP == MMI.EntryPropertyVec.end())
346 return signatureError(Message: "signature function is not a shader entry");
347 if (Info.Entries.contains(Val: F))
348 return signatureError(Message: "duplicate signature record for entry '" +
349 F->getName() + "'");
350 EntrySignature Sig;
351 Sig.Stage = EP->ShaderStage;
352 if (auto *Native = mdconst::dyn_extract_or_null<ConstantInt>(
353 MD: M.getModuleFlag(Key: "dx.nativelowprec")))
354 Sig.UseNative16Bit = !Native->isZero();
355 if (Sig.UseNative16Bit && MMI.ShaderModelVersion < VersionTuple(6, 2))
356 return signatureError(
357 Message: "native 16-bit signatures require shader model 6.2");
358 auto AddContext = [&](Error Err, StringRef Category) -> Error {
359 return signatureError(Message: "entry '" + F->getName() + "' " + Category +
360 " signature: " + toString(E: std::move(Err)));
361 };
362 if (Error Err =
363 parseSignature(MD: Record->getOperand(I: 1), Out&: Sig.Inputs, Info, Stage: Sig.Stage,
364 IO: IOType::In, Native16: Sig.UseNative16Bit, Extent&: Sig.InputVectors))
365 return AddContext(std::move(Err), "input");
366 if (Error Err = parseSignature(MD: Record->getOperand(I: 2), Out&: Sig.Outputs, Info,
367 Stage: Sig.Stage, IO: IOType::Out, Native16: Sig.UseNative16Bit,
368 Extent&: Sig.OutputVectors))
369 return AddContext(std::move(Err), "output");
370 for (const Instruction &I : instructions(F))
371 if (auto *II = dyn_cast<IntrinsicInst>(Val: &I);
372 II && isSignatureAccess(I: *II))
373 if (Error Err = analyzeAccess(I: *II, Sig))
374 return signatureError(Message: "entry '" + F->getName() +
375 "': " + toString(E: std::move(Err)));
376 buildDependencyMap(Sig);
377 Info.Entries.try_emplace(Key: F, Args: std::move(Sig));
378 }
379 }
380 // Signature IDs are local to an entry. Do not guess which entry a helper's
381 // accesses belong to, even if that helper happens to have a single caller.
382 for (const Function &F : M)
383 if (!Info.Entries.contains(Val: &F))
384 for (const Instruction &I : instructions(F))
385 if (auto *II = dyn_cast<IntrinsicInst>(Val: &I);
386 II && isSignatureAccess(I: *II))
387 return signatureError(Message: "signature access in function '" + F.getName() +
388 "' has no entry signature metadata");
389 return std::move(Info);
390}
391
392static ModuleSignatureInfo collectSignatures(Module &M,
393 const ModuleMetadataInfo &MMI) {
394 auto Result = analyzeModule(M, MMI);
395 if (!Result) {
396 M.getContext().emitError(ErrorStr: "Invalid semantic signature: " +
397 toString(E: Result.takeError()));
398 return ModuleSignatureInfo();
399 }
400 return std::move(*Result);
401}
402
403static MDNode *emitSignature(LLVMContext &Ctx,
404 ArrayRef<SemanticSignatureElement> Elements,
405 VersionTuple ValidatorVersion) {
406 if (Elements.empty())
407 return nullptr;
408 auto I32 = [&](uint32_t V) {
409 return ConstantAsMetadata::get(C: ConstantInt::get(Ty: Type::getInt32Ty(C&: Ctx), V));
410 };
411 auto I8 = [&](uint8_t V) {
412 return ConstantAsMetadata::get(C: ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V));
413 };
414 SmallVector<Metadata *> Nodes;
415 for (const auto &E : Elements) {
416 SmallVector<Metadata *> Indices, Props;
417 for (uint32_t Index : E.SemanticIndices)
418 Indices.push_back(Elt: I32(Index));
419 if (E.GSStream)
420 Props.append(IL: {I32(0), I32(E.GSStream)});
421 if (E.DynIndexMask)
422 Props.append(IL: {I32(2), I32(E.DynIndexMask)});
423 if (E.UsageMask &&
424 (ValidatorVersion.empty() || ValidatorVersion == VersionTuple(0, 0) ||
425 ValidatorVersion >= VersionTuple(1, 5)))
426 Props.append(IL: {I32(3), I32(E.UsageMask >> E.StartCol)});
427 Nodes.push_back(Elt: MDNode::get(
428 Context&: Ctx, MDs: {I32(E.SigId), MDString::get(Context&: Ctx, Str: E.SemanticName),
429 I8(static_cast<uint8_t>(E.CompType)),
430 I8(static_cast<uint8_t>(E.SemanticKind)),
431 MDNode::get(Context&: Ctx, MDs: Indices), I8(static_cast<uint8_t>(E.InterpMode)),
432 I32(E.Rows), I8(E.Cols), I32(E.StartRow), I8(E.StartCol),
433 Props.empty() ? nullptr : MDNode::get(Context&: Ctx, MDs: Props)}));
434 }
435 return MDNode::get(Context&: Ctx, MDs: Nodes);
436}
437
438static dxbc::SigComponentType getComponentType(ElementType Type, bool Legacy) {
439 switch (Type) {
440 case ElementType::I1:
441 return Legacy ? dxbc::SigComponentType::Unknown
442 : dxbc::SigComponentType::UInt32;
443 case ElementType::I16:
444 return dxbc::SigComponentType::SInt16;
445 case ElementType::U16:
446 return dxbc::SigComponentType::UInt16;
447 case ElementType::I32:
448 return dxbc::SigComponentType::SInt32;
449 case ElementType::U32:
450 return dxbc::SigComponentType::UInt32;
451 case ElementType::F16:
452 return dxbc::SigComponentType::Float16;
453 case ElementType::F32:
454 return dxbc::SigComponentType::Float32;
455 default:
456 llvm_unreachable("invalid signature component type");
457 }
458}
459
460static dxbc::D3DSystemValue getSystemValue(dxbc::PSV::SemanticKind Kind) {
461 using KindTy = dxbc::PSV::SemanticKind;
462 switch (Kind) {
463 case KindTy::Arbitrary:
464 return dxbc::D3DSystemValue::Undefined;
465 case KindTy::VertexID:
466 return dxbc::D3DSystemValue::VertexID;
467 case KindTy::InstanceID:
468 return dxbc::D3DSystemValue::InstanceID;
469 case KindTy::Position:
470 return dxbc::D3DSystemValue::Position;
471 case KindTy::IsFrontFace:
472 return dxbc::D3DSystemValue::IsFrontFace;
473 case KindTy::ClipDistance:
474 return dxbc::D3DSystemValue::ClipDistance;
475 case KindTy::CullDistance:
476 return dxbc::D3DSystemValue::CullDistance;
477 case KindTy::Target:
478 return dxbc::D3DSystemValue::Target;
479 default:
480 llvm_unreachable("validated vertex/pixel signature semantic");
481 }
482}
483
484// The DXIL reader normalizes system-value semantic names when loading module
485// metadata. The validator then recreates ISG1/OSG1 from those normalized names
486// and compares the parts byte-for-byte, so the container must use the same
487// spelling even if HLSL (or the source metadata) used a different casing.
488static StringRef getContainerSemanticName(const SemanticSignatureElement &E) {
489 using Kind = dxbc::PSV::SemanticKind;
490 switch (E.SemanticKind) {
491 case Kind::Arbitrary:
492 return E.SemanticName;
493 case Kind::VertexID:
494 return "SV_VertexID";
495 case Kind::InstanceID:
496 return "SV_InstanceID";
497 case Kind::Position:
498 return "SV_Position";
499 case Kind::IsFrontFace:
500 return "SV_IsFrontFace";
501 case Kind::ClipDistance:
502 return "SV_ClipDistance";
503 case Kind::CullDistance:
504 return "SV_CullDistance";
505 case Kind::Target:
506 return "SV_Target";
507 default:
508 llvm_unreachable("validated vertex/pixel signature semantic");
509 }
510}
511
512static void buildSignature(mcdxbc::Signature &Sig,
513 ArrayRef<SemanticSignatureElement> Elements,
514 bool Input, bool Native16, bool Legacy) {
515 for (const auto &E : Elements) {
516 uint8_t Mask = E.getDeclaredMask();
517 uint8_t ExclusiveMask =
518 Input ? E.getAlwaysReadsMask() : E.getNeverWritesMask();
519 if (Legacy)
520 ExclusiveMask = Input ? 0 : static_cast<uint8_t>(~Mask);
521 for (auto [Row, Index] : enumerate(First: E.SemanticIndices))
522 Sig.addParam(Stream: E.GSStream, Name: getContainerSemanticName(E), Index,
523 SystemValue: getSystemValue(Kind: E.SemanticKind),
524 CompType: getComponentType(Type: E.CompType, Legacy), Register: E.StartRow + Row, Mask,
525 ExclusiveMask, MinPrecision: E.getMinPrecision(UseMinPrecision: !Native16));
526 }
527}
528
529static void buildPSVElements(SmallVectorImpl<mcdxbc::PSVSignatureElement> &Dest,
530 ArrayRef<SemanticSignatureElement> Elements,
531 bool Legacy) {
532 for (const auto &E : Elements) {
533 auto Type = getComponentType(Type: E.CompType, Legacy);
534 // SigComponentType and PSV ComponentType share COMPONENT_TYPE definitions.
535 Dest.push_back(Elt: {.Name: E.SemanticKind == dxbc::PSV::SemanticKind::Arbitrary
536 ? E.SemanticName
537 : StringRef(),
538 .Indices: E.SemanticIndices, .StartRow: static_cast<uint8_t>(E.StartRow), .Cols: E.Cols,
539 .StartCol: E.StartCol, .Allocated: E.isAllocated(), .Kind: E.SemanticKind,
540 .Type: static_cast<dxbc::PSV::ComponentType>(Type), .Mode: E.InterpMode,
541 .DynamicMask: E.DynIndexMask, .Stream: static_cast<uint8_t>(E.GSStream)});
542 }
543}
544
545MDTuple *EntrySignature::getAsMetadata(LLVMContext &Ctx,
546 VersionTuple ValidatorVersion) const {
547 if (Inputs.empty() && Outputs.empty())
548 return nullptr;
549 return MDNode::get(Context&: Ctx,
550 MDs: {emitSignature(Ctx, Elements: Inputs, ValidatorVersion),
551 emitSignature(Ctx, Elements: Outputs, ValidatorVersion), nullptr});
552}
553
554void EntrySignature::buildSignatures(mcdxbc::Signature &Input,
555 mcdxbc::Signature &Output,
556 VersionTuple ValidatorVersion) const {
557 bool Legacy = !ValidatorVersion.empty() &&
558 ValidatorVersion != VersionTuple(0, 0) &&
559 ValidatorVersion < VersionTuple(1, 5);
560 buildSignature(Sig&: Input, Elements: Inputs, Input: true, Native16: UseNative16Bit, Legacy);
561 buildSignature(Sig&: Output, Elements: Outputs, Input: false, Native16: UseNative16Bit, Legacy);
562}
563
564void EntrySignature::updatePSV(mcdxbc::PSVRuntimeInfo &PSV,
565 VersionTuple ValidatorVersion) const {
566 bool Legacy = !ValidatorVersion.empty() &&
567 ValidatorVersion != VersionTuple(0, 0) &&
568 ValidatorVersion < VersionTuple(1, 5);
569 buildPSVElements(Dest&: PSV.InputElements, Elements: Inputs, Legacy);
570 buildPSVElements(Dest&: PSV.OutputElements, Elements: Outputs, Legacy);
571 PSV.BaseData.SigInputVectors = InputVectors;
572 PSV.BaseData.SigOutputVectors[0] = OutputVectors;
573 PSV.InputOutputMap[0] = InputOutputMap;
574 if (Stage == Triple::Vertex)
575 PSV.BaseData.StageInfo.VS.OutputPositionPresent =
576 llvm::any_of(Range: Outputs, P: [](const auto &E) {
577 return E.SemanticKind == dxbc::PSV::SemanticKind::Position;
578 });
579 if (Stage == Triple::Pixel)
580 PSV.BaseData.StageInfo.PS.SampleFrequency =
581 llvm::any_of(Range: Inputs, P: [](const auto &E) {
582 return E.InterpMode == dxbc::PSV::InterpolationMode::LinearSample ||
583 E.InterpMode ==
584 dxbc::PSV::InterpolationMode::LinearNoperspectiveSample;
585 });
586}
587
588SmallVector<uint32_t> EntrySignature::getDependencyState() const {
589 SmallVector<uint32_t> State = {InputVectors * 4, OutputVectors * 4};
590 llvm::append_range(C&: State, R: InputOutputMap);
591 return State;
592}
593
594void EntrySignature::print(raw_ostream &OS) const {
595 auto Print = [&](StringRef Name, ArrayRef<SemanticSignatureElement> Elements,
596 unsigned Vectors) {
597 OS << " " << Name << ": " << Elements.size() << " elements, " << Vectors
598 << " vectors\n";
599 for (const auto &E : Elements)
600 OS << " " << E.SigId << ": " << E.SemanticName << " rows=" << E.Rows
601 << " cols=" << unsigned(E.Cols) << " at " << E.StartRow << ":"
602 << unsigned(E.StartCol) << " usage=" << unsigned(E.UsageMask)
603 << " dynamic=" << unsigned(E.DynIndexMask) << '\n';
604 };
605 Print("Inputs", Inputs, InputVectors);
606 Print("Outputs", Outputs, OutputVectors);
607}
608
609void ModuleSignatureInfo::print(raw_ostream &OS, const Module &M) const {
610 for (const Function &F : M)
611 if (const auto *Sig = get(F: &F)) {
612 OS << "Semantic signatures for '" << F.getName() << "':\n";
613 Sig->print(OS);
614 }
615}
616
617AnalysisKey SignatureAnalysis::Key;
618ModuleSignatureInfo SignatureAnalysis::run(Module &M,
619 ModuleAnalysisManager &AM) {
620 return collectSignatures(M, MMI: AM.getResult<DXILMetadataAnalysis>(IR&: M));
621}
622
623PreservedAnalyses SignatureAnalysisPrinter::run(Module &M,
624 ModuleAnalysisManager &AM) {
625 AM.getResult<SignatureAnalysis>(IR&: M).print(OS, M);
626 return PreservedAnalyses::all();
627}
628
629bool SignatureAnalysisWrapper::runOnModule(Module &M) {
630 Info = std::make_unique<ModuleSignatureInfo>(args: collectSignatures(
631 M, MMI: getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata()));
632 return false;
633}
634
635void SignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {
636 AU.setPreservesAll();
637 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
638}
639
640void SignatureAnalysisWrapper::print(raw_ostream &OS, const Module *M) const {
641 if (Info)
642 Info->print(OS, M: *M);
643}
644
645char SignatureAnalysisWrapper::ID;
646INITIALIZE_PASS_BEGIN(SignatureAnalysisWrapper, "dxil-signature-analysis",
647 "DXIL Semantic Signature Analysis", false, true)
648INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
649INITIALIZE_PASS_END(SignatureAnalysisWrapper, "dxil-signature-analysis",
650 "DXIL Semantic Signature Analysis", false, true)
651