| 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(s1: static_cast<const void *>(&Buffer[Idx]), |
| 27 | s2: static_cast<const void *>(Sequence.begin()), |
| 28 | n: 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(S: El.Name); |
| 43 | SemanticNames.push_back(Elt: El.Name); |
| 44 | |
| 45 | v0::SignatureElement FinalElement; |
| 46 | memset(s: &FinalElement, c: 0, n: 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(Buffer: IndexBuffer, Sequence: El.Indices); |
| 59 | if (Idx == npos) { |
| 60 | FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size()); |
| 61 | llvm::append_range(C&: IndexBuffer, R: El.Indices); |
| 62 | } else |
| 63 | FinalElement.IndicesOffset = static_cast<uint32_t>(Idx); |
| 64 | FinalElements.push_back(Elt: 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&: OS, value: InfoSize, endian: llvm::endianness::little); |
| 94 | |
| 95 | // Write the info itself. |
| 96 | OS.write(Ptr: reinterpret_cast<const char *>(&BaseData), Size: InfoSize); |
| 97 | |
| 98 | uint32_t ResourceCount = static_cast<uint32_t>(Resources.size()); |
| 99 | |
| 100 | support::endian::write(os&: OS, value: ResourceCount, endian: llvm::endianness::little); |
| 101 | if (ResourceCount > 0) |
| 102 | support::endian::write(os&: OS, value: BindingSize, endian: llvm::endianness::little); |
| 103 | |
| 104 | for (const auto &Res : Resources) |
| 105 | OS.write(Ptr: reinterpret_cast<const char *>(&Res), Size: BindingSize); |
| 106 | |
| 107 | // PSV Version 0 stops after the resource list. |
| 108 | if (Version == 0) |
| 109 | return; |
| 110 | |
| 111 | support::endian::write(os&: OS, |
| 112 | value: static_cast<uint32_t>(DXConStrTabBuilder.getSize()), |
| 113 | endian: 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&: OS, value: static_cast<uint32_t>(IndexBuffer.size()), |
| 120 | endian: llvm::endianness::little); |
| 121 | for (auto I : IndexBuffer) |
| 122 | support::endian::write(os&: OS, value: I, endian: llvm::endianness::little); |
| 123 | |
| 124 | if (SignatureElements.size() > 0) { |
| 125 | // write the size of the signature elements. |
| 126 | support::endian::write(os&: OS, |
| 127 | value: static_cast<uint32_t>(sizeof(v0::SignatureElement)), |
| 128 | endian: llvm::endianness::little); |
| 129 | |
| 130 | // write the signature elements. |
| 131 | OS.write(Ptr: reinterpret_cast<const char *>(&SignatureElements[0]), |
| 132 | Size: SignatureElements.size() * sizeof(v0::SignatureElement)); |
| 133 | } |
| 134 | |
| 135 | for (const auto &MaskVector : OutputVectorMasks) |
| 136 | support::endian::write_array(os&: OS, values: ArrayRef<uint32_t>(MaskVector), |
| 137 | endian: llvm::endianness::little); |
| 138 | support::endian::write_array(os&: OS, values: ArrayRef<uint32_t>(PatchOrPrimMasks), |
| 139 | endian: llvm::endianness::little); |
| 140 | for (const auto &MaskVector : InputOutputMap) |
| 141 | support::endian::write_array(os&: OS, values: ArrayRef<uint32_t>(MaskVector), |
| 142 | endian: llvm::endianness::little); |
| 143 | support::endian::write_array(os&: OS, values: ArrayRef<uint32_t>(InputPatchMap), |
| 144 | endian: llvm::endianness::little); |
| 145 | support::endian::write_array(os&: OS, values: ArrayRef<uint32_t>(PatchOutputMap), |
| 146 | endian: 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(StrTabBuilder&: DXConStrTabBuilder, IndexBuffer, FinalElements&: SignatureElements, |
| 161 | SemanticNames, Elements: InputElements); |
| 162 | ProcessElementList(StrTabBuilder&: DXConStrTabBuilder, IndexBuffer, FinalElements&: SignatureElements, |
| 163 | SemanticNames, Elements: OutputElements); |
| 164 | ProcessElementList(StrTabBuilder&: DXConStrTabBuilder, IndexBuffer, FinalElements&: SignatureElements, |
| 165 | SemanticNames, Elements: PatchOrPrimElements); |
| 166 | |
| 167 | DXConStrTabBuilder.add(S: EntryName); |
| 168 | |
| 169 | DXConStrTabBuilder.finalize(); |
| 170 | for (auto ElAndName : zip(t&: SignatureElements, u&: SemanticNames)) { |
| 171 | llvm::dxbc::PSV::v0::SignatureElement &El = std::get<0>(t&: ElAndName); |
| 172 | StringRef Name = std::get<1>(t&: ElAndName); |
| 173 | El.NameOffset = static_cast<uint32_t>(DXConStrTabBuilder.getOffset(S: Name)); |
| 174 | if (sys::IsBigEndianHost) |
| 175 | El.swapBytes(); |
| 176 | } |
| 177 | |
| 178 | BaseData.EntryNameOffset = |
| 179 | static_cast<uint32_t>(DXConStrTabBuilder.getOffset(S: 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(N: 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(s: &FinalElement, c: 0, n: sizeof(dxbc::ProgramSignatureElement)); |
| 203 | FinalElement.Stream = P.Stream; |
| 204 | FinalElement.NameOffset = |
| 205 | static_cast<uint32_t>(StrTabBuilder.add(S: 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(Elt: FinalElement); |
| 214 | } |
| 215 | |
| 216 | StrTabBuilder.finalizeInOrder(); |
| 217 | stable_sort(Range&: SigParams, C: [&](const dxbc::ProgramSignatureElement &L, |
| 218 | const dxbc::ProgramSignatureElement R) { |
| 219 | return std::tie(args: L.Stream, args: L.Register, args: L.NameOffset) < |
| 220 | std::tie(args: R.Stream, args: R.Register, args: R.NameOffset); |
| 221 | }); |
| 222 | if (sys::IsBigEndianHost) |
| 223 | for (auto &El : SigParams) |
| 224 | El.swapBytes(); |
| 225 | |
| 226 | dxbc::ProgramSignatureHeader = {.ParamCount: static_cast<uint32_t>(Params.size()), |
| 227 | .FirstParamOffset: sizeof(dxbc::ProgramSignatureHeader)}; |
| 228 | if (sys::IsBigEndianHost) |
| 229 | Header.swapBytes(); |
| 230 | OS.write(Ptr: reinterpret_cast<const char *>(&Header), |
| 231 | Size: sizeof(dxbc::ProgramSignatureHeader)); |
| 232 | OS.write(Ptr: reinterpret_cast<const char *>(SigParams.data()), |
| 233 | Size: sizeof(dxbc::ProgramSignatureElement) * SigParams.size()); |
| 234 | StrTabBuilder.write(OS); |
| 235 | } |
| 236 | |