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" 115f757f3fSDimitry Andric #include "llvm/MC/StringTableBuilder.h" 125f757f3fSDimitry 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 195f757f3fSDimitry Andric static constexpr size_t npos = StringRef::npos; 205f757f3fSDimitry Andric 215f757f3fSDimitry Andric static size_t FindSequence(ArrayRef<uint32_t> Buffer, 225f757f3fSDimitry Andric ArrayRef<uint32_t> Sequence) { 235f757f3fSDimitry Andric if (Buffer.size() < Sequence.size()) 245f757f3fSDimitry Andric return npos; 255f757f3fSDimitry Andric for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) { 265f757f3fSDimitry Andric if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]), 275f757f3fSDimitry Andric static_cast<const void *>(Sequence.begin()), 285f757f3fSDimitry Andric Sequence.size() * sizeof(uint32_t))) 295f757f3fSDimitry Andric return Idx; 305f757f3fSDimitry Andric } 315f757f3fSDimitry Andric return npos; 325f757f3fSDimitry Andric } 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric static void 355f757f3fSDimitry Andric ProcessElementList(StringTableBuilder &StrTabBuilder, 365f757f3fSDimitry Andric SmallVectorImpl<uint32_t> &IndexBuffer, 375f757f3fSDimitry Andric SmallVectorImpl<v0::SignatureElement> &FinalElements, 385f757f3fSDimitry Andric SmallVectorImpl<StringRef> &SemanticNames, 395f757f3fSDimitry Andric ArrayRef<PSVSignatureElement> Elements) { 405f757f3fSDimitry Andric for (const auto &El : Elements) { 415f757f3fSDimitry Andric // Put the name in the string table and the name list. 425f757f3fSDimitry Andric StrTabBuilder.add(El.Name); 435f757f3fSDimitry Andric SemanticNames.push_back(El.Name); 445f757f3fSDimitry Andric 455f757f3fSDimitry Andric v0::SignatureElement FinalElement; 465f757f3fSDimitry Andric memset(&FinalElement, 0, sizeof(v0::SignatureElement)); 475f757f3fSDimitry Andric FinalElement.Rows = static_cast<uint8_t>(El.Indices.size()); 485f757f3fSDimitry Andric FinalElement.StartRow = El.StartRow; 495f757f3fSDimitry Andric FinalElement.Cols = El.Cols; 505f757f3fSDimitry Andric FinalElement.StartCol = El.StartCol; 515f757f3fSDimitry Andric FinalElement.Allocated = El.Allocated; 525f757f3fSDimitry Andric FinalElement.Kind = El.Kind; 535f757f3fSDimitry Andric FinalElement.Type = El.Type; 545f757f3fSDimitry Andric FinalElement.Mode = El.Mode; 555f757f3fSDimitry Andric FinalElement.DynamicMask = El.DynamicMask; 565f757f3fSDimitry Andric FinalElement.Stream = El.Stream; 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric size_t Idx = FindSequence(IndexBuffer, El.Indices); 595f757f3fSDimitry Andric if (Idx == npos) { 605f757f3fSDimitry Andric FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size()); 615f757f3fSDimitry Andric IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(), 625f757f3fSDimitry Andric El.Indices.end()); 635f757f3fSDimitry Andric } else 645f757f3fSDimitry Andric FinalElement.IndicesOffset = static_cast<uint32_t>(Idx); 655f757f3fSDimitry Andric FinalElements.push_back(FinalElement); 665f757f3fSDimitry Andric } 675f757f3fSDimitry Andric } 685f757f3fSDimitry Andric 6906c3fb27SDimitry Andric void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const { 705f757f3fSDimitry Andric assert(IsFinalized && "finalize must be called before write"); 715f757f3fSDimitry 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 InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo); 8506c3fb27SDimitry Andric BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 86*0fca6ea1SDimitry Andric break; 87*0fca6ea1SDimitry Andric case 3: 88*0fca6ea1SDimitry Andric default: 89*0fca6ea1SDimitry Andric InfoSize = sizeof(dxbc::PSV::v3::RuntimeInfo); 90*0fca6ea1SDimitry Andric BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 9106c3fb27SDimitry Andric } 925f757f3fSDimitry Andric 93*0fca6ea1SDimitry Andric // Write the size of the info. 945f757f3fSDimitry Andric support::endian::write(OS, InfoSize, llvm::endianness::little); 95*0fca6ea1SDimitry Andric 9606c3fb27SDimitry Andric // Write the info itself. 9706c3fb27SDimitry Andric OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize); 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric uint32_t ResourceCount = static_cast<uint32_t>(Resources.size()); 10006c3fb27SDimitry Andric 1015f757f3fSDimitry Andric support::endian::write(OS, ResourceCount, llvm::endianness::little); 1025f757f3fSDimitry Andric if (ResourceCount > 0) 1035f757f3fSDimitry Andric support::endian::write(OS, BindingSize, llvm::endianness::little); 10406c3fb27SDimitry Andric 10506c3fb27SDimitry Andric for (const auto &Res : Resources) 10606c3fb27SDimitry Andric OS.write(reinterpret_cast<const char *>(&Res), BindingSize); 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric // PSV Version 0 stops after the resource list. 1095f757f3fSDimitry Andric if (Version == 0) 1105f757f3fSDimitry Andric return; 1115f757f3fSDimitry Andric 112*0fca6ea1SDimitry Andric support::endian::write(OS, 113*0fca6ea1SDimitry Andric static_cast<uint32_t>(DXConStrTabBuilder.getSize()), 1145f757f3fSDimitry Andric llvm::endianness::little); 1155f757f3fSDimitry Andric 1165f757f3fSDimitry Andric // Write the string table. 117*0fca6ea1SDimitry Andric DXConStrTabBuilder.write(OS); 1185f757f3fSDimitry Andric 1195f757f3fSDimitry Andric // Write the index table size, then table. 1205f757f3fSDimitry Andric support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()), 1215f757f3fSDimitry Andric llvm::endianness::little); 1225f757f3fSDimitry Andric for (auto I : IndexBuffer) 1235f757f3fSDimitry Andric support::endian::write(OS, I, llvm::endianness::little); 1245f757f3fSDimitry Andric 1255f757f3fSDimitry Andric if (SignatureElements.size() > 0) { 1265f757f3fSDimitry Andric // write the size of the signature elements. 1275f757f3fSDimitry Andric support::endian::write(OS, 1285f757f3fSDimitry Andric static_cast<uint32_t>(sizeof(v0::SignatureElement)), 1295f757f3fSDimitry Andric llvm::endianness::little); 1305f757f3fSDimitry Andric 1315f757f3fSDimitry Andric // write the signature elements. 1325f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(&SignatureElements[0]), 1335f757f3fSDimitry Andric SignatureElements.size() * sizeof(v0::SignatureElement)); 1345f757f3fSDimitry Andric } 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric for (const auto &MaskVector : OutputVectorMasks) 1375f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 1385f757f3fSDimitry Andric llvm::endianness::little); 1395f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks), 1405f757f3fSDimitry Andric llvm::endianness::little); 1415f757f3fSDimitry Andric for (const auto &MaskVector : InputOutputMap) 1425f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 1435f757f3fSDimitry Andric llvm::endianness::little); 1445f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap), 1455f757f3fSDimitry Andric llvm::endianness::little); 1465f757f3fSDimitry Andric support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap), 1475f757f3fSDimitry Andric llvm::endianness::little); 1485f757f3fSDimitry Andric } 1495f757f3fSDimitry Andric 150*0fca6ea1SDimitry Andric void PSVRuntimeInfo::finalize(Triple::EnvironmentType Stage) { 151*0fca6ea1SDimitry Andric IsFinalized = true; 152*0fca6ea1SDimitry Andric BaseData.SigInputElements = static_cast<uint32_t>(InputElements.size()); 153*0fca6ea1SDimitry Andric BaseData.SigOutputElements = static_cast<uint32_t>(OutputElements.size()); 154*0fca6ea1SDimitry Andric BaseData.SigPatchOrPrimElements = 155*0fca6ea1SDimitry Andric static_cast<uint32_t>(PatchOrPrimElements.size()); 156*0fca6ea1SDimitry Andric 157*0fca6ea1SDimitry Andric SmallVector<StringRef, 32> SemanticNames; 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric // Build a string table and set associated offsets to be written when 160*0fca6ea1SDimitry Andric // write() is called 161*0fca6ea1SDimitry Andric ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 162*0fca6ea1SDimitry Andric SemanticNames, InputElements); 163*0fca6ea1SDimitry Andric ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 164*0fca6ea1SDimitry Andric SemanticNames, OutputElements); 165*0fca6ea1SDimitry Andric ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 166*0fca6ea1SDimitry Andric SemanticNames, PatchOrPrimElements); 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric DXConStrTabBuilder.add(EntryName); 169*0fca6ea1SDimitry Andric 170*0fca6ea1SDimitry Andric DXConStrTabBuilder.finalize(); 171*0fca6ea1SDimitry Andric for (auto ElAndName : zip(SignatureElements, SemanticNames)) { 172*0fca6ea1SDimitry Andric llvm::dxbc::PSV::v0::SignatureElement &El = std::get<0>(ElAndName); 173*0fca6ea1SDimitry Andric StringRef Name = std::get<1>(ElAndName); 174*0fca6ea1SDimitry Andric El.NameOffset = static_cast<uint32_t>(DXConStrTabBuilder.getOffset(Name)); 175*0fca6ea1SDimitry Andric if (sys::IsBigEndianHost) 176*0fca6ea1SDimitry Andric El.swapBytes(); 177*0fca6ea1SDimitry Andric } 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric BaseData.EntryNameOffset = 180*0fca6ea1SDimitry Andric static_cast<uint32_t>(DXConStrTabBuilder.getOffset(EntryName)); 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric if (!sys::IsBigEndianHost) 183*0fca6ea1SDimitry Andric return; 184*0fca6ea1SDimitry Andric BaseData.swapBytes(); 185*0fca6ea1SDimitry Andric BaseData.swapBytes(Stage); 186*0fca6ea1SDimitry Andric for (auto &Res : Resources) 187*0fca6ea1SDimitry Andric Res.swapBytes(); 188*0fca6ea1SDimitry Andric } 189*0fca6ea1SDimitry Andric 1905f757f3fSDimitry Andric void Signature::write(raw_ostream &OS) { 1915f757f3fSDimitry Andric SmallVector<dxbc::ProgramSignatureElement> SigParams; 1925f757f3fSDimitry Andric SigParams.reserve(Params.size()); 1935f757f3fSDimitry Andric StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF)); 1945f757f3fSDimitry Andric 1955f757f3fSDimitry Andric // Name offsets are from the start of the part. Pre-calculate the offset to 1965f757f3fSDimitry Andric // the start of the string table so that it can be added to the table offset. 1975f757f3fSDimitry Andric uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) + 1985f757f3fSDimitry Andric (sizeof(dxbc::ProgramSignatureElement) * Params.size()); 1995f757f3fSDimitry Andric 2005f757f3fSDimitry Andric for (const auto &P : Params) { 2015f757f3fSDimitry Andric // zero out the data 2025f757f3fSDimitry Andric dxbc::ProgramSignatureElement FinalElement; 2035f757f3fSDimitry Andric memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement)); 2045f757f3fSDimitry Andric FinalElement.Stream = P.Stream; 2055f757f3fSDimitry Andric FinalElement.NameOffset = 2065f757f3fSDimitry Andric static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart; 2075f757f3fSDimitry Andric FinalElement.Index = P.Index; 2085f757f3fSDimitry Andric FinalElement.SystemValue = P.SystemValue; 2095f757f3fSDimitry Andric FinalElement.CompType = P.CompType; 2105f757f3fSDimitry Andric FinalElement.Register = P.Register; 2115f757f3fSDimitry Andric FinalElement.Mask = P.Mask; 2125f757f3fSDimitry Andric FinalElement.ExclusiveMask = P.ExclusiveMask; 2135f757f3fSDimitry Andric FinalElement.MinPrecision = P.MinPrecision; 2145f757f3fSDimitry Andric SigParams.push_back(FinalElement); 2155f757f3fSDimitry Andric } 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric StrTabBuilder.finalizeInOrder(); 2185f757f3fSDimitry Andric stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L, 2195f757f3fSDimitry Andric const dxbc::ProgramSignatureElement R) { 2205f757f3fSDimitry Andric return std::tie(L.Stream, L.Register, L.NameOffset) < 2215f757f3fSDimitry Andric std::tie(R.Stream, R.Register, R.NameOffset); 2225f757f3fSDimitry Andric }); 2235f757f3fSDimitry Andric if (sys::IsBigEndianHost) 2245f757f3fSDimitry Andric for (auto &El : SigParams) 2255f757f3fSDimitry Andric El.swapBytes(); 2265f757f3fSDimitry Andric 2275f757f3fSDimitry Andric dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()), 2285f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureHeader)}; 2295f757f3fSDimitry Andric if (sys::IsBigEndianHost) 2305f757f3fSDimitry Andric Header.swapBytes(); 2315f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(&Header), 2325f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureHeader)); 2335f757f3fSDimitry Andric OS.write(reinterpret_cast<const char *>(SigParams.data()), 2345f757f3fSDimitry Andric sizeof(dxbc::ProgramSignatureElement) * SigParams.size()); 2355f757f3fSDimitry Andric StrTabBuilder.write(OS); 23606c3fb27SDimitry Andric } 237