xref: /llvm-project/llvm/lib/Object/DXContainer.cpp (revision c62c74639ad6eb0988861077b7123fa2b2c17cc5)
14070aa01SChris Bieneman //===- DXContainer.cpp - DXContainer object file implementation -----------===//
24070aa01SChris Bieneman //
34070aa01SChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44070aa01SChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
54070aa01SChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64070aa01SChris Bieneman //
74070aa01SChris Bieneman //===----------------------------------------------------------------------===//
84070aa01SChris Bieneman 
94070aa01SChris Bieneman #include "llvm/Object/DXContainer.h"
104070aa01SChris Bieneman #include "llvm/BinaryFormat/DXContainer.h"
114070aa01SChris Bieneman #include "llvm/Object/Error.h"
120c3f51c0SChris Bieneman #include "llvm/Support/Alignment.h"
13621ffbcbSChris Bieneman #include "llvm/Support/FormatVariadic.h"
144070aa01SChris Bieneman 
154070aa01SChris Bieneman using namespace llvm;
164070aa01SChris Bieneman using namespace llvm::object;
174070aa01SChris Bieneman 
parseFailed(const Twine & Msg)184070aa01SChris Bieneman static Error parseFailed(const Twine &Msg) {
194070aa01SChris Bieneman   return make_error<GenericBinaryError>(Msg.str(), object_error::parse_failed);
204070aa01SChris Bieneman }
214070aa01SChris Bieneman 
224070aa01SChris Bieneman template <typename T>
readStruct(StringRef Buffer,const char * Src,T & Struct)239e3919daSChris Bieneman static Error readStruct(StringRef Buffer, const char *Src, T &Struct) {
244070aa01SChris Bieneman   // Don't read before the beginning or past the end of the file
259e3919daSChris Bieneman   if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end())
264070aa01SChris Bieneman     return parseFailed("Reading structure out of file bounds");
274070aa01SChris Bieneman 
289e3919daSChris Bieneman   memcpy(&Struct, Src, sizeof(T));
2947258ffcSChris Bieneman   // DXContainer is always little endian
304070aa01SChris Bieneman   if (sys::IsBigEndianHost)
319e3919daSChris Bieneman     Struct.swapBytes();
329e3919daSChris Bieneman   return Error::success();
339e3919daSChris Bieneman }
349e3919daSChris Bieneman 
359e3919daSChris Bieneman template <typename T>
readInteger(StringRef Buffer,const char * Src,T & Val,Twine Str="structure")36621ffbcbSChris Bieneman static Error readInteger(StringRef Buffer, const char *Src, T &Val,
37621ffbcbSChris Bieneman                          Twine Str = "structure") {
386aa050a6SNathan James   static_assert(std::is_integral_v<T>,
399e3919daSChris Bieneman                 "Cannot call readInteger on non-integral type.");
409e3919daSChris Bieneman   // Don't read before the beginning or past the end of the file
419e3919daSChris Bieneman   if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end())
42621ffbcbSChris Bieneman     return parseFailed(Twine("Reading ") + Str + " out of file bounds");
439e3919daSChris Bieneman 
4449dc58f5SChris Bieneman   // The DXContainer offset table is comprised of uint32_t values but not padded
4549dc58f5SChris Bieneman   // to a 64-bit boundary. So Parts may start unaligned if there is an odd
4649dc58f5SChris Bieneman   // number of parts and part data itself is not required to be padded.
4749dc58f5SChris Bieneman   if (reinterpret_cast<uintptr_t>(Src) % alignof(T) != 0)
4849dc58f5SChris Bieneman     memcpy(reinterpret_cast<char *>(&Val), Src, sizeof(T));
4949dc58f5SChris Bieneman   else
509e3919daSChris Bieneman     Val = *reinterpret_cast<const T *>(Src);
519e3919daSChris Bieneman   // DXContainer is always little endian
529e3919daSChris Bieneman   if (sys::IsBigEndianHost)
539e3919daSChris Bieneman     sys::swapByteOrder(Val);
544070aa01SChris Bieneman   return Error::success();
554070aa01SChris Bieneman }
564070aa01SChris Bieneman 
DXContainer(MemoryBufferRef O)574070aa01SChris Bieneman DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {}
584070aa01SChris Bieneman 
parseHeader()594070aa01SChris Bieneman Error DXContainer::parseHeader() {
604070aa01SChris Bieneman   return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header);
614070aa01SChris Bieneman }
624070aa01SChris Bieneman 
parseDXILHeader(StringRef Part)63621ffbcbSChris Bieneman Error DXContainer::parseDXILHeader(StringRef Part) {
6421c94523SChris Bieneman   if (DXIL)
6521c94523SChris Bieneman     return parseFailed("More than one DXIL part is present in the file");
66621ffbcbSChris Bieneman   const char *Current = Part.begin();
6721c94523SChris Bieneman   dxbc::ProgramHeader Header;
68621ffbcbSChris Bieneman   if (Error Err = readStruct(Part, Current, Header))
6921c94523SChris Bieneman     return Err;
7021c94523SChris Bieneman   Current += offsetof(dxbc::ProgramHeader, Bitcode) + Header.Bitcode.Offset;
7121c94523SChris Bieneman   DXIL.emplace(std::make_pair(Header, Current));
7221c94523SChris Bieneman   return Error::success();
7321c94523SChris Bieneman }
7421c94523SChris Bieneman 
parseShaderFeatureFlags(StringRef Part)7550136ca1SXiang Li Error DXContainer::parseShaderFeatureFlags(StringRef Part) {
7650136ca1SXiang Li   if (ShaderFeatureFlags)
7749dc58f5SChris Bieneman     return parseFailed("More than one SFI0 part is present in the file");
7849dc58f5SChris Bieneman   uint64_t FlagValue = 0;
79621ffbcbSChris Bieneman   if (Error Err = readInteger(Part, Part.begin(), FlagValue))
8049dc58f5SChris Bieneman     return Err;
8150136ca1SXiang Li   ShaderFeatureFlags = FlagValue;
8249dc58f5SChris Bieneman   return Error::success();
8349dc58f5SChris Bieneman }
8449dc58f5SChris Bieneman 
parseHash(StringRef Part)85621ffbcbSChris Bieneman Error DXContainer::parseHash(StringRef Part) {
862556ba4aSChris Bieneman   if (Hash)
872556ba4aSChris Bieneman     return parseFailed("More than one HASH part is present in the file");
882556ba4aSChris Bieneman   dxbc::ShaderHash ReadHash;
89621ffbcbSChris Bieneman   if (Error Err = readStruct(Part, Part.begin(), ReadHash))
902556ba4aSChris Bieneman     return Err;
912556ba4aSChris Bieneman   Hash = ReadHash;
922556ba4aSChris Bieneman   return Error::success();
932556ba4aSChris Bieneman }
942556ba4aSChris Bieneman 
parsePSVInfo(StringRef Part)95ad93908eSChris Bieneman Error DXContainer::parsePSVInfo(StringRef Part) {
96ad93908eSChris Bieneman   if (PSVInfo)
97ad93908eSChris Bieneman     return parseFailed("More than one PSV0 part is present in the file");
98ad93908eSChris Bieneman   PSVInfo = DirectX::PSVRuntimeInfo(Part);
99ad93908eSChris Bieneman   // Parsing the PSVRuntime info occurs late because we need to read data from
100ad93908eSChris Bieneman   // other parts first.
101ad93908eSChris Bieneman   return Error::success();
102ad93908eSChris Bieneman }
103ad93908eSChris Bieneman 
initialize(StringRef Part)1049f87522bSChris B Error DirectX::Signature::initialize(StringRef Part) {
1059f87522bSChris B   dxbc::ProgramSignatureHeader SigHeader;
1069f87522bSChris B   if (Error Err = readStruct(Part, Part.begin(), SigHeader))
1079f87522bSChris B     return Err;
1089f87522bSChris B   size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount;
1099f87522bSChris B 
1109f87522bSChris B   if (Part.size() < Size + SigHeader.FirstParamOffset)
1119f87522bSChris B     return parseFailed("Signature parameters extend beyond the part boundary");
1129f87522bSChris B 
1139f87522bSChris B   Parameters.Data = Part.substr(SigHeader.FirstParamOffset, Size);
1149f87522bSChris B 
1159f87522bSChris B   StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size);
1169f87522bSChris B   StringTable = Part.substr(SigHeader.FirstParamOffset + Size);
1179f87522bSChris B 
1189f87522bSChris B   for (const auto &Param : Parameters) {
1199f87522bSChris B     if (Param.NameOffset < StringTableOffset)
1209f87522bSChris B       return parseFailed("Invalid parameter name offset: name starts before "
1219f87522bSChris B                          "the first name offset");
1229f87522bSChris B     if (Param.NameOffset - StringTableOffset > StringTable.size())
1239f87522bSChris B       return parseFailed("Invalid parameter name offset: name starts after the "
1249f87522bSChris B                          "end of the part data");
1259f87522bSChris B   }
1269f87522bSChris B   return Error::success();
1279f87522bSChris B }
1289f87522bSChris B 
parsePartOffsets()1299e3919daSChris Bieneman Error DXContainer::parsePartOffsets() {
130621ffbcbSChris Bieneman   uint32_t LastOffset =
131621ffbcbSChris Bieneman       sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t));
1329e3919daSChris Bieneman   const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header);
1339e3919daSChris Bieneman   for (uint32_t Part = 0; Part < Header.PartCount; ++Part) {
1349e3919daSChris Bieneman     uint32_t PartOffset;
1359e3919daSChris Bieneman     if (Error Err = readInteger(Data.getBuffer(), Current, PartOffset))
1369e3919daSChris Bieneman       return Err;
137621ffbcbSChris Bieneman     if (PartOffset < LastOffset)
138621ffbcbSChris Bieneman       return parseFailed(
139621ffbcbSChris Bieneman           formatv(
140621ffbcbSChris Bieneman               "Part offset for part {0} begins before the previous part ends",
141621ffbcbSChris Bieneman               Part)
142621ffbcbSChris Bieneman               .str());
1439e3919daSChris Bieneman     Current += sizeof(uint32_t);
144621ffbcbSChris Bieneman     if (PartOffset >= Data.getBufferSize())
1459e3919daSChris Bieneman       return parseFailed("Part offset points beyond boundary of the file");
146621ffbcbSChris Bieneman     // To prevent overflow when reading the part name, we subtract the part name
147621ffbcbSChris Bieneman     // size from the buffer size, rather than adding to the offset. Since the
148621ffbcbSChris Bieneman     // file header is larger than the part header we can't reach this code
149621ffbcbSChris Bieneman     // unless the buffer is at least as large as a part header, so this
150621ffbcbSChris Bieneman     // subtraction can't underflow.
151621ffbcbSChris Bieneman     if (PartOffset >= Data.getBufferSize() - sizeof(dxbc::PartHeader::Name))
152621ffbcbSChris Bieneman       return parseFailed("File not large enough to read part name");
1539e3919daSChris Bieneman     PartOffsets.push_back(PartOffset);
15421c94523SChris Bieneman 
15563accaf4SChris Bieneman     dxbc::PartType PT =
15663accaf4SChris Bieneman         dxbc::parsePartType(Data.getBuffer().substr(PartOffset, 4));
157621ffbcbSChris Bieneman     uint32_t PartDataStart = PartOffset + sizeof(dxbc::PartHeader);
158621ffbcbSChris Bieneman     uint32_t PartSize;
159621ffbcbSChris Bieneman     if (Error Err = readInteger(Data.getBuffer(),
160621ffbcbSChris Bieneman                                 Data.getBufferStart() + PartOffset + 4,
161621ffbcbSChris Bieneman                                 PartSize, "part size"))
162621ffbcbSChris Bieneman       return Err;
163621ffbcbSChris Bieneman     StringRef PartData = Data.getBuffer().substr(PartDataStart, PartSize);
164621ffbcbSChris Bieneman     LastOffset = PartOffset + PartSize;
16563accaf4SChris Bieneman     switch (PT) {
16663accaf4SChris Bieneman     case dxbc::PartType::DXIL:
167621ffbcbSChris Bieneman       if (Error Err = parseDXILHeader(PartData))
16821c94523SChris Bieneman         return Err;
16963accaf4SChris Bieneman       break;
17049dc58f5SChris Bieneman     case dxbc::PartType::SFI0:
17150136ca1SXiang Li       if (Error Err = parseShaderFeatureFlags(PartData))
17249dc58f5SChris Bieneman         return Err;
17349dc58f5SChris Bieneman       break;
1742556ba4aSChris Bieneman     case dxbc::PartType::HASH:
175621ffbcbSChris Bieneman       if (Error Err = parseHash(PartData))
1762556ba4aSChris Bieneman         return Err;
1772556ba4aSChris Bieneman       break;
178ad93908eSChris Bieneman     case dxbc::PartType::PSV0:
179ad93908eSChris Bieneman       if (Error Err = parsePSVInfo(PartData))
180ad93908eSChris Bieneman         return Err;
181ad93908eSChris Bieneman       break;
1829f87522bSChris B     case dxbc::PartType::ISG1:
1839f87522bSChris B       if (Error Err = InputSignature.initialize(PartData))
1849f87522bSChris B         return Err;
1859f87522bSChris B       break;
1869f87522bSChris B     case dxbc::PartType::OSG1:
1879f87522bSChris B       if (Error Err = OutputSignature.initialize(PartData))
1889f87522bSChris B         return Err;
1899f87522bSChris B       break;
1909f87522bSChris B     case dxbc::PartType::PSG1:
1919f87522bSChris B       if (Error Err = PatchConstantSignature.initialize(PartData))
1929f87522bSChris B         return Err;
1939f87522bSChris B       break;
19463accaf4SChris Bieneman     case dxbc::PartType::Unknown:
19563accaf4SChris Bieneman       break;
19663accaf4SChris Bieneman     }
1979e3919daSChris Bieneman   }
198ad93908eSChris Bieneman 
199ad93908eSChris Bieneman   // Fully parsing the PSVInfo requires knowing the shader kind which we read
200ad93908eSChris Bieneman   // out of the program header in the DXIL part.
201ad93908eSChris Bieneman   if (PSVInfo) {
202ad93908eSChris Bieneman     if (!DXIL)
203ad93908eSChris Bieneman       return parseFailed("Cannot fully parse pipeline state validation "
204ad93908eSChris Bieneman                          "information without DXIL part.");
205ad93908eSChris Bieneman     if (Error Err = PSVInfo->parse(DXIL->first.ShaderKind))
206ad93908eSChris Bieneman       return Err;
207ad93908eSChris Bieneman   }
2089e3919daSChris Bieneman   return Error::success();
2099e3919daSChris Bieneman }
2109e3919daSChris Bieneman 
create(MemoryBufferRef Object)2114070aa01SChris Bieneman Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) {
2124070aa01SChris Bieneman   DXContainer Container(Object);
2134070aa01SChris Bieneman   if (Error Err = Container.parseHeader())
214b26e44e6SChris Bieneman     return std::move(Err);
2159e3919daSChris Bieneman   if (Error Err = Container.parsePartOffsets())
2169e3919daSChris Bieneman     return std::move(Err);
2174070aa01SChris Bieneman   return Container;
2184070aa01SChris Bieneman }
2199e3919daSChris Bieneman 
updateIteratorImpl(const uint32_t Offset)2209e3919daSChris Bieneman void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) {
2219e3919daSChris Bieneman   StringRef Buffer = Container.Data.getBuffer();
2229e3919daSChris Bieneman   const char *Current = Buffer.data() + Offset;
2239e3919daSChris Bieneman   // Offsets are validated during parsing, so all offsets in the container are
2249e3919daSChris Bieneman   // valid and contain enough readable data to read a header.
2259e3919daSChris Bieneman   cantFail(readStruct(Buffer, Current, IteratorState.Part));
2269e3919daSChris Bieneman   IteratorState.Data =
2279e3919daSChris Bieneman       StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size);
228352c395fSChris Bieneman   IteratorState.Offset = Offset;
2299e3919daSChris Bieneman }
230ad93908eSChris Bieneman 
parse(uint16_t ShaderKind)231ad93908eSChris Bieneman Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) {
232ad93908eSChris Bieneman   Triple::EnvironmentType ShaderStage = dxbc::getShaderStage(ShaderKind);
233ad93908eSChris Bieneman 
234ad93908eSChris Bieneman   const char *Current = Data.begin();
235ad93908eSChris Bieneman   if (Error Err = readInteger(Data, Current, Size))
236ad93908eSChris Bieneman     return Err;
237ad93908eSChris Bieneman   Current += sizeof(uint32_t);
238ad93908eSChris Bieneman 
239ad93908eSChris Bieneman   StringRef PSVInfoData = Data.substr(sizeof(uint32_t), Size);
240ad93908eSChris Bieneman 
2415fdf8605SChris Bieneman   if (PSVInfoData.size() < Size)
2425fdf8605SChris Bieneman     return parseFailed(
2435fdf8605SChris Bieneman         "Pipeline state data extends beyond the bounds of the part");
2445fdf8605SChris Bieneman 
245ad93908eSChris Bieneman   using namespace dxbc::PSV;
246ad93908eSChris Bieneman 
247ad93908eSChris Bieneman   const uint32_t PSVVersion = getVersion();
248ad93908eSChris Bieneman 
249ad93908eSChris Bieneman   // Detect the PSVVersion by looking at the size field.
250*c62c7463SCooper Partin   if (PSVVersion == 3) {
251*c62c7463SCooper Partin     v3::RuntimeInfo Info;
252*c62c7463SCooper Partin     if (Error Err = readStruct(PSVInfoData, Current, Info))
253*c62c7463SCooper Partin       return Err;
254*c62c7463SCooper Partin     if (sys::IsBigEndianHost)
255*c62c7463SCooper Partin       Info.swapBytes(ShaderStage);
256*c62c7463SCooper Partin     BasicInfo = Info;
257*c62c7463SCooper Partin   } else if (PSVVersion == 2) {
258ad93908eSChris Bieneman     v2::RuntimeInfo Info;
259ad93908eSChris Bieneman     if (Error Err = readStruct(PSVInfoData, Current, Info))
260ad93908eSChris Bieneman       return Err;
261ad93908eSChris Bieneman     if (sys::IsBigEndianHost)
262ad93908eSChris Bieneman       Info.swapBytes(ShaderStage);
263ad93908eSChris Bieneman     BasicInfo = Info;
264ad93908eSChris Bieneman   } else if (PSVVersion == 1) {
265ad93908eSChris Bieneman     v1::RuntimeInfo Info;
266ad93908eSChris Bieneman     if (Error Err = readStruct(PSVInfoData, Current, Info))
267ad93908eSChris Bieneman       return Err;
268ad93908eSChris Bieneman     if (sys::IsBigEndianHost)
269ad93908eSChris Bieneman       Info.swapBytes(ShaderStage);
270ad93908eSChris Bieneman     BasicInfo = Info;
2710c3f51c0SChris Bieneman   } else if (PSVVersion == 0) {
272ad93908eSChris Bieneman     v0::RuntimeInfo Info;
273ad93908eSChris Bieneman     if (Error Err = readStruct(PSVInfoData, Current, Info))
274ad93908eSChris Bieneman       return Err;
275ad93908eSChris Bieneman     if (sys::IsBigEndianHost)
276ad93908eSChris Bieneman       Info.swapBytes(ShaderStage);
277ad93908eSChris Bieneman     BasicInfo = Info;
2780c3f51c0SChris Bieneman   } else
2790c3f51c0SChris Bieneman     return parseFailed(
2800c3f51c0SChris Bieneman         "Cannot read PSV Runtime Info, unsupported PSV version.");
2810c3f51c0SChris Bieneman 
282ad93908eSChris Bieneman   Current += Size;
283ad93908eSChris Bieneman 
284dd3f7b02SChris Bieneman   uint32_t ResourceCount = 0;
285dd3f7b02SChris Bieneman   if (Error Err = readInteger(Data, Current, ResourceCount))
286dd3f7b02SChris Bieneman     return Err;
287dd3f7b02SChris Bieneman   Current += sizeof(uint32_t);
288dd3f7b02SChris Bieneman 
2895fdf8605SChris Bieneman   if (ResourceCount > 0) {
2905fdf8605SChris Bieneman     if (Error Err = readInteger(Data, Current, Resources.Stride))
2915fdf8605SChris Bieneman       return Err;
2925fdf8605SChris Bieneman     Current += sizeof(uint32_t);
2935fdf8605SChris Bieneman 
294dd3f7b02SChris Bieneman     size_t BindingDataSize = Resources.Stride * ResourceCount;
295dd3f7b02SChris Bieneman     Resources.Data = Data.substr(Current - Data.begin(), BindingDataSize);
296dd3f7b02SChris Bieneman 
2975fdf8605SChris Bieneman     if (Resources.Data.size() < BindingDataSize)
2985fdf8605SChris Bieneman       return parseFailed(
2995fdf8605SChris Bieneman           "Resource binding data extends beyond the bounds of the part");
3005fdf8605SChris Bieneman 
301dd3f7b02SChris Bieneman     Current += BindingDataSize;
3020c3f51c0SChris Bieneman   } else
3030c3f51c0SChris Bieneman     Resources.Stride = sizeof(v2::ResourceBindInfo);
3040c3f51c0SChris Bieneman 
3050c3f51c0SChris Bieneman   // PSV version 0 ends after the resource bindings.
3060c3f51c0SChris Bieneman   if (PSVVersion == 0)
3070c3f51c0SChris Bieneman     return Error::success();
3080c3f51c0SChris Bieneman 
3090c3f51c0SChris Bieneman   // String table starts at a 4-byte offset.
3100c3f51c0SChris Bieneman   Current = reinterpret_cast<const char *>(
31137332bc0SSimon Pilgrim       alignTo<4>(reinterpret_cast<uintptr_t>(Current)));
3120c3f51c0SChris Bieneman 
3130c3f51c0SChris Bieneman   uint32_t StringTableSize = 0;
3140c3f51c0SChris Bieneman   if (Error Err = readInteger(Data, Current, StringTableSize))
3150c3f51c0SChris Bieneman     return Err;
3160c3f51c0SChris Bieneman   if (StringTableSize % 4 != 0)
3170c3f51c0SChris Bieneman     return parseFailed("String table misaligned");
3180c3f51c0SChris Bieneman   Current += sizeof(uint32_t);
3190c3f51c0SChris Bieneman   StringTable = StringRef(Current, StringTableSize);
3200c3f51c0SChris Bieneman 
3210c3f51c0SChris Bieneman   Current += StringTableSize;
3220c3f51c0SChris Bieneman 
3230c3f51c0SChris Bieneman   uint32_t SemanticIndexTableSize = 0;
3240c3f51c0SChris Bieneman   if (Error Err = readInteger(Data, Current, SemanticIndexTableSize))
3250c3f51c0SChris Bieneman     return Err;
3260c3f51c0SChris Bieneman   Current += sizeof(uint32_t);
3270c3f51c0SChris Bieneman 
3280c3f51c0SChris Bieneman   SemanticIndexTable.reserve(SemanticIndexTableSize);
3290c3f51c0SChris Bieneman   for (uint32_t I = 0; I < SemanticIndexTableSize; ++I) {
3300c3f51c0SChris Bieneman     uint32_t Index = 0;
3310c3f51c0SChris Bieneman     if (Error Err = readInteger(Data, Current, Index))
3320c3f51c0SChris Bieneman       return Err;
3330c3f51c0SChris Bieneman     Current += sizeof(uint32_t);
3340c3f51c0SChris Bieneman     SemanticIndexTable.push_back(Index);
3350c3f51c0SChris Bieneman   }
3360c3f51c0SChris Bieneman 
3370c3f51c0SChris Bieneman   uint8_t InputCount = getSigInputCount();
3380c3f51c0SChris Bieneman   uint8_t OutputCount = getSigOutputCount();
3390c3f51c0SChris Bieneman   uint8_t PatchOrPrimCount = getSigPatchOrPrimCount();
3400c3f51c0SChris Bieneman 
3410c3f51c0SChris Bieneman   uint32_t ElementCount = InputCount + OutputCount + PatchOrPrimCount;
3420c3f51c0SChris Bieneman 
3430c3f51c0SChris Bieneman   if (ElementCount > 0) {
3440c3f51c0SChris Bieneman     if (Error Err = readInteger(Data, Current, SigInputElements.Stride))
3450c3f51c0SChris Bieneman       return Err;
3460c3f51c0SChris Bieneman     Current += sizeof(uint32_t);
3470c3f51c0SChris Bieneman     // Assign the stride to all the arrays.
3480c3f51c0SChris Bieneman     SigOutputElements.Stride = SigPatchOrPrimElements.Stride =
3490c3f51c0SChris Bieneman         SigInputElements.Stride;
3500c3f51c0SChris Bieneman 
3513db3e2ceSAlexandre Ganea     if (Data.end() - Current <
3523db3e2ceSAlexandre Ganea         (ptrdiff_t)(ElementCount * SigInputElements.Stride))
3530c3f51c0SChris Bieneman       return parseFailed(
3540c3f51c0SChris Bieneman           "Signature elements extend beyond the size of the part");
3550c3f51c0SChris Bieneman 
3560c3f51c0SChris Bieneman     size_t InputSize = SigInputElements.Stride * InputCount;
3570c3f51c0SChris Bieneman     SigInputElements.Data = Data.substr(Current - Data.begin(), InputSize);
3580c3f51c0SChris Bieneman     Current += InputSize;
3590c3f51c0SChris Bieneman 
3600c3f51c0SChris Bieneman     size_t OutputSize = SigOutputElements.Stride * OutputCount;
3610c3f51c0SChris Bieneman     SigOutputElements.Data = Data.substr(Current - Data.begin(), OutputSize);
3620c3f51c0SChris Bieneman     Current += OutputSize;
3630c3f51c0SChris Bieneman 
3640c3f51c0SChris Bieneman     size_t PSize = SigPatchOrPrimElements.Stride * PatchOrPrimCount;
3650c3f51c0SChris Bieneman     SigPatchOrPrimElements.Data = Data.substr(Current - Data.begin(), PSize);
3660c3f51c0SChris Bieneman     Current += PSize;
3675fdf8605SChris Bieneman   }
368dd3f7b02SChris Bieneman 
369b799e9daSChris B   ArrayRef<uint8_t> OutputVectorCounts = getOutputVectorCounts();
370b799e9daSChris B   uint8_t PatchConstOrPrimVectorCount = getPatchConstOrPrimVectorCount();
371b799e9daSChris B   uint8_t InputVectorCount = getInputVectorCount();
372b799e9daSChris B 
373b799e9daSChris B   auto maskDwordSize = [](uint8_t Vector) {
374b799e9daSChris B     return (static_cast<uint32_t>(Vector) + 7) >> 3;
375b799e9daSChris B   };
376b799e9daSChris B 
377b799e9daSChris B   auto mapTableSize = [maskDwordSize](uint8_t X, uint8_t Y) {
378b799e9daSChris B     return maskDwordSize(Y) * X * 4;
379b799e9daSChris B   };
380b799e9daSChris B 
381b799e9daSChris B   if (usesViewID()) {
382b799e9daSChris B     for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
383b799e9daSChris B       // The vector mask is one bit per component and 4 components per vector.
384b799e9daSChris B       // We can compute the number of dwords required by rounding up to the next
385b799e9daSChris B       // multiple of 8.
386b799e9daSChris B       uint32_t NumDwords =
387b799e9daSChris B           maskDwordSize(static_cast<uint32_t>(OutputVectorCounts[I]));
388b799e9daSChris B       size_t NumBytes = NumDwords * sizeof(uint32_t);
389b799e9daSChris B       OutputVectorMasks[I].Data = Data.substr(Current - Data.begin(), NumBytes);
390b799e9daSChris B       Current += NumBytes;
391b799e9daSChris B     }
392b799e9daSChris B 
393b799e9daSChris B     if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0) {
394b799e9daSChris B       uint32_t NumDwords = maskDwordSize(PatchConstOrPrimVectorCount);
395b799e9daSChris B       size_t NumBytes = NumDwords * sizeof(uint32_t);
396b799e9daSChris B       PatchOrPrimMasks.Data = Data.substr(Current - Data.begin(), NumBytes);
397b799e9daSChris B       Current += NumBytes;
398b799e9daSChris B     }
399b799e9daSChris B   }
400b799e9daSChris B 
401b799e9daSChris B   // Input/Output mapping table
402b799e9daSChris B   for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
403b799e9daSChris B     if (InputVectorCount == 0 || OutputVectorCounts[I] == 0)
404b799e9daSChris B       continue;
405b799e9daSChris B     uint32_t NumDwords = mapTableSize(InputVectorCount, OutputVectorCounts[I]);
406b799e9daSChris B     size_t NumBytes = NumDwords * sizeof(uint32_t);
407b799e9daSChris B     InputOutputMap[I].Data = Data.substr(Current - Data.begin(), NumBytes);
408b799e9daSChris B     Current += NumBytes;
409b799e9daSChris B   }
410b799e9daSChris B 
411b799e9daSChris B   // Hull shader: Input/Patch mapping table
412b799e9daSChris B   if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0 &&
413b799e9daSChris B       InputVectorCount > 0) {
414b799e9daSChris B     uint32_t NumDwords =
415b799e9daSChris B         mapTableSize(InputVectorCount, PatchConstOrPrimVectorCount);
416b799e9daSChris B     size_t NumBytes = NumDwords * sizeof(uint32_t);
417b799e9daSChris B     InputPatchMap.Data = Data.substr(Current - Data.begin(), NumBytes);
418b799e9daSChris B     Current += NumBytes;
419b799e9daSChris B   }
420b799e9daSChris B 
421b799e9daSChris B   // Domain Shader: Patch/Output mapping table
422b799e9daSChris B   if (ShaderStage == Triple::Domain && PatchConstOrPrimVectorCount > 0 &&
423b799e9daSChris B       OutputVectorCounts[0] > 0) {
424b799e9daSChris B     uint32_t NumDwords =
425b799e9daSChris B         mapTableSize(PatchConstOrPrimVectorCount, OutputVectorCounts[0]);
426b799e9daSChris B     size_t NumBytes = NumDwords * sizeof(uint32_t);
427b799e9daSChris B     PatchOutputMap.Data = Data.substr(Current - Data.begin(), NumBytes);
428b799e9daSChris B     Current += NumBytes;
429b799e9daSChris B   }
430b799e9daSChris B 
431ad93908eSChris Bieneman   return Error::success();
432ad93908eSChris Bieneman }
4330c3f51c0SChris Bieneman 
getSigInputCount() const4340c3f51c0SChris Bieneman uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const {
435*c62c7463SCooper Partin   if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
436*c62c7463SCooper Partin     return P->SigInputElements;
4370c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
4380c3f51c0SChris Bieneman     return P->SigInputElements;
4390c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
4400c3f51c0SChris Bieneman     return P->SigInputElements;
4410c3f51c0SChris Bieneman   return 0;
4420c3f51c0SChris Bieneman }
4430c3f51c0SChris Bieneman 
getSigOutputCount() const4440c3f51c0SChris Bieneman uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const {
445*c62c7463SCooper Partin   if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
446*c62c7463SCooper Partin     return P->SigOutputElements;
4470c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
4480c3f51c0SChris Bieneman     return P->SigOutputElements;
4490c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
4500c3f51c0SChris Bieneman     return P->SigOutputElements;
4510c3f51c0SChris Bieneman   return 0;
4520c3f51c0SChris Bieneman }
4530c3f51c0SChris Bieneman 
getSigPatchOrPrimCount() const4540c3f51c0SChris Bieneman uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const {
455*c62c7463SCooper Partin   if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
456*c62c7463SCooper Partin     return P->SigPatchOrPrimElements;
4570c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
4580c3f51c0SChris Bieneman     return P->SigPatchOrPrimElements;
4590c3f51c0SChris Bieneman   if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
4600c3f51c0SChris Bieneman     return P->SigPatchOrPrimElements;
4610c3f51c0SChris Bieneman   return 0;
4620c3f51c0SChris Bieneman }
463