1145449b1SDimitry Andric //===- DXContainer.cpp - DXContainer object file implementation -----------===//
2145449b1SDimitry Andric //
3145449b1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4145449b1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5145449b1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6145449b1SDimitry Andric //
7145449b1SDimitry Andric //===----------------------------------------------------------------------===//
8145449b1SDimitry Andric
9145449b1SDimitry Andric #include "llvm/Object/DXContainer.h"
10145449b1SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h"
11145449b1SDimitry Andric #include "llvm/Object/Error.h"
12b1c73532SDimitry Andric #include "llvm/Support/Alignment.h"
13e3b55780SDimitry Andric #include "llvm/Support/FormatVariadic.h"
14145449b1SDimitry Andric
15145449b1SDimitry Andric using namespace llvm;
16145449b1SDimitry Andric using namespace llvm::object;
17145449b1SDimitry Andric
parseFailed(const Twine & Msg)18145449b1SDimitry Andric static Error parseFailed(const Twine &Msg) {
19145449b1SDimitry Andric return make_error<GenericBinaryError>(Msg.str(), object_error::parse_failed);
20145449b1SDimitry Andric }
21145449b1SDimitry Andric
22145449b1SDimitry Andric template <typename T>
readStruct(StringRef Buffer,const char * Src,T & Struct)23145449b1SDimitry Andric static Error readStruct(StringRef Buffer, const char *Src, T &Struct) {
24145449b1SDimitry Andric // Don't read before the beginning or past the end of the file
25145449b1SDimitry Andric if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end())
26145449b1SDimitry Andric return parseFailed("Reading structure out of file bounds");
27145449b1SDimitry Andric
28145449b1SDimitry Andric memcpy(&Struct, Src, sizeof(T));
29145449b1SDimitry Andric // DXContainer is always little endian
30145449b1SDimitry Andric if (sys::IsBigEndianHost)
31145449b1SDimitry Andric Struct.swapBytes();
32145449b1SDimitry Andric return Error::success();
33145449b1SDimitry Andric }
34145449b1SDimitry Andric
35145449b1SDimitry Andric template <typename T>
readInteger(StringRef Buffer,const char * Src,T & Val,Twine Str="structure")36e3b55780SDimitry Andric static Error readInteger(StringRef Buffer, const char *Src, T &Val,
37e3b55780SDimitry Andric Twine Str = "structure") {
38e3b55780SDimitry Andric static_assert(std::is_integral_v<T>,
39145449b1SDimitry Andric "Cannot call readInteger on non-integral type.");
40145449b1SDimitry Andric // Don't read before the beginning or past the end of the file
41145449b1SDimitry Andric if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end())
42e3b55780SDimitry Andric return parseFailed(Twine("Reading ") + Str + " out of file bounds");
43145449b1SDimitry Andric
44e3b55780SDimitry Andric // The DXContainer offset table is comprised of uint32_t values but not padded
45e3b55780SDimitry Andric // to a 64-bit boundary. So Parts may start unaligned if there is an odd
46e3b55780SDimitry Andric // number of parts and part data itself is not required to be padded.
47e3b55780SDimitry Andric if (reinterpret_cast<uintptr_t>(Src) % alignof(T) != 0)
48e3b55780SDimitry Andric memcpy(reinterpret_cast<char *>(&Val), Src, sizeof(T));
49e3b55780SDimitry Andric else
50145449b1SDimitry Andric Val = *reinterpret_cast<const T *>(Src);
51145449b1SDimitry Andric // DXContainer is always little endian
52145449b1SDimitry Andric if (sys::IsBigEndianHost)
53145449b1SDimitry Andric sys::swapByteOrder(Val);
54145449b1SDimitry Andric return Error::success();
55145449b1SDimitry Andric }
56145449b1SDimitry Andric
DXContainer(MemoryBufferRef O)57145449b1SDimitry Andric DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {}
58145449b1SDimitry Andric
parseHeader()59145449b1SDimitry Andric Error DXContainer::parseHeader() {
60145449b1SDimitry Andric return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header);
61145449b1SDimitry Andric }
62145449b1SDimitry Andric
parseDXILHeader(StringRef Part)63e3b55780SDimitry Andric Error DXContainer::parseDXILHeader(StringRef Part) {
64145449b1SDimitry Andric if (DXIL)
65145449b1SDimitry Andric return parseFailed("More than one DXIL part is present in the file");
66e3b55780SDimitry Andric const char *Current = Part.begin();
67145449b1SDimitry Andric dxbc::ProgramHeader Header;
68e3b55780SDimitry Andric if (Error Err = readStruct(Part, Current, Header))
69145449b1SDimitry Andric return Err;
70145449b1SDimitry Andric Current += offsetof(dxbc::ProgramHeader, Bitcode) + Header.Bitcode.Offset;
71145449b1SDimitry Andric DXIL.emplace(std::make_pair(Header, Current));
72145449b1SDimitry Andric return Error::success();
73145449b1SDimitry Andric }
74145449b1SDimitry Andric
parseShaderFeatureFlags(StringRef Part)75ac9a064cSDimitry Andric Error DXContainer::parseShaderFeatureFlags(StringRef Part) {
76ac9a064cSDimitry Andric if (ShaderFeatureFlags)
77e3b55780SDimitry Andric return parseFailed("More than one SFI0 part is present in the file");
78e3b55780SDimitry Andric uint64_t FlagValue = 0;
79e3b55780SDimitry Andric if (Error Err = readInteger(Part, Part.begin(), FlagValue))
80e3b55780SDimitry Andric return Err;
81ac9a064cSDimitry Andric ShaderFeatureFlags = FlagValue;
82e3b55780SDimitry Andric return Error::success();
83e3b55780SDimitry Andric }
84e3b55780SDimitry Andric
parseHash(StringRef Part)85e3b55780SDimitry Andric Error DXContainer::parseHash(StringRef Part) {
86e3b55780SDimitry Andric if (Hash)
87e3b55780SDimitry Andric return parseFailed("More than one HASH part is present in the file");
88e3b55780SDimitry Andric dxbc::ShaderHash ReadHash;
89e3b55780SDimitry Andric if (Error Err = readStruct(Part, Part.begin(), ReadHash))
90e3b55780SDimitry Andric return Err;
91e3b55780SDimitry Andric Hash = ReadHash;
92e3b55780SDimitry Andric return Error::success();
93e3b55780SDimitry Andric }
94e3b55780SDimitry Andric
parsePSVInfo(StringRef Part)957fa27ce4SDimitry Andric Error DXContainer::parsePSVInfo(StringRef Part) {
967fa27ce4SDimitry Andric if (PSVInfo)
977fa27ce4SDimitry Andric return parseFailed("More than one PSV0 part is present in the file");
987fa27ce4SDimitry Andric PSVInfo = DirectX::PSVRuntimeInfo(Part);
997fa27ce4SDimitry Andric // Parsing the PSVRuntime info occurs late because we need to read data from
1007fa27ce4SDimitry Andric // other parts first.
1017fa27ce4SDimitry Andric return Error::success();
1027fa27ce4SDimitry Andric }
1037fa27ce4SDimitry Andric
initialize(StringRef Part)104b1c73532SDimitry Andric Error DirectX::Signature::initialize(StringRef Part) {
105b1c73532SDimitry Andric dxbc::ProgramSignatureHeader SigHeader;
106b1c73532SDimitry Andric if (Error Err = readStruct(Part, Part.begin(), SigHeader))
107b1c73532SDimitry Andric return Err;
108b1c73532SDimitry Andric size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount;
109b1c73532SDimitry Andric
110b1c73532SDimitry Andric if (Part.size() < Size + SigHeader.FirstParamOffset)
111b1c73532SDimitry Andric return parseFailed("Signature parameters extend beyond the part boundary");
112b1c73532SDimitry Andric
113b1c73532SDimitry Andric Parameters.Data = Part.substr(SigHeader.FirstParamOffset, Size);
114b1c73532SDimitry Andric
115b1c73532SDimitry Andric StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size);
116b1c73532SDimitry Andric StringTable = Part.substr(SigHeader.FirstParamOffset + Size);
117b1c73532SDimitry Andric
118b1c73532SDimitry Andric for (const auto &Param : Parameters) {
119b1c73532SDimitry Andric if (Param.NameOffset < StringTableOffset)
120b1c73532SDimitry Andric return parseFailed("Invalid parameter name offset: name starts before "
121b1c73532SDimitry Andric "the first name offset");
122b1c73532SDimitry Andric if (Param.NameOffset - StringTableOffset > StringTable.size())
123b1c73532SDimitry Andric return parseFailed("Invalid parameter name offset: name starts after the "
124b1c73532SDimitry Andric "end of the part data");
125b1c73532SDimitry Andric }
126b1c73532SDimitry Andric return Error::success();
127b1c73532SDimitry Andric }
128b1c73532SDimitry Andric
parsePartOffsets()129145449b1SDimitry Andric Error DXContainer::parsePartOffsets() {
130e3b55780SDimitry Andric uint32_t LastOffset =
131e3b55780SDimitry Andric sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t));
132145449b1SDimitry Andric const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header);
133145449b1SDimitry Andric for (uint32_t Part = 0; Part < Header.PartCount; ++Part) {
134145449b1SDimitry Andric uint32_t PartOffset;
135145449b1SDimitry Andric if (Error Err = readInteger(Data.getBuffer(), Current, PartOffset))
136145449b1SDimitry Andric return Err;
137e3b55780SDimitry Andric if (PartOffset < LastOffset)
138e3b55780SDimitry Andric return parseFailed(
139e3b55780SDimitry Andric formatv(
140e3b55780SDimitry Andric "Part offset for part {0} begins before the previous part ends",
141e3b55780SDimitry Andric Part)
142e3b55780SDimitry Andric .str());
143145449b1SDimitry Andric Current += sizeof(uint32_t);
144e3b55780SDimitry Andric if (PartOffset >= Data.getBufferSize())
145145449b1SDimitry Andric return parseFailed("Part offset points beyond boundary of the file");
146e3b55780SDimitry Andric // To prevent overflow when reading the part name, we subtract the part name
147e3b55780SDimitry Andric // size from the buffer size, rather than adding to the offset. Since the
148e3b55780SDimitry Andric // file header is larger than the part header we can't reach this code
149e3b55780SDimitry Andric // unless the buffer is at least as large as a part header, so this
150e3b55780SDimitry Andric // subtraction can't underflow.
151e3b55780SDimitry Andric if (PartOffset >= Data.getBufferSize() - sizeof(dxbc::PartHeader::Name))
152e3b55780SDimitry Andric return parseFailed("File not large enough to read part name");
153145449b1SDimitry Andric PartOffsets.push_back(PartOffset);
154145449b1SDimitry Andric
155e3b55780SDimitry Andric dxbc::PartType PT =
156e3b55780SDimitry Andric dxbc::parsePartType(Data.getBuffer().substr(PartOffset, 4));
157e3b55780SDimitry Andric uint32_t PartDataStart = PartOffset + sizeof(dxbc::PartHeader);
158e3b55780SDimitry Andric uint32_t PartSize;
159e3b55780SDimitry Andric if (Error Err = readInteger(Data.getBuffer(),
160e3b55780SDimitry Andric Data.getBufferStart() + PartOffset + 4,
161e3b55780SDimitry Andric PartSize, "part size"))
162145449b1SDimitry Andric return Err;
163e3b55780SDimitry Andric StringRef PartData = Data.getBuffer().substr(PartDataStart, PartSize);
164e3b55780SDimitry Andric LastOffset = PartOffset + PartSize;
165e3b55780SDimitry Andric switch (PT) {
166e3b55780SDimitry Andric case dxbc::PartType::DXIL:
167e3b55780SDimitry Andric if (Error Err = parseDXILHeader(PartData))
168e3b55780SDimitry Andric return Err;
169e3b55780SDimitry Andric break;
170e3b55780SDimitry Andric case dxbc::PartType::SFI0:
171ac9a064cSDimitry Andric if (Error Err = parseShaderFeatureFlags(PartData))
172e3b55780SDimitry Andric return Err;
173e3b55780SDimitry Andric break;
174e3b55780SDimitry Andric case dxbc::PartType::HASH:
175e3b55780SDimitry Andric if (Error Err = parseHash(PartData))
176e3b55780SDimitry Andric return Err;
177e3b55780SDimitry Andric break;
1787fa27ce4SDimitry Andric case dxbc::PartType::PSV0:
1797fa27ce4SDimitry Andric if (Error Err = parsePSVInfo(PartData))
1807fa27ce4SDimitry Andric return Err;
1817fa27ce4SDimitry Andric break;
182b1c73532SDimitry Andric case dxbc::PartType::ISG1:
183b1c73532SDimitry Andric if (Error Err = InputSignature.initialize(PartData))
184b1c73532SDimitry Andric return Err;
185b1c73532SDimitry Andric break;
186b1c73532SDimitry Andric case dxbc::PartType::OSG1:
187b1c73532SDimitry Andric if (Error Err = OutputSignature.initialize(PartData))
188b1c73532SDimitry Andric return Err;
189b1c73532SDimitry Andric break;
190b1c73532SDimitry Andric case dxbc::PartType::PSG1:
191b1c73532SDimitry Andric if (Error Err = PatchConstantSignature.initialize(PartData))
192b1c73532SDimitry Andric return Err;
193b1c73532SDimitry Andric break;
194e3b55780SDimitry Andric case dxbc::PartType::Unknown:
195e3b55780SDimitry Andric break;
196e3b55780SDimitry Andric }
197145449b1SDimitry Andric }
1987fa27ce4SDimitry Andric
1997fa27ce4SDimitry Andric // Fully parsing the PSVInfo requires knowing the shader kind which we read
2007fa27ce4SDimitry Andric // out of the program header in the DXIL part.
2017fa27ce4SDimitry Andric if (PSVInfo) {
2027fa27ce4SDimitry Andric if (!DXIL)
2037fa27ce4SDimitry Andric return parseFailed("Cannot fully parse pipeline state validation "
2047fa27ce4SDimitry Andric "information without DXIL part.");
2057fa27ce4SDimitry Andric if (Error Err = PSVInfo->parse(DXIL->first.ShaderKind))
2067fa27ce4SDimitry Andric return Err;
2077fa27ce4SDimitry Andric }
208145449b1SDimitry Andric return Error::success();
209145449b1SDimitry Andric }
210145449b1SDimitry Andric
create(MemoryBufferRef Object)211145449b1SDimitry Andric Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) {
212145449b1SDimitry Andric DXContainer Container(Object);
213145449b1SDimitry Andric if (Error Err = Container.parseHeader())
214145449b1SDimitry Andric return std::move(Err);
215145449b1SDimitry Andric if (Error Err = Container.parsePartOffsets())
216145449b1SDimitry Andric return std::move(Err);
217145449b1SDimitry Andric return Container;
218145449b1SDimitry Andric }
219145449b1SDimitry Andric
updateIteratorImpl(const uint32_t Offset)220145449b1SDimitry Andric void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) {
221145449b1SDimitry Andric StringRef Buffer = Container.Data.getBuffer();
222145449b1SDimitry Andric const char *Current = Buffer.data() + Offset;
223145449b1SDimitry Andric // Offsets are validated during parsing, so all offsets in the container are
224145449b1SDimitry Andric // valid and contain enough readable data to read a header.
225145449b1SDimitry Andric cantFail(readStruct(Buffer, Current, IteratorState.Part));
226145449b1SDimitry Andric IteratorState.Data =
227145449b1SDimitry Andric StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size);
228145449b1SDimitry Andric IteratorState.Offset = Offset;
229145449b1SDimitry Andric }
2307fa27ce4SDimitry Andric
parse(uint16_t ShaderKind)2317fa27ce4SDimitry Andric Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) {
2327fa27ce4SDimitry Andric Triple::EnvironmentType ShaderStage = dxbc::getShaderStage(ShaderKind);
2337fa27ce4SDimitry Andric
2347fa27ce4SDimitry Andric const char *Current = Data.begin();
2357fa27ce4SDimitry Andric if (Error Err = readInteger(Data, Current, Size))
2367fa27ce4SDimitry Andric return Err;
2377fa27ce4SDimitry Andric Current += sizeof(uint32_t);
2387fa27ce4SDimitry Andric
2397fa27ce4SDimitry Andric StringRef PSVInfoData = Data.substr(sizeof(uint32_t), Size);
2407fa27ce4SDimitry Andric
2417fa27ce4SDimitry Andric if (PSVInfoData.size() < Size)
2427fa27ce4SDimitry Andric return parseFailed(
2437fa27ce4SDimitry Andric "Pipeline state data extends beyond the bounds of the part");
2447fa27ce4SDimitry Andric
2457fa27ce4SDimitry Andric using namespace dxbc::PSV;
2467fa27ce4SDimitry Andric
2477fa27ce4SDimitry Andric const uint32_t PSVVersion = getVersion();
2487fa27ce4SDimitry Andric
2497fa27ce4SDimitry Andric // Detect the PSVVersion by looking at the size field.
250ac9a064cSDimitry Andric if (PSVVersion == 3) {
251ac9a064cSDimitry Andric v3::RuntimeInfo Info;
252ac9a064cSDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info))
253ac9a064cSDimitry Andric return Err;
254ac9a064cSDimitry Andric if (sys::IsBigEndianHost)
255ac9a064cSDimitry Andric Info.swapBytes(ShaderStage);
256ac9a064cSDimitry Andric BasicInfo = Info;
257ac9a064cSDimitry Andric } else if (PSVVersion == 2) {
2587fa27ce4SDimitry Andric v2::RuntimeInfo Info;
2597fa27ce4SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info))
2607fa27ce4SDimitry Andric return Err;
2617fa27ce4SDimitry Andric if (sys::IsBigEndianHost)
2627fa27ce4SDimitry Andric Info.swapBytes(ShaderStage);
2637fa27ce4SDimitry Andric BasicInfo = Info;
2647fa27ce4SDimitry Andric } else if (PSVVersion == 1) {
2657fa27ce4SDimitry Andric v1::RuntimeInfo Info;
2667fa27ce4SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info))
2677fa27ce4SDimitry Andric return Err;
2687fa27ce4SDimitry Andric if (sys::IsBigEndianHost)
2697fa27ce4SDimitry Andric Info.swapBytes(ShaderStage);
2707fa27ce4SDimitry Andric BasicInfo = Info;
271b1c73532SDimitry Andric } else if (PSVVersion == 0) {
2727fa27ce4SDimitry Andric v0::RuntimeInfo Info;
2737fa27ce4SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info))
2747fa27ce4SDimitry Andric return Err;
2757fa27ce4SDimitry Andric if (sys::IsBigEndianHost)
2767fa27ce4SDimitry Andric Info.swapBytes(ShaderStage);
2777fa27ce4SDimitry Andric BasicInfo = Info;
278b1c73532SDimitry Andric } else
279b1c73532SDimitry Andric return parseFailed(
280b1c73532SDimitry Andric "Cannot read PSV Runtime Info, unsupported PSV version.");
281b1c73532SDimitry Andric
2827fa27ce4SDimitry Andric Current += Size;
2837fa27ce4SDimitry Andric
2847fa27ce4SDimitry Andric uint32_t ResourceCount = 0;
2857fa27ce4SDimitry Andric if (Error Err = readInteger(Data, Current, ResourceCount))
2867fa27ce4SDimitry Andric return Err;
2877fa27ce4SDimitry Andric Current += sizeof(uint32_t);
2887fa27ce4SDimitry Andric
2897fa27ce4SDimitry Andric if (ResourceCount > 0) {
2907fa27ce4SDimitry Andric if (Error Err = readInteger(Data, Current, Resources.Stride))
2917fa27ce4SDimitry Andric return Err;
2927fa27ce4SDimitry Andric Current += sizeof(uint32_t);
2937fa27ce4SDimitry Andric
2947fa27ce4SDimitry Andric size_t BindingDataSize = Resources.Stride * ResourceCount;
2957fa27ce4SDimitry Andric Resources.Data = Data.substr(Current - Data.begin(), BindingDataSize);
2967fa27ce4SDimitry Andric
2977fa27ce4SDimitry Andric if (Resources.Data.size() < BindingDataSize)
2987fa27ce4SDimitry Andric return parseFailed(
2997fa27ce4SDimitry Andric "Resource binding data extends beyond the bounds of the part");
3007fa27ce4SDimitry Andric
3017fa27ce4SDimitry Andric Current += BindingDataSize;
302b1c73532SDimitry Andric } else
303b1c73532SDimitry Andric Resources.Stride = sizeof(v2::ResourceBindInfo);
304b1c73532SDimitry Andric
305b1c73532SDimitry Andric // PSV version 0 ends after the resource bindings.
306b1c73532SDimitry Andric if (PSVVersion == 0)
307b1c73532SDimitry Andric return Error::success();
308b1c73532SDimitry Andric
309b1c73532SDimitry Andric // String table starts at a 4-byte offset.
310b1c73532SDimitry Andric Current = reinterpret_cast<const char *>(
311312c0ed1SDimitry Andric alignTo<4>(reinterpret_cast<uintptr_t>(Current)));
312b1c73532SDimitry Andric
313b1c73532SDimitry Andric uint32_t StringTableSize = 0;
314b1c73532SDimitry Andric if (Error Err = readInteger(Data, Current, StringTableSize))
315b1c73532SDimitry Andric return Err;
316b1c73532SDimitry Andric if (StringTableSize % 4 != 0)
317b1c73532SDimitry Andric return parseFailed("String table misaligned");
318b1c73532SDimitry Andric Current += sizeof(uint32_t);
319b1c73532SDimitry Andric StringTable = StringRef(Current, StringTableSize);
320b1c73532SDimitry Andric
321b1c73532SDimitry Andric Current += StringTableSize;
322b1c73532SDimitry Andric
323b1c73532SDimitry Andric uint32_t SemanticIndexTableSize = 0;
324b1c73532SDimitry Andric if (Error Err = readInteger(Data, Current, SemanticIndexTableSize))
325b1c73532SDimitry Andric return Err;
326b1c73532SDimitry Andric Current += sizeof(uint32_t);
327b1c73532SDimitry Andric
328b1c73532SDimitry Andric SemanticIndexTable.reserve(SemanticIndexTableSize);
329b1c73532SDimitry Andric for (uint32_t I = 0; I < SemanticIndexTableSize; ++I) {
330b1c73532SDimitry Andric uint32_t Index = 0;
331b1c73532SDimitry Andric if (Error Err = readInteger(Data, Current, Index))
332b1c73532SDimitry Andric return Err;
333b1c73532SDimitry Andric Current += sizeof(uint32_t);
334b1c73532SDimitry Andric SemanticIndexTable.push_back(Index);
335b1c73532SDimitry Andric }
336b1c73532SDimitry Andric
337b1c73532SDimitry Andric uint8_t InputCount = getSigInputCount();
338b1c73532SDimitry Andric uint8_t OutputCount = getSigOutputCount();
339b1c73532SDimitry Andric uint8_t PatchOrPrimCount = getSigPatchOrPrimCount();
340b1c73532SDimitry Andric
341b1c73532SDimitry Andric uint32_t ElementCount = InputCount + OutputCount + PatchOrPrimCount;
342b1c73532SDimitry Andric
343b1c73532SDimitry Andric if (ElementCount > 0) {
344b1c73532SDimitry Andric if (Error Err = readInteger(Data, Current, SigInputElements.Stride))
345b1c73532SDimitry Andric return Err;
346b1c73532SDimitry Andric Current += sizeof(uint32_t);
347b1c73532SDimitry Andric // Assign the stride to all the arrays.
348b1c73532SDimitry Andric SigOutputElements.Stride = SigPatchOrPrimElements.Stride =
349b1c73532SDimitry Andric SigInputElements.Stride;
350b1c73532SDimitry Andric
351ac9a064cSDimitry Andric if (Data.end() - Current <
352ac9a064cSDimitry Andric (ptrdiff_t)(ElementCount * SigInputElements.Stride))
353b1c73532SDimitry Andric return parseFailed(
354b1c73532SDimitry Andric "Signature elements extend beyond the size of the part");
355b1c73532SDimitry Andric
356b1c73532SDimitry Andric size_t InputSize = SigInputElements.Stride * InputCount;
357b1c73532SDimitry Andric SigInputElements.Data = Data.substr(Current - Data.begin(), InputSize);
358b1c73532SDimitry Andric Current += InputSize;
359b1c73532SDimitry Andric
360b1c73532SDimitry Andric size_t OutputSize = SigOutputElements.Stride * OutputCount;
361b1c73532SDimitry Andric SigOutputElements.Data = Data.substr(Current - Data.begin(), OutputSize);
362b1c73532SDimitry Andric Current += OutputSize;
363b1c73532SDimitry Andric
364b1c73532SDimitry Andric size_t PSize = SigPatchOrPrimElements.Stride * PatchOrPrimCount;
365b1c73532SDimitry Andric SigPatchOrPrimElements.Data = Data.substr(Current - Data.begin(), PSize);
366b1c73532SDimitry Andric Current += PSize;
367b1c73532SDimitry Andric }
368b1c73532SDimitry Andric
369b1c73532SDimitry Andric ArrayRef<uint8_t> OutputVectorCounts = getOutputVectorCounts();
370b1c73532SDimitry Andric uint8_t PatchConstOrPrimVectorCount = getPatchConstOrPrimVectorCount();
371b1c73532SDimitry Andric uint8_t InputVectorCount = getInputVectorCount();
372b1c73532SDimitry Andric
373b1c73532SDimitry Andric auto maskDwordSize = [](uint8_t Vector) {
374b1c73532SDimitry Andric return (static_cast<uint32_t>(Vector) + 7) >> 3;
375b1c73532SDimitry Andric };
376b1c73532SDimitry Andric
377b1c73532SDimitry Andric auto mapTableSize = [maskDwordSize](uint8_t X, uint8_t Y) {
378b1c73532SDimitry Andric return maskDwordSize(Y) * X * 4;
379b1c73532SDimitry Andric };
380b1c73532SDimitry Andric
381b1c73532SDimitry Andric if (usesViewID()) {
382b1c73532SDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
383b1c73532SDimitry Andric // The vector mask is one bit per component and 4 components per vector.
384b1c73532SDimitry Andric // We can compute the number of dwords required by rounding up to the next
385b1c73532SDimitry Andric // multiple of 8.
386b1c73532SDimitry Andric uint32_t NumDwords =
387b1c73532SDimitry Andric maskDwordSize(static_cast<uint32_t>(OutputVectorCounts[I]));
388b1c73532SDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t);
389b1c73532SDimitry Andric OutputVectorMasks[I].Data = Data.substr(Current - Data.begin(), NumBytes);
390b1c73532SDimitry Andric Current += NumBytes;
391b1c73532SDimitry Andric }
392b1c73532SDimitry Andric
393b1c73532SDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0) {
394b1c73532SDimitry Andric uint32_t NumDwords = maskDwordSize(PatchConstOrPrimVectorCount);
395b1c73532SDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t);
396b1c73532SDimitry Andric PatchOrPrimMasks.Data = Data.substr(Current - Data.begin(), NumBytes);
397b1c73532SDimitry Andric Current += NumBytes;
398b1c73532SDimitry Andric }
399b1c73532SDimitry Andric }
400b1c73532SDimitry Andric
401b1c73532SDimitry Andric // Input/Output mapping table
402b1c73532SDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
403b1c73532SDimitry Andric if (InputVectorCount == 0 || OutputVectorCounts[I] == 0)
404b1c73532SDimitry Andric continue;
405b1c73532SDimitry Andric uint32_t NumDwords = mapTableSize(InputVectorCount, OutputVectorCounts[I]);
406b1c73532SDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t);
407b1c73532SDimitry Andric InputOutputMap[I].Data = Data.substr(Current - Data.begin(), NumBytes);
408b1c73532SDimitry Andric Current += NumBytes;
409b1c73532SDimitry Andric }
410b1c73532SDimitry Andric
411b1c73532SDimitry Andric // Hull shader: Input/Patch mapping table
412b1c73532SDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0 &&
413b1c73532SDimitry Andric InputVectorCount > 0) {
414b1c73532SDimitry Andric uint32_t NumDwords =
415b1c73532SDimitry Andric mapTableSize(InputVectorCount, PatchConstOrPrimVectorCount);
416b1c73532SDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t);
417b1c73532SDimitry Andric InputPatchMap.Data = Data.substr(Current - Data.begin(), NumBytes);
418b1c73532SDimitry Andric Current += NumBytes;
419b1c73532SDimitry Andric }
420b1c73532SDimitry Andric
421b1c73532SDimitry Andric // Domain Shader: Patch/Output mapping table
422b1c73532SDimitry Andric if (ShaderStage == Triple::Domain && PatchConstOrPrimVectorCount > 0 &&
423b1c73532SDimitry Andric OutputVectorCounts[0] > 0) {
424b1c73532SDimitry Andric uint32_t NumDwords =
425b1c73532SDimitry Andric mapTableSize(PatchConstOrPrimVectorCount, OutputVectorCounts[0]);
426b1c73532SDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t);
427b1c73532SDimitry Andric PatchOutputMap.Data = Data.substr(Current - Data.begin(), NumBytes);
428b1c73532SDimitry Andric Current += NumBytes;
4297fa27ce4SDimitry Andric }
4307fa27ce4SDimitry Andric
4317fa27ce4SDimitry Andric return Error::success();
4327fa27ce4SDimitry Andric }
433b1c73532SDimitry Andric
getSigInputCount() const434b1c73532SDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const {
435ac9a064cSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
436ac9a064cSDimitry Andric return P->SigInputElements;
437b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
438b1c73532SDimitry Andric return P->SigInputElements;
439b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
440b1c73532SDimitry Andric return P->SigInputElements;
441b1c73532SDimitry Andric return 0;
442b1c73532SDimitry Andric }
443b1c73532SDimitry Andric
getSigOutputCount() const444b1c73532SDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const {
445ac9a064cSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
446ac9a064cSDimitry Andric return P->SigOutputElements;
447b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
448b1c73532SDimitry Andric return P->SigOutputElements;
449b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
450b1c73532SDimitry Andric return P->SigOutputElements;
451b1c73532SDimitry Andric return 0;
452b1c73532SDimitry Andric }
453b1c73532SDimitry Andric
getSigPatchOrPrimCount() const454b1c73532SDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const {
455ac9a064cSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
456ac9a064cSDimitry Andric return P->SigPatchOrPrimElements;
457b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
458b1c73532SDimitry Andric return P->SigPatchOrPrimElements;
459b1c73532SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
460b1c73532SDimitry Andric return P->SigPatchOrPrimElements;
461b1c73532SDimitry Andric return 0;
462b1c73532SDimitry Andric }
463