236 lines · cpp
1//===- llvm/MC/DXContainerPSVInfo.cpp - DXContainer PSVInfo -----*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/MC/DXContainerPSVInfo.h"10#include "llvm/BinaryFormat/DXContainer.h"11#include "llvm/MC/StringTableBuilder.h"12#include "llvm/Support/EndianStream.h"13#include "llvm/Support/raw_ostream.h"14 15using namespace llvm;16using namespace llvm::mcdxbc;17using namespace llvm::dxbc::PSV;18 19static constexpr size_t npos = StringRef::npos;20 21static size_t FindSequence(ArrayRef<uint32_t> Buffer,22 ArrayRef<uint32_t> Sequence) {23 if (Buffer.size() < Sequence.size())24 return npos;25 for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) {26 if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]),27 static_cast<const void *>(Sequence.begin()),28 Sequence.size() * sizeof(uint32_t)))29 return Idx;30 }31 return npos;32}33 34static void35ProcessElementList(StringTableBuilder &StrTabBuilder,36 SmallVectorImpl<uint32_t> &IndexBuffer,37 SmallVectorImpl<v0::SignatureElement> &FinalElements,38 SmallVectorImpl<StringRef> &SemanticNames,39 ArrayRef<PSVSignatureElement> Elements) {40 for (const auto &El : Elements) {41 // Put the name in the string table and the name list.42 StrTabBuilder.add(El.Name);43 SemanticNames.push_back(El.Name);44 45 v0::SignatureElement FinalElement;46 memset(&FinalElement, 0, sizeof(v0::SignatureElement));47 FinalElement.Rows = static_cast<uint8_t>(El.Indices.size());48 FinalElement.StartRow = El.StartRow;49 FinalElement.Cols = El.Cols;50 FinalElement.StartCol = El.StartCol;51 FinalElement.Allocated = El.Allocated;52 FinalElement.Kind = El.Kind;53 FinalElement.Type = El.Type;54 FinalElement.Mode = El.Mode;55 FinalElement.DynamicMask = El.DynamicMask;56 FinalElement.Stream = El.Stream;57 58 size_t Idx = FindSequence(IndexBuffer, El.Indices);59 if (Idx == npos) {60 FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size());61 llvm::append_range(IndexBuffer, El.Indices);62 } else63 FinalElement.IndicesOffset = static_cast<uint32_t>(Idx);64 FinalElements.push_back(FinalElement);65 }66}67 68void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const {69 assert(IsFinalized && "finalize must be called before write");70 71 uint32_t InfoSize;72 uint32_t BindingSize;73 switch (Version) {74 case 0:75 InfoSize = sizeof(dxbc::PSV::v0::RuntimeInfo);76 BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);77 break;78 case 1:79 InfoSize = sizeof(dxbc::PSV::v1::RuntimeInfo);80 BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);81 break;82 case 2:83 InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo);84 BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);85 break;86 case 3:87 default:88 InfoSize = sizeof(dxbc::PSV::v3::RuntimeInfo);89 BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);90 }91 92 // Write the size of the info.93 support::endian::write(OS, InfoSize, llvm::endianness::little);94 95 // Write the info itself.96 OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize);97 98 uint32_t ResourceCount = static_cast<uint32_t>(Resources.size());99 100 support::endian::write(OS, ResourceCount, llvm::endianness::little);101 if (ResourceCount > 0)102 support::endian::write(OS, BindingSize, llvm::endianness::little);103 104 for (const auto &Res : Resources)105 OS.write(reinterpret_cast<const char *>(&Res), BindingSize);106 107 // PSV Version 0 stops after the resource list.108 if (Version == 0)109 return;110 111 support::endian::write(OS,112 static_cast<uint32_t>(DXConStrTabBuilder.getSize()),113 llvm::endianness::little);114 115 // Write the string table.116 DXConStrTabBuilder.write(OS);117 118 // Write the index table size, then table.119 support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()),120 llvm::endianness::little);121 for (auto I : IndexBuffer)122 support::endian::write(OS, I, llvm::endianness::little);123 124 if (SignatureElements.size() > 0) {125 // write the size of the signature elements.126 support::endian::write(OS,127 static_cast<uint32_t>(sizeof(v0::SignatureElement)),128 llvm::endianness::little);129 130 // write the signature elements.131 OS.write(reinterpret_cast<const char *>(&SignatureElements[0]),132 SignatureElements.size() * sizeof(v0::SignatureElement));133 }134 135 for (const auto &MaskVector : OutputVectorMasks)136 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),137 llvm::endianness::little);138 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks),139 llvm::endianness::little);140 for (const auto &MaskVector : InputOutputMap)141 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),142 llvm::endianness::little);143 support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap),144 llvm::endianness::little);145 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),146 llvm::endianness::little);147}148 149void PSVRuntimeInfo::finalize(Triple::EnvironmentType Stage) {150 IsFinalized = true;151 BaseData.SigInputElements = static_cast<uint32_t>(InputElements.size());152 BaseData.SigOutputElements = static_cast<uint32_t>(OutputElements.size());153 BaseData.SigPatchOrPrimElements =154 static_cast<uint32_t>(PatchOrPrimElements.size());155 156 SmallVector<StringRef, 32> SemanticNames;157 158 // Build a string table and set associated offsets to be written when159 // write() is called160 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,161 SemanticNames, InputElements);162 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,163 SemanticNames, OutputElements);164 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,165 SemanticNames, PatchOrPrimElements);166 167 DXConStrTabBuilder.add(EntryName);168 169 DXConStrTabBuilder.finalize();170 for (auto ElAndName : zip(SignatureElements, SemanticNames)) {171 llvm::dxbc::PSV::v0::SignatureElement &El = std::get<0>(ElAndName);172 StringRef Name = std::get<1>(ElAndName);173 El.NameOffset = static_cast<uint32_t>(DXConStrTabBuilder.getOffset(Name));174 if (sys::IsBigEndianHost)175 El.swapBytes();176 }177 178 BaseData.EntryNameOffset =179 static_cast<uint32_t>(DXConStrTabBuilder.getOffset(EntryName));180 181 if (!sys::IsBigEndianHost)182 return;183 BaseData.swapBytes();184 BaseData.swapBytes(Stage);185 for (auto &Res : Resources)186 Res.swapBytes();187}188 189void Signature::write(raw_ostream &OS) {190 SmallVector<dxbc::ProgramSignatureElement> SigParams;191 SigParams.reserve(Params.size());192 StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));193 194 // Name offsets are from the start of the part. Pre-calculate the offset to195 // the start of the string table so that it can be added to the table offset.196 uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +197 (sizeof(dxbc::ProgramSignatureElement) * Params.size());198 199 for (const auto &P : Params) {200 // zero out the data201 dxbc::ProgramSignatureElement FinalElement;202 memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));203 FinalElement.Stream = P.Stream;204 FinalElement.NameOffset =205 static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;206 FinalElement.Index = P.Index;207 FinalElement.SystemValue = P.SystemValue;208 FinalElement.CompType = P.CompType;209 FinalElement.Register = P.Register;210 FinalElement.Mask = P.Mask;211 FinalElement.ExclusiveMask = P.ExclusiveMask;212 FinalElement.MinPrecision = P.MinPrecision;213 SigParams.push_back(FinalElement);214 }215 216 StrTabBuilder.finalizeInOrder();217 stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,218 const dxbc::ProgramSignatureElement R) {219 return std::tie(L.Stream, L.Register, L.NameOffset) <220 std::tie(R.Stream, R.Register, R.NameOffset);221 });222 if (sys::IsBigEndianHost)223 for (auto &El : SigParams)224 El.swapBytes();225 226 dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),227 sizeof(dxbc::ProgramSignatureHeader)};228 if (sys::IsBigEndianHost)229 Header.swapBytes();230 OS.write(reinterpret_cast<const char *>(&Header),231 sizeof(dxbc::ProgramSignatureHeader));232 OS.write(reinterpret_cast<const char *>(SigParams.data()),233 sizeof(dxbc::ProgramSignatureElement) * SigParams.size());234 StrTabBuilder.write(OS);235}236