LLVM 24.0.0git
DXILSignatureAnalysis.cpp
Go to the documentation of this file.
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
10#include "DirectX.h"
11#include "llvm/ADT/STLExtras.h"
15#include "llvm/IR/Constants.h"
18#include "llvm/IR/IntrinsicsDirectX.h"
19#include "llvm/IR/Module.h"
22#include "llvm/Support/Error.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) {
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.
42 if (!Node || Node->getNumOperands() != 13)
43 return signatureError("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>(Node->getOperand(I));
48 unsigned Width = (I == 7 || (I >= 9 && I <= 11)) ? 8 : 32;
49 if (!CI || CI->getBitWidth() != Width)
50 return signatureError("expected i" + Twine(Width) + " at operand " +
51 Twine(I));
52 }
53 if (!isa_and_nonnull<MDString>(Node->getOperand(1)))
54 return signatureError("expected semantic name string");
55 auto *Indices = dyn_cast_or_null<MDNode>(Node->getOperand(4));
56 if (!Indices)
57 return signatureError("expected semantic indices node");
58 for (const MDOperand &Index : Indices->operands()) {
60 if (!CI || CI->getBitWidth() != 32)
61 return signatureError("expected i32 semantic index");
62 }
63 return Error::success();
64}
65
71
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 "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 "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 "SV_InstanceID requires a scalar 16- or 32-bit unsigned integer");
92 break;
93 case dxbc::PSV::SemanticKind::ShadingRate:
94 if (E.Rows != 1 || E.Cols != 1 ||
95 (E.CompType != ElementType::U16 && E.CompType != ElementType::U32))
96 return signatureError(
97 "SV_ShadingRate requires a scalar 16- or 32-bit unsigned integer");
98 break;
99 case dxbc::PSV::SemanticKind::SampleIndex:
100 if (E.Rows != 1 || E.Cols != 1 ||
101 (E.CompType != ElementType::U16 && E.CompType != ElementType::U32))
102 return signatureError(
103 "SV_SampleIndex requires a scalar 16- or 32-bit unsigned integer");
104 break;
105 case dxbc::PSV::SemanticKind::PrimitiveID:
106 if (E.Rows != 1 || E.Cols != 1 ||
107 (E.CompType != ElementType::U16 && E.CompType != ElementType::U32))
108 return signatureError(
109 "SV_PrimitiveID requires a scalar 16- or 32-bit unsigned integer");
110 break;
111 case dxbc::PSV::SemanticKind::Barycentrics:
112 if (E.Rows != 1 || E.Cols != 3 ||
113 (E.CompType != ElementType::F16 && E.CompType != ElementType::F32))
114 return signatureError("SV_Barycentrics requires one row of three 16- or "
115 "32-bit floating-point components");
116 break;
117 default:
118 break;
119 }
120 return Error::success();
121}
122
124 switch (E.SemanticKind) {
125 case dxbc::PSV::SemanticKind::Target:
126 if (E.Rows != 1 || E.SemanticIndices.front() >= 8)
127 return signatureError(
128 "pixel targets require one row and an index within 0-7");
129 break;
130 case dxbc::PSV::SemanticKind::VertexID:
131 if (E.SemanticIndices.front() != 0)
132 return signatureError("SV_VertexID requires semantic index 0");
133 break;
134 case dxbc::PSV::SemanticKind::Barycentrics:
135 if (E.SemanticIndices.front() != 0)
136 return signatureError("SV_Barycentrics requires semantic index 0");
137 break;
138 case dxbc::PSV::SemanticKind::SampleIndex:
139 if (E.SemanticIndices.front() != 0)
140 return signatureError("SV_SampleIndex requires semantic index 0");
141 break;
142 case dxbc::PSV::SemanticKind::PrimitiveID:
143 if (E.SemanticIndices.front() != 0)
144 return signatureError("SV_PrimitiveID requires semantic index 0");
145 break;
146 default:
147 break;
148 }
149 return Error::success();
150}
151
152static Error
154 const VersionTuple &ShaderModelVersion) {
155 switch (E.SemanticKind) {
156 case dxbc::PSV::SemanticKind::Barycentrics:
157 if (ShaderModelVersion < VersionTuple(6, 1))
158 return signatureError("SV_Barycentrics requires shader model 6.1");
159 break;
160 default:
161 break;
162 }
163 return Error::success();
164}
165
170 const VersionTuple &ShaderModelVersion,
171 bool Native16, unsigned &Extent) {
172 if (!MD)
173 return Error::success();
174 auto *List = dyn_cast<MDNode>(MD);
175 if (!List)
176 return signatureError("expected a signature element list or null");
177
178 std::set<std::pair<std::string, uint32_t>> Semantics;
179 constexpr unsigned MaxAllocatedElements = MaxSignatureRows * 4;
180 unsigned NumAllocated = 0;
181 std::array<uint8_t, MaxSignatureRows> AllocatedColumns = {};
182 std::array<dxbc::PSV::InterpolationMode, MaxSignatureRows> RowModes = {};
183 std::array<bool, MaxSignatureRows> RowNative16 = {};
184 for (const MDOperand &Op : List->operands()) {
186 if (Error Err = checkElementNode(Node))
187 return Err;
189 if (!Parsed)
190 return Parsed.takeError();
191 SemanticSignatureElement E = std::move(*Parsed);
192 if (E.SigId != Out.size())
193 return signatureError("signature IDs must be dense and in list order");
194 if (Stage != Triple::Vertex && Stage != Triple::Pixel)
195 return signatureError("nonempty signatures are currently supported only "
196 "for vertex and pixel entries");
197 if (!E.Rows || E.Rows > MaxSignatureRows)
198 return signatureError("signature row count must be within 1-32");
199 if (E.SemanticName.empty() || E.SemanticName.contains('\0'))
200 return signatureError("invalid semantic name");
201 if (E.CompType != ElementType::F16 && E.CompType != ElementType::F32 &&
202 !isIntegerComponent(E.CompType))
203 return signatureError("unsupported signature component type");
204 if (E.GSStream != 0)
205 return signatureError("nonzero stream requires a geometry output");
206 auto NamedKind = getSemanticKind(E.SemanticName);
207 auto Interpretation = getInterpretationKind(NamedKind, Stage, IO);
208 if (Interpretation == SemanticInterpretation::Invalid)
209 return signatureError("invalid or unsupported semantic for this stage "
210 "and signature category");
211 if (Interpretation == SemanticInterpretation::NotAllocated)
212 return signatureError("semantic accessed by a dedicated intrinsic must "
213 "not appear in an input/output signature");
214 auto ExpectedKind = Interpretation == SemanticInterpretation::Arbitrary
215 ? dxbc::PSV::SemanticKind::Arbitrary
216 : NamedKind;
217 if (E.SemanticKind != ExpectedKind)
218 return signatureError("semantic name and kind disagree at this signature "
219 "point");
220 if (Interpretation == SemanticInterpretation::NotPacked) {
221 if (E.isAllocated())
222 return signatureError(E.SemanticName +
223 " must not have an allocated location");
224 } else {
225 if (!E.isAllocated())
226 return signatureError("signature element " + Twine(E.SigId) + " ('" +
227 E.SemanticName + "') has no allocated location");
228 if (E.StartRow >= MaxSignatureRows ||
229 E.Rows > MaxSignatureRows - E.StartRow || E.StartCol + E.Cols > 4)
230 return signatureError(
231 "allocated signature element exceeds register bounds");
232 }
233 if (E.InterpMode == dxbc::PSV::InterpolationMode::Invalid)
234 return signatureError("invalid interpolation mode");
235
236 for (uint32_t Index : E.SemanticIndices)
237 if (!Semantics.emplace(E.SemanticName.upper(), Index).second)
238 return signatureError("duplicate semantic name and index");
239 if (Error Err = diagnoseSemanticType(E))
240 return Err;
241 if (Error Err = diagnoseSemanticIndex(E))
242 return Err;
243 if (Error Err = diagnoseSemanticShaderModel(E, ShaderModelVersion))
244 return Err;
245 if (E.SemanticKind == dxbc::PSV::SemanticKind::Barycentrics) {
247 if (E.InterpMode == Mode::Undefined || E.InterpMode == Mode::Constant)
248 return signatureError("SV_Barycentrics requires perspective or "
249 "noperspective interpolation");
250 }
251
252 if (Stage == Triple::Vertex && IO == IOType::In &&
253 (E.StartRow != Extent || E.StartCol != 0))
254 return signatureError("vertex inputs require stacked locations in "
255 "signature order (element " +
256 Twine(E.SigId) + ")");
257 if (Interpretation == SemanticInterpretation::Target &&
258 (E.StartRow != E.SemanticIndices.front() || E.StartCol != 0))
259 return signatureError("pixel target location must match its semantic "
260 "index at column 0");
261 if (Stage == Triple::Pixel && IO == IOType::In &&
262 isIntegerComponent(E.CompType) &&
263 E.InterpMode != dxbc::PSV::InterpolationMode::Constant)
264 return signatureError(
265 "integer pixel inputs require constant interpolation");
266
267 if (E.isAllocated()) {
268 if (++NumAllocated > MaxAllocatedElements)
269 return signatureError("too many signature elements");
270 // Co-packed elements must obey row constraints, even when their component
271 // masks do not overlap. Min-precision types occupy 32-bit components.
272 bool IsNative16 = Native16 && (E.CompType == ElementType::F16 ||
273 E.CompType == ElementType::I16 ||
274 E.CompType == ElementType::U16);
275 uint8_t Mask = E.getDeclaredMask();
276 for (unsigned Row = E.StartRow; Row != E.StartRow + E.Rows; ++Row) {
277 if (AllocatedColumns[Row] & Mask)
278 return signatureError("signature elements overlap at row " +
279 Twine(Row) + " (element " + Twine(E.SigId) +
280 ")");
281 if (AllocatedColumns[Row] && RowModes[Row] != E.InterpMode)
282 return signatureError(
283 "signature elements have different interpolation "
284 "modes at row " +
285 Twine(Row) + " (element " + Twine(E.SigId) + ")");
286 if (AllocatedColumns[Row] && RowNative16[Row] != IsNative16)
287 return signatureError("signature elements have different component "
288 "widths at row " +
289 Twine(Row) + " (element " + Twine(E.SigId) +
290 ")");
291 AllocatedColumns[Row] |= Mask;
292 RowModes[Row] = E.InterpMode;
293 RowNative16[Row] = IsNative16;
294 }
295 Extent = std::max(Extent, E.StartRow + E.Rows);
296 }
297 E.SemanticName = Info.Names.insert(E.SemanticName).first->getKey();
298
299 // Access masks will be recomputed so reset to 0 here.
300 E.UsageMask = 0;
301 E.DynIndexMask = 0;
302 Out.push_back(std::move(E));
303 }
304 return Error::success();
305}
306
308 bool Input = I.getIntrinsicID() == Intrinsic::dx_load_input;
309 auto &Elements = Input ? Sig.Inputs : Sig.Outputs;
310 auto *ID = dyn_cast<ConstantInt>(I.getArgOperand(0));
311 auto *Col = dyn_cast<ConstantInt>(I.getArgOperand(2));
312 StringRef Category = Input ? "input" : "output";
313 assert(ID && "signature ID is marked as ImmArg and must be constant");
314 if (ID->getZExtValue() >= Elements.size())
315 return signatureError(Category +
316 " signature: signature access has an invalid element "
317 "ID " +
318 Twine(ID->getZExtValue()));
319 auto &E = Elements[ID->getZExtValue()];
320 auto AccessError = [&](const Twine &Message) {
321 return signatureError(Category + " signature element " + Twine(E.SigId) +
322 " ('" + E.SemanticName + "'): " + Message);
323 };
324 if (E.SemanticKind == dxbc::PSV::SemanticKind::SampleIndex)
325 return AccessError("must not be read with dx.op.load/store");
326 Type *Ty = Input ? I.getType() : I.getArgOperand(3)->getType();
327 unsigned Width = 1;
328 if (auto *VT = dyn_cast<FixedVectorType>(Ty)) {
329 Width = VT->getNumElements();
330 Ty = VT->getElementType();
331 }
332 if (!Col || Col->getZExtValue() >= E.Cols ||
333 Width > E.Cols - Col->getZExtValue())
334 return AccessError("signature access has an invalid component index");
335 auto *Row = dyn_cast<ConstantInt>(I.getArgOperand(1));
336 if (Row && Row->getZExtValue() >= E.Rows)
337 return AccessError("signature access has an invalid row index");
338 if (!Row && E.Rows == 1)
339 return AccessError(
340 "dynamic indexing requires a multi-row signature element");
341 bool CorrectType = false;
342 switch (E.CompType) {
343 case ElementType::F16:
344 CorrectType = Ty->isHalfTy();
345 break;
346 case ElementType::F32:
347 CorrectType = Ty->isFloatTy();
348 break;
349 case ElementType::I16:
350 case ElementType::U16:
351 CorrectType = Ty->isIntegerTy(16);
352 break;
353 case ElementType::I1:
354 // Boolean signature elements use the i32 load/store overload.
355 CorrectType = Ty->isIntegerTy(32);
356 break;
357 case ElementType::I32:
358 case ElementType::U32:
359 CorrectType = Ty->isIntegerTy(32);
360 break;
361 default:
362 llvm_unreachable("invalid signature component type");
363 }
364 if (!CorrectType)
365 return AccessError("signature access type disagrees with its element");
366 uint8_t Mask = ((1U << Width) - 1) << Col->getZExtValue();
367 E.UsageMask |= Mask << E.getStartColOrZero();
368 if (!Row)
369 E.DynIndexMask |= Mask;
370 return Error::success();
371}
372
374 // Each output vector needs four component bits, so one 32-bit word holds
375 // eight vectors. Adding seven rounds up to include a partially filled word.
376 unsigned Words = (Sig.OutputVectors + 7) / 8;
377 Sig.InputOutputMap.assign(Sig.InputVectors * 4 * Words, 0);
378 // Conservatively connect every accessed input component to every written
379 // output component. This includes control, memory, call, and dynamic-index
380 // dependencies without incorrectly claiming that unknown dependencies are
381 // absent. Unused components and padding remain zero. Both DXIL and PSV use
382 // this same map; a more precise dependency analysis can refine it later.
383 for (const auto &Input : Sig.Inputs) {
384 if (!Input.isAllocated())
385 continue;
386 for (unsigned IR = 0; IR != Input.Rows; ++IR)
387 for (unsigned IC = 0; IC != 4; ++IC) {
388 if (!(Input.UsageMask & (1U << IC)))
389 continue;
390 unsigned Base = ((Input.StartRow + IR) * 4 + IC) * Words;
391 for (const auto &Output : Sig.Outputs)
392 for (unsigned OR = 0; OR != Output.Rows; ++OR)
393 for (unsigned OC = 0; OC != 4; ++OC) {
394 if (!(Output.UsageMask & (1U << OC)))
395 continue;
396 unsigned Bit = (Output.StartRow + OR) * 4 + OC;
397 Sig.InputOutputMap[Base + Bit / 32] |= 1U << (Bit % 32);
398 }
399 }
400 }
401}
402
406 if (NamedMDNode *Table = M.getNamedMetadata("dx.semantic.signatures")) {
407 for (const MDNode *Record : Table->operands()) {
408 if (Record->getNumOperands() != 3)
409 return signatureError(
410 "expected an entry/input/output signature triple");
411 auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Record->getOperand(0));
412 auto *F = VAM ? dyn_cast<Function>(VAM->getValue()) : nullptr;
413 if (!F || F->getParent() != &M || F->isDeclaration())
414 return signatureError(
415 "signature entry must be a defined function in the module");
416 auto EP =
418 [F](const EntryProperties &E) { return E.Entry == F; });
419 if (EP == MMI.EntryPropertyVec.end())
420 return signatureError("signature function is not a shader entry");
421 if (Info.Entries.contains(F))
422 return signatureError("duplicate signature record for entry '" +
423 F->getName() + "'");
424 EntrySignature Sig;
425 Sig.Stage = EP->ShaderStage;
427 M.getModuleFlag("dx.nativelowprec")))
428 Sig.UseNative16Bit = !Native->isZero();
429 if (Sig.UseNative16Bit && MMI.ShaderModelVersion < VersionTuple(6, 2))
430 return signatureError(
431 "native 16-bit signatures require shader model 6.2");
432 auto AddContext = [&](Error Err, StringRef Category) -> Error {
433 return signatureError("entry '" + F->getName() + "' " + Category +
434 " signature: " + toString(std::move(Err)));
435 };
436 if (Error Err = parseSignature(
437 Record->getOperand(1), Sig.Inputs, Info, Sig.Stage, IOType::In,
439 return AddContext(std::move(Err), "input");
440 if (Error Err = parseSignature(
441 Record->getOperand(2), Sig.Outputs, Info, Sig.Stage, IOType::Out,
443 return AddContext(std::move(Err), "output");
444 for (const Instruction &I : instructions(F))
445 if (auto *II = dyn_cast<IntrinsicInst>(&I);
447 if (Error Err = analyzeAccess(*II, Sig))
448 return signatureError("entry '" + F->getName() +
449 "': " + toString(std::move(Err)));
451 Info.Entries.try_emplace(F, std::move(Sig));
452 }
453 }
454 // Signature IDs are local to an entry. Do not guess which entry a helper's
455 // accesses belong to, even if that helper happens to have a single caller.
456 for (const Function &F : M)
457 if (!Info.Entries.contains(&F))
458 for (const Instruction &I : instructions(F))
459 if (auto *II = dyn_cast<IntrinsicInst>(&I);
461 return signatureError("signature access in function '" + F.getName() +
462 "' has no entry signature metadata");
463 return std::move(Info);
464}
465
467 const ModuleMetadataInfo &MMI) {
468 auto Result = analyzeModule(M, MMI);
469 if (!Result) {
470 M.getContext().emitError("Invalid semantic signature: " +
471 toString(Result.takeError()));
472 return ModuleSignatureInfo();
473 }
474 return std::move(*Result);
475}
476
479 VersionTuple ValidatorVersion) {
480 if (Elements.empty())
481 return nullptr;
482 auto I32 = [&](uint32_t V) {
483 return ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Ctx), V));
484 };
485 auto I8 = [&](uint8_t V) {
486 return ConstantAsMetadata::get(ConstantInt::get(Type::getInt8Ty(Ctx), V));
487 };
489 for (const auto &E : Elements) {
490 SmallVector<Metadata *> Indices, Props;
491 for (uint32_t Index : E.SemanticIndices)
492 Indices.push_back(I32(Index));
493 if (E.GSStream)
494 Props.append({I32(0), I32(E.GSStream)});
495 if (E.DynIndexMask)
496 Props.append({I32(2), I32(E.DynIndexMask)});
497 if (E.UsageMask &&
498 (ValidatorVersion.empty() || ValidatorVersion == VersionTuple(0, 0) ||
499 ValidatorVersion >= VersionTuple(1, 5)))
500 Props.append({I32(3), I32(E.UsageMask >> E.getStartColOrZero())});
502 Ctx, {I32(E.SigId), MDString::get(Ctx, E.SemanticName),
503 I8(static_cast<uint8_t>(E.CompType)),
504 I8(static_cast<uint8_t>(E.SemanticKind)),
505 MDNode::get(Ctx, Indices), I8(static_cast<uint8_t>(E.InterpMode)),
506 I32(E.Rows), I8(E.Cols), I32(E.StartRow), I8(E.StartCol),
507 Props.empty() ? nullptr : MDNode::get(Ctx, Props)}));
508 }
509 return MDNode::get(Ctx, Nodes);
510}
511
513 switch (Type) {
514 case ElementType::I1:
515 return Legacy ? dxbc::SigComponentType::Unknown
516 : dxbc::SigComponentType::UInt32;
517 case ElementType::I16:
518 return dxbc::SigComponentType::SInt16;
519 case ElementType::U16:
520 return dxbc::SigComponentType::UInt16;
521 case ElementType::I32:
522 return dxbc::SigComponentType::SInt32;
523 case ElementType::U32:
524 return dxbc::SigComponentType::UInt32;
525 case ElementType::F16:
526 return dxbc::SigComponentType::Float16;
527 case ElementType::F32:
528 return dxbc::SigComponentType::Float32;
529 default:
530 llvm_unreachable("invalid signature component type");
531 }
532}
533
535 using KindTy = dxbc::PSV::SemanticKind;
536 switch (Kind) {
537 case KindTy::Arbitrary:
538 return dxbc::D3DSystemValue::Undefined;
539 case KindTy::VertexID:
540 return dxbc::D3DSystemValue::VertexID;
541 case KindTy::InstanceID:
542 return dxbc::D3DSystemValue::InstanceID;
543 case KindTy::Position:
544 return dxbc::D3DSystemValue::Position;
545 case KindTy::IsFrontFace:
546 return dxbc::D3DSystemValue::IsFrontFace;
547 case KindTy::ClipDistance:
548 return dxbc::D3DSystemValue::ClipDistance;
549 case KindTy::CullDistance:
550 return dxbc::D3DSystemValue::CullDistance;
551 case KindTy::Target:
552 return dxbc::D3DSystemValue::Target;
553 case KindTy::ShadingRate:
554 return dxbc::D3DSystemValue::ShadingRate;
555 case KindTy::Barycentrics:
556 return dxbc::D3DSystemValue::Barycentrics;
557 case KindTy::SampleIndex:
558 return dxbc::D3DSystemValue::SampleIndex;
559 case KindTy::PrimitiveID:
560 return dxbc::D3DSystemValue::PrimitiveID;
561 default:
562 llvm_unreachable("validated vertex/pixel signature semantic");
563 }
564}
565
566// The DXIL reader normalizes system-value semantic names when loading module
567// metadata. The validator then recreates ISG1/OSG1 from those normalized names
568// and compares the parts byte-for-byte, so the container must use the same
569// spelling even if HLSL (or the source metadata) used a different casing.
571 using Kind = dxbc::PSV::SemanticKind;
572 switch (E.SemanticKind) {
573 case Kind::Arbitrary:
574 return E.SemanticName;
575 case Kind::VertexID:
576 return "SV_VertexID";
577 case Kind::InstanceID:
578 return "SV_InstanceID";
579 case Kind::Position:
580 return "SV_Position";
581 case Kind::IsFrontFace:
582 return "SV_IsFrontFace";
583 case Kind::ClipDistance:
584 return "SV_ClipDistance";
585 case Kind::CullDistance:
586 return "SV_CullDistance";
587 case Kind::Target:
588 return "SV_Target";
589 case Kind::ShadingRate:
590 return "SV_ShadingRate";
591 case Kind::Barycentrics:
592 return "SV_Barycentrics";
593 case Kind::SampleIndex:
594 return "SV_SampleIndex";
595 case Kind::PrimitiveID:
596 return "SV_PrimitiveID";
597 default:
598 llvm_unreachable("validated vertex/pixel signature semantic");
599 }
600}
601
604 bool Input, bool Native16, bool Legacy) {
605 for (const auto &E : Elements) {
606 uint8_t Mask = E.getDeclaredMask();
607 uint8_t ExclusiveMask =
608 Input ? E.getAlwaysReadsMask() : E.getNeverWritesMask();
609 if (Legacy)
610 ExclusiveMask = Input ? 0 : static_cast<uint8_t>(~Mask);
611 for (auto [Row, Index] : enumerate(E.SemanticIndices))
612 Sig.addParam(E.GSStream, getContainerSemanticName(E), Index,
613 getSystemValue(E.SemanticKind),
614 getComponentType(E.CompType, Legacy),
615 E.isAllocated() ? E.StartRow + Row : UnallocatedRow, Mask,
616 ExclusiveMask, E.getMinPrecision(!Native16));
617 }
618}
619
622 bool Legacy) {
623 for (const auto &E : Elements) {
624 auto Type = getComponentType(E.CompType, Legacy);
625 // SigComponentType and PSV ComponentType share COMPONENT_TYPE definitions.
626 Dest.push_back(
627 {E.SemanticKind == dxbc::PSV::SemanticKind::Arbitrary ? E.SemanticName
628 : StringRef(),
629 E.SemanticIndices,
630 E.isAllocated() ? static_cast<uint8_t>(E.StartRow) : uint8_t(0),
631 E.Cols, E.getStartColOrZero(), E.isAllocated(), E.SemanticKind,
632 static_cast<dxbc::PSV::ComponentType>(Type), E.InterpMode,
633 E.DynIndexMask, static_cast<uint8_t>(E.GSStream)});
634 }
635}
636
638 VersionTuple ValidatorVersion) const {
639 if (Inputs.empty() && Outputs.empty())
640 return nullptr;
641 return MDNode::get(Ctx,
642 {emitSignature(Ctx, Inputs, ValidatorVersion),
643 emitSignature(Ctx, Outputs, ValidatorVersion), nullptr});
644}
645
647 mcdxbc::Signature &Output,
648 VersionTuple ValidatorVersion) const {
649 bool Legacy = !ValidatorVersion.empty() &&
650 ValidatorVersion != VersionTuple(0, 0) &&
651 ValidatorVersion < VersionTuple(1, 5);
654}
655
657 // Each output vector needs four component bits, so one 32-bit word holds
658 // eight vectors. Conservatively mark every written output component as
659 // dependent on the view ID, matching the conservative input/output map.
660 SmallVector<uint32_t> Mask((OutputVectors + 7) / 8, 0);
661 for (const auto &Output : Outputs) {
662 if (!Output.isAllocated())
663 continue;
664 for (unsigned R = 0; R != Output.Rows; ++R)
665 for (unsigned C = 0; C != 4; ++C) {
666 if (!(Output.UsageMask & (1U << C)))
667 continue;
668 unsigned Bit = (Output.StartRow + R) * 4 + C;
669 Mask[Bit / 32] |= 1U << (Bit % 32);
670 }
671 }
672 return Mask;
673}
674
676 VersionTuple ValidatorVersion,
677 bool UsesViewID) const {
678 bool Legacy = !ValidatorVersion.empty() &&
679 ValidatorVersion != VersionTuple(0, 0) &&
680 ValidatorVersion < VersionTuple(1, 5);
686 if (UsesViewID)
688 if (Stage == Triple::Vertex)
690 llvm::any_of(Outputs, [](const auto &E) {
691 return E.SemanticKind == dxbc::PSV::SemanticKind::Position;
692 });
693 if (Stage == Triple::Pixel)
695 llvm::any_of(Inputs, [](const auto &E) {
696 return E.InterpMode == dxbc::PSV::InterpolationMode::LinearSample ||
697 E.InterpMode ==
698 dxbc::PSV::InterpolationMode::LinearNoperspectiveSample ||
699 E.SemanticKind == dxbc::PSV::SemanticKind::SampleIndex;
700 });
701}
702
706 if (UsesViewID)
709 return State;
710}
711
713 auto Print = [&](StringRef Name, ArrayRef<SemanticSignatureElement> Elements,
714 unsigned Vectors) {
715 OS << " " << Name << ": " << Elements.size() << " elements, " << Vectors
716 << " vectors\n";
717 for (const auto &E : Elements)
718 OS << " " << E.SigId << ": " << E.SemanticName << " rows=" << E.Rows
719 << " cols=" << unsigned(E.Cols) << " at " << E.StartRow << ":"
720 << unsigned(E.StartCol) << " usage=" << unsigned(E.UsageMask)
721 << " dynamic=" << unsigned(E.DynIndexMask) << '\n';
722 };
723 Print("Inputs", Inputs, InputVectors);
724 Print("Outputs", Outputs, OutputVectors);
725}
726
728 for (const Function &F : M)
729 if (const auto *Sig = get(&F)) {
730 OS << "Semantic signatures for '" << F.getName() << "':\n";
731 Sig->print(OS);
732 }
733}
734
735AnalysisKey SignatureAnalysis::Key;
740
746
748 Info = std::make_unique<ModuleSignatureInfo>(collectSignatures(
749 M, getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata()));
750 return false;
751}
752
757
759 if (Info)
760 Info->print(OS, *M);
761}
762
765 "DXIL Semantic Signature Analysis", false, true)
768 "DXIL Semantic Signature Analysis", false, true)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Error diagnoseSemanticType(const SemanticSignatureElement &E)
static Error diagnoseSemanticIndex(const SemanticSignatureElement &E)
static bool isSignatureAccess(const IntrinsicInst &I)
static bool isIntegerComponent(ElementType Type)
static MDNode * emitSignature(LLVMContext &Ctx, ArrayRef< SemanticSignatureElement > Elements, VersionTuple ValidatorVersion)
static void buildSignature(mcdxbc::Signature &Sig, ArrayRef< SemanticSignatureElement > Elements, bool Input, bool Native16, bool Legacy)
static dxbc::D3DSystemValue getSystemValue(dxbc::PSV::SemanticKind Kind)
static Expected< ModuleSignatureInfo > analyzeModule(Module &M, const ModuleMetadataInfo &MMI)
static ModuleSignatureInfo collectSignatures(Module &M, const ModuleMetadataInfo &MMI)
static dxbc::SigComponentType getComponentType(ElementType Type, bool Legacy)
static void buildDependencyMap(EntrySignature &Sig)
static Error diagnoseSemanticShaderModel(const SemanticSignatureElement &E, const VersionTuple &ShaderModelVersion)
static Error checkElementNode(const MDNode *Node)
static void buildPSVElements(SmallVectorImpl< mcdxbc::PSVSignatureElement > &Dest, ArrayRef< SemanticSignatureElement > Elements, bool Legacy)
static StringRef getContainerSemanticName(const SemanticSignatureElement &E)
static Error signatureError(const Twine &Message)
static Error analyzeAccess(const IntrinsicInst &I, EntrySignature &Sig)
static Error parseSignature(Metadata *MD, SmallVectorImpl< SemanticSignatureElement > &Out, ModuleSignatureInfo &Info, Triple::EnvironmentType Stage, IOType IO, const VersionTuple &ShaderModelVersion, bool Native16, unsigned &Extent)
Module.h This file contains the declarations for the Module class.
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:85
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
This file contains some templates that are useful if you are working with the STL at all.
This file contains some functions that are useful when dealing with strings.
The Input class is used to parse a yaml document into in-memory structs and vectors.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
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
void print(raw_ostream &OS, const Module *M) const override
print - Print out the internal state of the pass.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
A wrapper class for inspecting calls to intrinsic functions.
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
Tracking metadata reference owned by Metadata.
Definition Metadata.h:902
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:597
Tuple of metadata.
Definition Metadata.h:1496
Root of the metadata hierarchy.
Definition Metadata.h:64
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A tuple of MDNodes.
Definition Metadata.h:1797
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
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
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
Represents a version number in the form major[.minor[.subminor[.build]]].
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
const EntrySignature * get(const Function *F) const
void print(raw_ostream &OS, const Module &M) const
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
void print(raw_ostream &OS, const Module *M) const override
print - Print out the internal state of the pass.
Result run(Module &M, ModuleAnalysisManager &AM)
void addParam(uint32_t Stream, StringRef Name, uint32_t Index, dxbc::D3DSystemValue SystemValue, dxbc::SigComponentType CompType, uint32_t Register, uint8_t Mask, uint8_t ExclusiveMask, dxbc::SigMinPrecision MinPrecision)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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 dxbc::PSV::SemanticKind getSemanticKind(StringRef SemanticName)
static constexpr unsigned MaxSignatureRows
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.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
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
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
bool isa_and_nonnull(const Y &Val)
Definition Casting.h:676
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
DWARFExpression::Operation Op
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29
SmallVector< hlsl::SemanticSignatureElement > Inputs
SmallVector< uint32_t > getDependencyState(bool UsesViewID) const
Return the serialized dx.viewIdState words for this entry: input scalar count, output scalar count,...
Triple::EnvironmentType Stage
void buildSignatures(mcdxbc::Signature &Input, mcdxbc::Signature &Output, VersionTuple ValidatorVersion) const
Append ISG1/OSG1 parameters to the supplied builders.
SmallVector< hlsl::SemanticSignatureElement > Outputs
void updatePSV(mcdxbc::PSVRuntimeInfo &PSV, VersionTuple ValidatorVersion, bool UsesViewID) const
Append PSV signature elements and set vector extents, the dependency map, the view ID output mask if ...
SmallVector< uint32_t > getViewIDOutputMask() const
Return the mask of output scalars that depend on the view ID.
MDTuple * getAsMetadata(LLVMContext &Ctx, VersionTuple ValidatorVersion) const
Return the DXIL input/output/patch-constant signature triple.
SmallVector< uint32_t > InputOutputMap
void print(raw_ostream &OS) const
SmallVector< EntryProperties > EntryPropertyVec
static LLVM_ABI Expected< SemanticSignatureElement > fromMetadata(const MDNode *Node)
dxbc::PSV::v3::RuntimeInfo BaseData
SmallVector< PSVSignatureElement > InputElements
SmallVector< PSVSignatureElement > OutputElements
std::array< SmallVector< uint32_t >, 4 > OutputVectorMasks
std::array< SmallVector< uint32_t >, 4 > InputOutputMap