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 llvm::append_range(IndexBuffer, El.Indices); 62 } else 63 FinalElement.IndicesOffset = static_cast<uint32_t>(Idx); 64 FinalElements.push_back(FinalElement); 65 } 66 } 67 68 void 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 149 void 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 when 159 // write() is called 160 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 189 void 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 to 195 // 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 data 201 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