xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/DXContainerPSVInfo.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
106c3fb27SDimitry Andric //===- llvm/MC/DXContainerPSVInfo.cpp - DXContainer PSVInfo -----*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "llvm/MC/DXContainerPSVInfo.h"
1006c3fb27SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h"
11*5f757f3fSDimitry Andric #include "llvm/MC/StringTableBuilder.h"
12*5f757f3fSDimitry Andric #include "llvm/Support/EndianStream.h"
1306c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h"
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric using namespace llvm;
1606c3fb27SDimitry Andric using namespace llvm::mcdxbc;
1706c3fb27SDimitry Andric using namespace llvm::dxbc::PSV;
1806c3fb27SDimitry Andric 
19*5f757f3fSDimitry Andric static constexpr size_t npos = StringRef::npos;
20*5f757f3fSDimitry Andric 
21*5f757f3fSDimitry Andric static size_t FindSequence(ArrayRef<uint32_t> Buffer,
22*5f757f3fSDimitry Andric                            ArrayRef<uint32_t> Sequence) {
23*5f757f3fSDimitry Andric   if (Buffer.size() < Sequence.size())
24*5f757f3fSDimitry Andric     return npos;
25*5f757f3fSDimitry Andric   for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) {
26*5f757f3fSDimitry Andric     if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]),
27*5f757f3fSDimitry Andric                     static_cast<const void *>(Sequence.begin()),
28*5f757f3fSDimitry Andric                     Sequence.size() * sizeof(uint32_t)))
29*5f757f3fSDimitry Andric       return Idx;
30*5f757f3fSDimitry Andric   }
31*5f757f3fSDimitry Andric   return npos;
32*5f757f3fSDimitry Andric }
33*5f757f3fSDimitry Andric 
34*5f757f3fSDimitry Andric static void
35*5f757f3fSDimitry Andric ProcessElementList(StringTableBuilder &StrTabBuilder,
36*5f757f3fSDimitry Andric                    SmallVectorImpl<uint32_t> &IndexBuffer,
37*5f757f3fSDimitry Andric                    SmallVectorImpl<v0::SignatureElement> &FinalElements,
38*5f757f3fSDimitry Andric                    SmallVectorImpl<StringRef> &SemanticNames,
39*5f757f3fSDimitry Andric                    ArrayRef<PSVSignatureElement> Elements) {
40*5f757f3fSDimitry Andric   for (const auto &El : Elements) {
41*5f757f3fSDimitry Andric     // Put the name in the string table and the name list.
42*5f757f3fSDimitry Andric     StrTabBuilder.add(El.Name);
43*5f757f3fSDimitry Andric     SemanticNames.push_back(El.Name);
44*5f757f3fSDimitry Andric 
45*5f757f3fSDimitry Andric     v0::SignatureElement FinalElement;
46*5f757f3fSDimitry Andric     memset(&FinalElement, 0, sizeof(v0::SignatureElement));
47*5f757f3fSDimitry Andric     FinalElement.Rows = static_cast<uint8_t>(El.Indices.size());
48*5f757f3fSDimitry Andric     FinalElement.StartRow = El.StartRow;
49*5f757f3fSDimitry Andric     FinalElement.Cols = El.Cols;
50*5f757f3fSDimitry Andric     FinalElement.StartCol = El.StartCol;
51*5f757f3fSDimitry Andric     FinalElement.Allocated = El.Allocated;
52*5f757f3fSDimitry Andric     FinalElement.Kind = El.Kind;
53*5f757f3fSDimitry Andric     FinalElement.Type = El.Type;
54*5f757f3fSDimitry Andric     FinalElement.Mode = El.Mode;
55*5f757f3fSDimitry Andric     FinalElement.DynamicMask = El.DynamicMask;
56*5f757f3fSDimitry Andric     FinalElement.Stream = El.Stream;
57*5f757f3fSDimitry Andric 
58*5f757f3fSDimitry Andric     size_t Idx = FindSequence(IndexBuffer, El.Indices);
59*5f757f3fSDimitry Andric     if (Idx == npos) {
60*5f757f3fSDimitry Andric       FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size());
61*5f757f3fSDimitry Andric       IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(),
62*5f757f3fSDimitry Andric                          El.Indices.end());
63*5f757f3fSDimitry Andric     } else
64*5f757f3fSDimitry Andric       FinalElement.IndicesOffset = static_cast<uint32_t>(Idx);
65*5f757f3fSDimitry Andric     FinalElements.push_back(FinalElement);
66*5f757f3fSDimitry Andric   }
67*5f757f3fSDimitry Andric }
68*5f757f3fSDimitry Andric 
6906c3fb27SDimitry Andric void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const {
70*5f757f3fSDimitry Andric   assert(IsFinalized && "finalize must be called before write");
71*5f757f3fSDimitry Andric 
7206c3fb27SDimitry Andric   uint32_t InfoSize;
7306c3fb27SDimitry Andric   uint32_t BindingSize;
7406c3fb27SDimitry Andric   switch (Version) {
7506c3fb27SDimitry Andric   case 0:
7606c3fb27SDimitry Andric     InfoSize = sizeof(dxbc::PSV::v0::RuntimeInfo);
7706c3fb27SDimitry Andric     BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);
7806c3fb27SDimitry Andric     break;
7906c3fb27SDimitry Andric   case 1:
8006c3fb27SDimitry Andric     InfoSize = sizeof(dxbc::PSV::v1::RuntimeInfo);
8106c3fb27SDimitry Andric     BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);
8206c3fb27SDimitry Andric     break;
8306c3fb27SDimitry Andric   case 2:
8406c3fb27SDimitry Andric   default:
8506c3fb27SDimitry Andric     InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo);
8606c3fb27SDimitry Andric     BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);
8706c3fb27SDimitry Andric   }
8806c3fb27SDimitry Andric   // Write the size of the info.
89*5f757f3fSDimitry Andric 
90*5f757f3fSDimitry Andric   support::endian::write(OS, InfoSize, llvm::endianness::little);
9106c3fb27SDimitry Andric   // Write the info itself.
9206c3fb27SDimitry Andric   OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize);
9306c3fb27SDimitry Andric 
9406c3fb27SDimitry Andric   uint32_t ResourceCount = static_cast<uint32_t>(Resources.size());
9506c3fb27SDimitry Andric 
96*5f757f3fSDimitry Andric   support::endian::write(OS, ResourceCount, llvm::endianness::little);
97*5f757f3fSDimitry Andric   if (ResourceCount > 0)
98*5f757f3fSDimitry Andric     support::endian::write(OS, BindingSize, llvm::endianness::little);
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric   for (const auto &Res : Resources)
10106c3fb27SDimitry Andric     OS.write(reinterpret_cast<const char *>(&Res), BindingSize);
102*5f757f3fSDimitry Andric 
103*5f757f3fSDimitry Andric   // PSV Version 0 stops after the resource list.
104*5f757f3fSDimitry Andric   if (Version == 0)
105*5f757f3fSDimitry Andric     return;
106*5f757f3fSDimitry Andric 
107*5f757f3fSDimitry Andric   StringTableBuilder StrTabBuilder((StringTableBuilder::DXContainer));
108*5f757f3fSDimitry Andric   SmallVector<uint32_t, 64> IndexBuffer;
109*5f757f3fSDimitry Andric   SmallVector<v0::SignatureElement, 32> SignatureElements;
110*5f757f3fSDimitry Andric   SmallVector<StringRef, 32> SemanticNames;
111*5f757f3fSDimitry Andric 
112*5f757f3fSDimitry Andric   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
113*5f757f3fSDimitry Andric                      SemanticNames, InputElements);
114*5f757f3fSDimitry Andric   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
115*5f757f3fSDimitry Andric                      SemanticNames, OutputElements);
116*5f757f3fSDimitry Andric   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
117*5f757f3fSDimitry Andric                      SemanticNames, PatchOrPrimElements);
118*5f757f3fSDimitry Andric 
119*5f757f3fSDimitry Andric   StrTabBuilder.finalize();
120*5f757f3fSDimitry Andric   for (auto ElAndName : zip(SignatureElements, SemanticNames)) {
121*5f757f3fSDimitry Andric     v0::SignatureElement &El = std::get<0>(ElAndName);
122*5f757f3fSDimitry Andric     StringRef Name = std::get<1>(ElAndName);
123*5f757f3fSDimitry Andric     El.NameOffset = static_cast<uint32_t>(StrTabBuilder.getOffset(Name));
124*5f757f3fSDimitry Andric     if (sys::IsBigEndianHost)
125*5f757f3fSDimitry Andric       El.swapBytes();
126*5f757f3fSDimitry Andric   }
127*5f757f3fSDimitry Andric 
128*5f757f3fSDimitry Andric   support::endian::write(OS, static_cast<uint32_t>(StrTabBuilder.getSize()),
129*5f757f3fSDimitry Andric                          llvm::endianness::little);
130*5f757f3fSDimitry Andric 
131*5f757f3fSDimitry Andric   // Write the string table.
132*5f757f3fSDimitry Andric   StrTabBuilder.write(OS);
133*5f757f3fSDimitry Andric 
134*5f757f3fSDimitry Andric   // Write the index table size, then table.
135*5f757f3fSDimitry Andric   support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()),
136*5f757f3fSDimitry Andric                          llvm::endianness::little);
137*5f757f3fSDimitry Andric   for (auto I : IndexBuffer)
138*5f757f3fSDimitry Andric     support::endian::write(OS, I, llvm::endianness::little);
139*5f757f3fSDimitry Andric 
140*5f757f3fSDimitry Andric   if (SignatureElements.size() > 0) {
141*5f757f3fSDimitry Andric     // write the size of the signature elements.
142*5f757f3fSDimitry Andric     support::endian::write(OS,
143*5f757f3fSDimitry Andric                            static_cast<uint32_t>(sizeof(v0::SignatureElement)),
144*5f757f3fSDimitry Andric                            llvm::endianness::little);
145*5f757f3fSDimitry Andric 
146*5f757f3fSDimitry Andric     // write the signature elements.
147*5f757f3fSDimitry Andric     OS.write(reinterpret_cast<const char *>(&SignatureElements[0]),
148*5f757f3fSDimitry Andric              SignatureElements.size() * sizeof(v0::SignatureElement));
149*5f757f3fSDimitry Andric   }
150*5f757f3fSDimitry Andric 
151*5f757f3fSDimitry Andric   for (const auto &MaskVector : OutputVectorMasks)
152*5f757f3fSDimitry Andric     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
153*5f757f3fSDimitry Andric                                  llvm::endianness::little);
154*5f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks),
155*5f757f3fSDimitry Andric                                llvm::endianness::little);
156*5f757f3fSDimitry Andric   for (const auto &MaskVector : InputOutputMap)
157*5f757f3fSDimitry Andric     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
158*5f757f3fSDimitry Andric                                  llvm::endianness::little);
159*5f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap),
160*5f757f3fSDimitry Andric                                llvm::endianness::little);
161*5f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),
162*5f757f3fSDimitry Andric                                llvm::endianness::little);
163*5f757f3fSDimitry Andric }
164*5f757f3fSDimitry Andric 
165*5f757f3fSDimitry Andric void Signature::write(raw_ostream &OS) {
166*5f757f3fSDimitry Andric   SmallVector<dxbc::ProgramSignatureElement> SigParams;
167*5f757f3fSDimitry Andric   SigParams.reserve(Params.size());
168*5f757f3fSDimitry Andric   StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));
169*5f757f3fSDimitry Andric 
170*5f757f3fSDimitry Andric   // Name offsets are from the start of the part. Pre-calculate the offset to
171*5f757f3fSDimitry Andric   // the start of the string table so that it can be added to the table offset.
172*5f757f3fSDimitry Andric   uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +
173*5f757f3fSDimitry Andric                         (sizeof(dxbc::ProgramSignatureElement) * Params.size());
174*5f757f3fSDimitry Andric 
175*5f757f3fSDimitry Andric   for (const auto &P : Params) {
176*5f757f3fSDimitry Andric     // zero out the data
177*5f757f3fSDimitry Andric     dxbc::ProgramSignatureElement FinalElement;
178*5f757f3fSDimitry Andric     memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));
179*5f757f3fSDimitry Andric     FinalElement.Stream = P.Stream;
180*5f757f3fSDimitry Andric     FinalElement.NameOffset =
181*5f757f3fSDimitry Andric         static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;
182*5f757f3fSDimitry Andric     FinalElement.Index = P.Index;
183*5f757f3fSDimitry Andric     FinalElement.SystemValue = P.SystemValue;
184*5f757f3fSDimitry Andric     FinalElement.CompType = P.CompType;
185*5f757f3fSDimitry Andric     FinalElement.Register = P.Register;
186*5f757f3fSDimitry Andric     FinalElement.Mask = P.Mask;
187*5f757f3fSDimitry Andric     FinalElement.ExclusiveMask = P.ExclusiveMask;
188*5f757f3fSDimitry Andric     FinalElement.MinPrecision = P.MinPrecision;
189*5f757f3fSDimitry Andric     SigParams.push_back(FinalElement);
190*5f757f3fSDimitry Andric   }
191*5f757f3fSDimitry Andric 
192*5f757f3fSDimitry Andric   StrTabBuilder.finalizeInOrder();
193*5f757f3fSDimitry Andric   stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,
194*5f757f3fSDimitry Andric                              const dxbc::ProgramSignatureElement R) {
195*5f757f3fSDimitry Andric     return std::tie(L.Stream, L.Register, L.NameOffset) <
196*5f757f3fSDimitry Andric            std::tie(R.Stream, R.Register, R.NameOffset);
197*5f757f3fSDimitry Andric   });
198*5f757f3fSDimitry Andric   if (sys::IsBigEndianHost)
199*5f757f3fSDimitry Andric     for (auto &El : SigParams)
200*5f757f3fSDimitry Andric       El.swapBytes();
201*5f757f3fSDimitry Andric 
202*5f757f3fSDimitry Andric   dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),
203*5f757f3fSDimitry Andric                                          sizeof(dxbc::ProgramSignatureHeader)};
204*5f757f3fSDimitry Andric   if (sys::IsBigEndianHost)
205*5f757f3fSDimitry Andric     Header.swapBytes();
206*5f757f3fSDimitry Andric   OS.write(reinterpret_cast<const char *>(&Header),
207*5f757f3fSDimitry Andric            sizeof(dxbc::ProgramSignatureHeader));
208*5f757f3fSDimitry Andric   OS.write(reinterpret_cast<const char *>(SigParams.data()),
209*5f757f3fSDimitry Andric            sizeof(dxbc::ProgramSignatureElement) * SigParams.size());
210*5f757f3fSDimitry Andric   StrTabBuilder.write(OS);
21106c3fb27SDimitry Andric }
212