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-exception 6 // 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 15 using namespace llvm; 16 using namespace llvm::mcdxbc; 17 using namespace llvm::dxbc::PSV; 18 19 static constexpr size_t npos = StringRef::npos; 20 21 static 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 34 static void 35 ProcessElementList(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 IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(), 62 El.Indices.end()); 63 } else 64 FinalElement.IndicesOffset = static_cast<uint32_t>(Idx); 65 FinalElements.push_back(FinalElement); 66 } 67 } 68 69 void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const { 70 assert(IsFinalized && "finalize must be called before write"); 71 72 uint32_t InfoSize; 73 uint32_t BindingSize; 74 switch (Version) { 75 case 0: 76 InfoSize = sizeof(dxbc::PSV::v0::RuntimeInfo); 77 BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo); 78 break; 79 case 1: 80 InfoSize = sizeof(dxbc::PSV::v1::RuntimeInfo); 81 BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo); 82 break; 83 case 2: 84 default: 85 InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo); 86 BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 87 } 88 // Write the size of the info. 89 90 support::endian::write(OS, InfoSize, llvm::endianness::little); 91 // Write the info itself. 92 OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize); 93 94 uint32_t ResourceCount = static_cast<uint32_t>(Resources.size()); 95 96 support::endian::write(OS, ResourceCount, llvm::endianness::little); 97 if (ResourceCount > 0) 98 support::endian::write(OS, BindingSize, llvm::endianness::little); 99 100 for (const auto &Res : Resources) 101 OS.write(reinterpret_cast<const char *>(&Res), BindingSize); 102 103 // PSV Version 0 stops after the resource list. 104 if (Version == 0) 105 return; 106 107 StringTableBuilder StrTabBuilder((StringTableBuilder::DXContainer)); 108 SmallVector<uint32_t, 64> IndexBuffer; 109 SmallVector<v0::SignatureElement, 32> SignatureElements; 110 SmallVector<StringRef, 32> SemanticNames; 111 112 ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 113 SemanticNames, InputElements); 114 ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 115 SemanticNames, OutputElements); 116 ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements, 117 SemanticNames, PatchOrPrimElements); 118 119 StrTabBuilder.finalize(); 120 for (auto ElAndName : zip(SignatureElements, SemanticNames)) { 121 v0::SignatureElement &El = std::get<0>(ElAndName); 122 StringRef Name = std::get<1>(ElAndName); 123 El.NameOffset = static_cast<uint32_t>(StrTabBuilder.getOffset(Name)); 124 if (sys::IsBigEndianHost) 125 El.swapBytes(); 126 } 127 128 support::endian::write(OS, static_cast<uint32_t>(StrTabBuilder.getSize()), 129 llvm::endianness::little); 130 131 // Write the string table. 132 StrTabBuilder.write(OS); 133 134 // Write the index table size, then table. 135 support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()), 136 llvm::endianness::little); 137 for (auto I : IndexBuffer) 138 support::endian::write(OS, I, llvm::endianness::little); 139 140 if (SignatureElements.size() > 0) { 141 // write the size of the signature elements. 142 support::endian::write(OS, 143 static_cast<uint32_t>(sizeof(v0::SignatureElement)), 144 llvm::endianness::little); 145 146 // write the signature elements. 147 OS.write(reinterpret_cast<const char *>(&SignatureElements[0]), 148 SignatureElements.size() * sizeof(v0::SignatureElement)); 149 } 150 151 for (const auto &MaskVector : OutputVectorMasks) 152 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 153 llvm::endianness::little); 154 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks), 155 llvm::endianness::little); 156 for (const auto &MaskVector : InputOutputMap) 157 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 158 llvm::endianness::little); 159 support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap), 160 llvm::endianness::little); 161 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap), 162 llvm::endianness::little); 163 } 164 165 void Signature::write(raw_ostream &OS) { 166 SmallVector<dxbc::ProgramSignatureElement> SigParams; 167 SigParams.reserve(Params.size()); 168 StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF)); 169 170 // Name offsets are from the start of the part. Pre-calculate the offset to 171 // the start of the string table so that it can be added to the table offset. 172 uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) + 173 (sizeof(dxbc::ProgramSignatureElement) * Params.size()); 174 175 for (const auto &P : Params) { 176 // zero out the data 177 dxbc::ProgramSignatureElement FinalElement; 178 memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement)); 179 FinalElement.Stream = P.Stream; 180 FinalElement.NameOffset = 181 static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart; 182 FinalElement.Index = P.Index; 183 FinalElement.SystemValue = P.SystemValue; 184 FinalElement.CompType = P.CompType; 185 FinalElement.Register = P.Register; 186 FinalElement.Mask = P.Mask; 187 FinalElement.ExclusiveMask = P.ExclusiveMask; 188 FinalElement.MinPrecision = P.MinPrecision; 189 SigParams.push_back(FinalElement); 190 } 191 192 StrTabBuilder.finalizeInOrder(); 193 stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L, 194 const dxbc::ProgramSignatureElement R) { 195 return std::tie(L.Stream, L.Register, L.NameOffset) < 196 std::tie(R.Stream, R.Register, R.NameOffset); 197 }); 198 if (sys::IsBigEndianHost) 199 for (auto &El : SigParams) 200 El.swapBytes(); 201 202 dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()), 203 sizeof(dxbc::ProgramSignatureHeader)}; 204 if (sys::IsBigEndianHost) 205 Header.swapBytes(); 206 OS.write(reinterpret_cast<const char *>(&Header), 207 sizeof(dxbc::ProgramSignatureHeader)); 208 OS.write(reinterpret_cast<const char *>(SigParams.data()), 209 sizeof(dxbc::ProgramSignatureElement) * SigParams.size()); 210 StrTabBuilder.write(OS); 211 } 212