106c3fb27SDimitry Andric //===- llvm/MC/DXContainerPSVInfo.cpp - DXContainer PSVInfo -----*- C++ -*-===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "llvm/MC/DXContainerPSVInfo.h" 1006c3fb27SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h" 11*5f757f3fSDimitry Andric #include "llvm/MC/StringTableBuilder.h" 12*5f757f3fSDimitry Andric #include "llvm/Support/EndianStream.h" 1306c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h" 1406c3fb27SDimitry Andric 1506c3fb27SDimitry Andric using namespace llvm; 1606c3fb27SDimitry Andric using namespace llvm::mcdxbc; 1706c3fb27SDimitry Andric using namespace llvm::dxbc::PSV; 1806c3fb27SDimitry Andric 19*5f757f3fSDimitry Andric static constexpr size_t npos = StringRef::npos; 20*5f757f3fSDimitry Andric 21*5f757f3fSDimitry Andric static size_t FindSequence(ArrayRef<uint32_t> Buffer, 22*5f757f3fSDimitry Andric ArrayRef<uint32_t> Sequence) { 23*5f757f3fSDimitry Andric if (Buffer.size() < Sequence.size()) 24*5f757f3fSDimitry Andric return npos; 25*5f757f3fSDimitry Andric for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) { 26*5f757f3fSDimitry Andric if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]), 27*5f757f3fSDimitry Andric static_cast<const void *>(Sequence.begin()), 28*5f757f3fSDimitry Andric Sequence.size() * sizeof(uint32_t))) 29*5f757f3fSDimitry Andric return Idx; 30*5f757f3fSDimitry Andric } 31*5f757f3fSDimitry Andric return npos; 32*5f757f3fSDimitry Andric } 33*5f757f3fSDimitry Andric 34*5f757f3fSDimitry Andric static void 35*5f757f3fSDimitry Andric ProcessElementList(StringTableBuilder &StrTabBuilder, 36*5f757f3fSDimitry Andric SmallVectorImpl<uint32_t> &IndexBuffer, 37*5f757f3fSDimitry Andric SmallVectorImpl<v0::SignatureElement> &FinalElements, 38*5f757f3fSDimitry Andric SmallVectorImpl<StringRef> &SemanticNames, 39*5f757f3fSDimitry Andric ArrayRef<PSVSignatureElement> Elements) { 40*5f757f3fSDimitry Andric for (const auto &El : Elements) { 41*5f757f3fSDimitry Andric // Put the name in the string table and the name list. 42*5f757f3fSDimitry Andric StrTabBuilder.add(El.Name); 43*5f757f3fSDimitry Andric SemanticNames.push_back(El.Name); 44*5f757f3fSDimitry Andric 45*5f757f3fSDimitry Andric v0::SignatureElement FinalElement; 46*5f757f3fSDimitry Andric memset(&FinalElement, 0, sizeof(v0::SignatureElement)); 47*5f757f3fSDimitry Andric FinalElement.Rows = static_cast<uint8_t>(El.Indices.size()); 48*5f757f3fSDimitry Andric FinalElement.StartRow = El.StartRow; 49*5f757f3fSDimitry Andric FinalElement.Cols = El.Cols; 50*5f757f3fSDimitry Andric FinalElement.StartCol = El.StartCol; 51*5f757f3fSDimitry Andric FinalElement.Allocated = El.Allocated; 52*5f757f3fSDimitry Andric FinalElement.Kind = El.Kind; 53*5f757f3fSDimitry Andric FinalElement.Type = El.Type; 54*5f757f3fSDimitry Andric FinalElement.Mode = El.Mode; 55*5f757f3fSDimitry Andric FinalElement.DynamicMask = El.DynamicMask; 56*5f757f3fSDimitry Andric FinalElement.Stream = El.Stream; 57*5f757f3fSDimitry Andric 58*5f757f3fSDimitry Andric size_t Idx = FindSequence(IndexBuffer, El.Indices); 59*5f757f3fSDimitry Andric if (Idx == npos) { 60*5f757f3fSDimitry Andric FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size()); 61*5f757f3fSDimitry Andric IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(), 62*5f757f3fSDimitry Andric El.Indices.end()); 63*5f757f3fSDimitry Andric } else 64*5f757f3fSDimitry Andric FinalElement.IndicesOffset = static_cast<uint32_t>(Idx); 65*5f757f3fSDimitry Andric FinalElements.push_back(FinalElement); 66*5f757f3fSDimitry Andric } 67*5f757f3fSDimitry Andric } 68*5f757f3fSDimitry Andric 6906c3fb27SDimitry Andric void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const { 70*5f757f3fSDimitry Andric assert(IsFinalized && "finalize must be called before write"); 71*5f757f3fSDimitry Andric 7206c3fb27SDimitry Andric uint32_t InfoSize; 7306c3fb27SDimitry Andric uint32_t BindingSize; 7406c3fb27SDimitry Andric switch (Version) { 7506c3fb27SDimitry Andric case 0: 7606c3fb27SDimitry Andric InfoSize = sizeof(dxbc::PSV::v0::RuntimeInfo); 7706c3fb27SDimitry Andric BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo); 7806c3fb27SDimitry Andric break; 7906c3fb27SDimitry Andric case 1: 8006c3fb27SDimitry Andric InfoSize = sizeof(dxbc::PSV::v1::RuntimeInfo); 8106c3fb27SDimitry Andric BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo); 8206c3fb27SDimitry Andric break; 8306c3fb27SDimitry Andric case 2: 8406c3fb27SDimitry Andric default: 8506c3fb27SDimitry Andric InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo); 8606c3fb27SDimitry Andric BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 8706c3fb27SDimitry Andric } 8806c3fb27SDimitry Andric // Write the size of the info. 89*5f757f3fSDimitry Andric 90*5f757f3fSDimitry Andric support::endian::write(OS, InfoSize, llvm::endianness::little); 9106c3fb27SDimitry Andric // Write the info itself. 9206c3fb27SDimitry Andric OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize); 9306c3fb27SDimitry Andric 9406c3fb27SDimitry Andric uint32_t ResourceCount = static_cast<uint32_t>(Resources.size()); 9506c3fb27SDimitry Andric 96*5f757f3fSDimitry Andric support::endian::write(OS, ResourceCount, llvm::endianness::little); 97*5f757f3fSDimitry Andric if (ResourceCount > 0) 98*5f757f3fSDimitry Andric support::endian::write(OS, BindingSize, llvm::endianness::little); 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric for (const auto &Res : Resources) 10106c3fb27SDimitry Andric OS.write(reinterpret_cast<const char *>(&Res), BindingSize); 102*5f757f3fSDimitry Andric 103*5f757f3fSDimitry Andric // PSV Version 0 stops after the resource list. 104*5f757f3fSDimitry Andric if (Version == 0) 105*5f757f3fSDimitry Andric return; 106*5f757f3fSDimitry Andric 107*5f757f3fSDimitry Andric StringTableBuilder StrTabBuilder((StringTableBuilder::DXContainer)); 108*5f757f3fSDimitry Andric SmallVector<uint32_t, 64> IndexBuffer; 109*5f757f3fSDimitry Andric SmallVector<v0::SignatureElement, 32> SignatureElements; 110*5f757f3fSDimitry Andric SmallVector<StringRef, 32> SemanticNames; 111*5f757f3fSDimitry Andric 112*5f757f3fSDimitry Andric ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 113*5f757f3fSDimitry Andric SemanticNames, InputElements); 114*5f757f3fSDimitry Andric ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 115*5f757f3fSDimitry Andric SemanticNames, OutputElements); 116*5f757f3fSDimitry Andric ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 117*5f757f3fSDimitry Andric SemanticNames, PatchOrPrimElements); 118*5f757f3fSDimitry Andric 119*5f757f3fSDimitry Andric StrTabBuilder.finalize(); 120*5f757f3fSDimitry Andric for (auto ElAndName : zip(SignatureElements, SemanticNames)) { 121*5f757f3fSDimitry Andric v0::SignatureElement &El = std::get<0>(ElAndName); 122*5f757f3fSDimitry Andric StringRef Name = std::get<1>(ElAndName); 123*5f757f3fSDimitry Andric El.NameOffset = static_cast<uint32_t>(StrTabBuilder.getOffset(Name)); 124*5f757f3fSDimitry Andric if (sys::IsBigEndianHost) 125*5f757f3fSDimitry Andric El.swapBytes(); 126*5f757f3fSDimitry Andric } 127*5f757f3fSDimitry Andric 128*5f757f3fSDimitry Andric support::endian::write(OS, static_cast<uint32_t>(StrTabBuilder.getSize()), 129*5f757f3fSDimitry Andric llvm::endianness::little); 130*5f757f3fSDimitry Andric 131*5f757f3fSDimitry Andric // Write the string table. 132*5f757f3fSDimitry Andric StrTabBuilder.write(OS); 133*5f757f3fSDimitry Andric 134*5f757f3fSDimitry Andric // Write the index table size, then table. 135*5f757f3fSDimitry Andric support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()), 136*5f757f3fSDimitry Andric llvm::endianness::little); 137*5f757f3fSDimitry Andric for (auto I : IndexBuffer) 138*5f757f3fSDimitry Andric support::endian::write(OS, I, llvm::endianness::little); 139*5f757f3fSDimitry Andric 140*5f757f3fSDimitry Andric if (SignatureElements.size() > 0) { 141*5f757f3fSDimitry Andric // write the size of the signature elements. 142*5f757f3fSDimitry Andric support::endian::write(OS, 143*5f757f3fSDimitry Andric static_cast<uint32_t>(sizeof(v0::SignatureElement)), 144*5f757f3fSDimitry Andric llvm::endianness::little); 145*5f757f3fSDimitry Andric 146*5f757f3fSDimitry Andric // write the signature elements. 147*5f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(&SignatureElements[0]), 148*5f757f3fSDimitry Andric SignatureElements.size() * sizeof(v0::SignatureElement)); 149*5f757f3fSDimitry Andric } 150*5f757f3fSDimitry Andric 151*5f757f3fSDimitry Andric for (const auto &MaskVector : OutputVectorMasks) 152*5f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 153*5f757f3fSDimitry Andric llvm::endianness::little); 154*5f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks), 155*5f757f3fSDimitry Andric llvm::endianness::little); 156*5f757f3fSDimitry Andric for (const auto &MaskVector : InputOutputMap) 157*5f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 158*5f757f3fSDimitry Andric llvm::endianness::little); 159*5f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap), 160*5f757f3fSDimitry Andric llvm::endianness::little); 161*5f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap), 162*5f757f3fSDimitry Andric llvm::endianness::little); 163*5f757f3fSDimitry Andric } 164*5f757f3fSDimitry Andric 165*5f757f3fSDimitry Andric void Signature::write(raw_ostream &OS) { 166*5f757f3fSDimitry Andric SmallVector<dxbc::ProgramSignatureElement> SigParams; 167*5f757f3fSDimitry Andric SigParams.reserve(Params.size()); 168*5f757f3fSDimitry Andric StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF)); 169*5f757f3fSDimitry Andric 170*5f757f3fSDimitry Andric // Name offsets are from the start of the part. Pre-calculate the offset to 171*5f757f3fSDimitry Andric // the start of the string table so that it can be added to the table offset. 172*5f757f3fSDimitry Andric uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) + 173*5f757f3fSDimitry Andric (sizeof(dxbc::ProgramSignatureElement) * Params.size()); 174*5f757f3fSDimitry Andric 175*5f757f3fSDimitry Andric for (const auto &P : Params) { 176*5f757f3fSDimitry Andric // zero out the data 177*5f757f3fSDimitry Andric dxbc::ProgramSignatureElement FinalElement; 178*5f757f3fSDimitry Andric memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement)); 179*5f757f3fSDimitry Andric FinalElement.Stream = P.Stream; 180*5f757f3fSDimitry Andric FinalElement.NameOffset = 181*5f757f3fSDimitry Andric static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart; 182*5f757f3fSDimitry Andric FinalElement.Index = P.Index; 183*5f757f3fSDimitry Andric FinalElement.SystemValue = P.SystemValue; 184*5f757f3fSDimitry Andric FinalElement.CompType = P.CompType; 185*5f757f3fSDimitry Andric FinalElement.Register = P.Register; 186*5f757f3fSDimitry Andric FinalElement.Mask = P.Mask; 187*5f757f3fSDimitry Andric FinalElement.ExclusiveMask = P.ExclusiveMask; 188*5f757f3fSDimitry Andric FinalElement.MinPrecision = P.MinPrecision; 189*5f757f3fSDimitry Andric SigParams.push_back(FinalElement); 190*5f757f3fSDimitry Andric } 191*5f757f3fSDimitry Andric 192*5f757f3fSDimitry Andric StrTabBuilder.finalizeInOrder(); 193*5f757f3fSDimitry Andric stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L, 194*5f757f3fSDimitry Andric const dxbc::ProgramSignatureElement R) { 195*5f757f3fSDimitry Andric return std::tie(L.Stream, L.Register, L.NameOffset) < 196*5f757f3fSDimitry Andric std::tie(R.Stream, R.Register, R.NameOffset); 197*5f757f3fSDimitry Andric }); 198*5f757f3fSDimitry Andric if (sys::IsBigEndianHost) 199*5f757f3fSDimitry Andric for (auto &El : SigParams) 200*5f757f3fSDimitry Andric El.swapBytes(); 201*5f757f3fSDimitry Andric 202*5f757f3fSDimitry Andric dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()), 203*5f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureHeader)}; 204*5f757f3fSDimitry Andric if (sys::IsBigEndianHost) 205*5f757f3fSDimitry Andric Header.swapBytes(); 206*5f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(&Header), 207*5f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureHeader)); 208*5f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(SigParams.data()), 209*5f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureElement) * SigParams.size()); 210*5f757f3fSDimitry Andric StrTabBuilder.write(OS); 21106c3fb27SDimitry Andric } 212