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
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(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
34static void
35ProcessElementList(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
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&: 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
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 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
189void 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 Header = {.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