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