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 InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo); 85 BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 86 break; 87 case 3: 88 default: 89 InfoSize = sizeof(dxbc::PSV::v3::RuntimeInfo); 90 BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo); 91 } 92 93 // Write the size of the info. 94 support::endian::write(OS, InfoSize, llvm::endianness::little); 95 96 // Write the info itself. 97 OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize); 98 99 uint32_t ResourceCount = static_cast<uint32_t>(Resources.size()); 100 101 support::endian::write(OS, ResourceCount, llvm::endianness::little); 102 if (ResourceCount > 0) 103 support::endian::write(OS, BindingSize, llvm::endianness::little); 104 105 for (const auto &Res : Resources) 106 OS.write(reinterpret_cast<const char *>(&Res), BindingSize); 107 108 // PSV Version 0 stops after the resource list. 109 if (Version == 0) 110 return; 111 112 support::endian::write(OS, 113 static_cast<uint32_t>(DXConStrTabBuilder.getSize()), 114 llvm::endianness::little); 115 116 // Write the string table. 117 DXConStrTabBuilder.write(OS); 118 119 // Write the index table size, then table. 120 support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()), 121 llvm::endianness::little); 122 for (auto I : IndexBuffer) 123 support::endian::write(OS, I, llvm::endianness::little); 124 125 if (SignatureElements.size() > 0) { 126 // write the size of the signature elements. 127 support::endian::write(OS, 128 static_cast<uint32_t>(sizeof(v0::SignatureElement)), 129 llvm::endianness::little); 130 131 // write the signature elements. 132 OS.write(reinterpret_cast<const char *>(&SignatureElements[0]), 133 SignatureElements.size() * sizeof(v0::SignatureElement)); 134 } 135 136 for (const auto &MaskVector : OutputVectorMasks) 137 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 138 llvm::endianness::little); 139 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks), 140 llvm::endianness::little); 141 for (const auto &MaskVector : InputOutputMap) 142 support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector), 143 llvm::endianness::little); 144 support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap), 145 llvm::endianness::little); 146 support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap), 147 llvm::endianness::little); 148 } 149 150 void PSVRuntimeInfo::finalize(Triple::EnvironmentType Stage) { 151 IsFinalized = true; 152 BaseData.SigInputElements = static_cast<uint32_t>(InputElements.size()); 153 BaseData.SigOutputElements = static_cast<uint32_t>(OutputElements.size()); 154 BaseData.SigPatchOrPrimElements = 155 static_cast<uint32_t>(PatchOrPrimElements.size()); 156 157 SmallVector<StringRef, 32> SemanticNames; 158 159 // Build a string table and set associated offsets to be written when 160 // write() is called 161 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 162 SemanticNames, InputElements); 163 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 164 SemanticNames, OutputElements); 165 ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements, 166 SemanticNames, PatchOrPrimElements); 167 168 DXConStrTabBuilder.add(EntryName); 169 170 DXConStrTabBuilder.finalize(); 171 for (auto ElAndName : zip(SignatureElements, SemanticNames)) { 172 llvm::dxbc::PSV::v0::SignatureElement &El = std::get<0>(ElAndName); 173 StringRef Name = std::get<1>(ElAndName); 174 El.NameOffset = static_cast<uint32_t>(DXConStrTabBuilder.getOffset(Name)); 175 if (sys::IsBigEndianHost) 176 El.swapBytes(); 177 } 178 179 BaseData.EntryNameOffset = 180 static_cast<uint32_t>(DXConStrTabBuilder.getOffset(EntryName)); 181 182 if (!sys::IsBigEndianHost) 183 return; 184 BaseData.swapBytes(); 185 BaseData.swapBytes(Stage); 186 for (auto &Res : Resources) 187 Res.swapBytes(); 188 } 189 190 void Signature::write(raw_ostream &OS) { 191 SmallVector<dxbc::ProgramSignatureElement> SigParams; 192 SigParams.reserve(Params.size()); 193 StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF)); 194 195 // Name offsets are from the start of the part. Pre-calculate the offset to 196 // the start of the string table so that it can be added to the table offset. 197 uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) + 198 (sizeof(dxbc::ProgramSignatureElement) * Params.size()); 199 200 for (const auto &P : Params) { 201 // zero out the data 202 dxbc::ProgramSignatureElement FinalElement; 203 memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement)); 204 FinalElement.Stream = P.Stream; 205 FinalElement.NameOffset = 206 static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart; 207 FinalElement.Index = P.Index; 208 FinalElement.SystemValue = P.SystemValue; 209 FinalElement.CompType = P.CompType; 210 FinalElement.Register = P.Register; 211 FinalElement.Mask = P.Mask; 212 FinalElement.ExclusiveMask = P.ExclusiveMask; 213 FinalElement.MinPrecision = P.MinPrecision; 214 SigParams.push_back(FinalElement); 215 } 216 217 StrTabBuilder.finalizeInOrder(); 218 stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L, 219 const dxbc::ProgramSignatureElement R) { 220 return std::tie(L.Stream, L.Register, L.NameOffset) < 221 std::tie(R.Stream, R.Register, R.NameOffset); 222 }); 223 if (sys::IsBigEndianHost) 224 for (auto &El : SigParams) 225 El.swapBytes(); 226 227 dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()), 228 sizeof(dxbc::ProgramSignatureHeader)}; 229 if (sys::IsBigEndianHost) 230 Header.swapBytes(); 231 OS.write(reinterpret_cast<const char *>(&Header), 232 sizeof(dxbc::ProgramSignatureHeader)); 233 OS.write(reinterpret_cast<const char *>(SigParams.data()), 234 sizeof(dxbc::ProgramSignatureElement) * SigParams.size()); 235 StrTabBuilder.write(OS); 236 } 237