xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/DXContainerPSVInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
115f757f3fSDimitry Andric #include "llvm/MC/StringTableBuilder.h"
125f757f3fSDimitry 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 
195f757f3fSDimitry Andric static constexpr size_t npos = StringRef::npos;
205f757f3fSDimitry Andric 
215f757f3fSDimitry Andric static size_t FindSequence(ArrayRef<uint32_t> Buffer,
225f757f3fSDimitry Andric                            ArrayRef<uint32_t> Sequence) {
235f757f3fSDimitry Andric   if (Buffer.size() < Sequence.size())
245f757f3fSDimitry Andric     return npos;
255f757f3fSDimitry Andric   for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) {
265f757f3fSDimitry Andric     if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]),
275f757f3fSDimitry Andric                     static_cast<const void *>(Sequence.begin()),
285f757f3fSDimitry Andric                     Sequence.size() * sizeof(uint32_t)))
295f757f3fSDimitry Andric       return Idx;
305f757f3fSDimitry Andric   }
315f757f3fSDimitry Andric   return npos;
325f757f3fSDimitry Andric }
335f757f3fSDimitry Andric 
345f757f3fSDimitry Andric static void
355f757f3fSDimitry Andric ProcessElementList(StringTableBuilder &StrTabBuilder,
365f757f3fSDimitry Andric                    SmallVectorImpl<uint32_t> &IndexBuffer,
375f757f3fSDimitry Andric                    SmallVectorImpl<v0::SignatureElement> &FinalElements,
385f757f3fSDimitry Andric                    SmallVectorImpl<StringRef> &SemanticNames,
395f757f3fSDimitry Andric                    ArrayRef<PSVSignatureElement> Elements) {
405f757f3fSDimitry Andric   for (const auto &El : Elements) {
415f757f3fSDimitry Andric     // Put the name in the string table and the name list.
425f757f3fSDimitry Andric     StrTabBuilder.add(El.Name);
435f757f3fSDimitry Andric     SemanticNames.push_back(El.Name);
445f757f3fSDimitry Andric 
455f757f3fSDimitry Andric     v0::SignatureElement FinalElement;
465f757f3fSDimitry Andric     memset(&FinalElement, 0, sizeof(v0::SignatureElement));
475f757f3fSDimitry Andric     FinalElement.Rows = static_cast<uint8_t>(El.Indices.size());
485f757f3fSDimitry Andric     FinalElement.StartRow = El.StartRow;
495f757f3fSDimitry Andric     FinalElement.Cols = El.Cols;
505f757f3fSDimitry Andric     FinalElement.StartCol = El.StartCol;
515f757f3fSDimitry Andric     FinalElement.Allocated = El.Allocated;
525f757f3fSDimitry Andric     FinalElement.Kind = El.Kind;
535f757f3fSDimitry Andric     FinalElement.Type = El.Type;
545f757f3fSDimitry Andric     FinalElement.Mode = El.Mode;
555f757f3fSDimitry Andric     FinalElement.DynamicMask = El.DynamicMask;
565f757f3fSDimitry Andric     FinalElement.Stream = El.Stream;
575f757f3fSDimitry Andric 
585f757f3fSDimitry Andric     size_t Idx = FindSequence(IndexBuffer, El.Indices);
595f757f3fSDimitry Andric     if (Idx == npos) {
605f757f3fSDimitry Andric       FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size());
615f757f3fSDimitry Andric       IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(),
625f757f3fSDimitry Andric                          El.Indices.end());
635f757f3fSDimitry Andric     } else
645f757f3fSDimitry Andric       FinalElement.IndicesOffset = static_cast<uint32_t>(Idx);
655f757f3fSDimitry Andric     FinalElements.push_back(FinalElement);
665f757f3fSDimitry Andric   }
675f757f3fSDimitry Andric }
685f757f3fSDimitry Andric 
6906c3fb27SDimitry Andric void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const {
705f757f3fSDimitry Andric   assert(IsFinalized && "finalize must be called before write");
715f757f3fSDimitry 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     InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo);
8506c3fb27SDimitry Andric     BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);
86*0fca6ea1SDimitry Andric     break;
87*0fca6ea1SDimitry Andric   case 3:
88*0fca6ea1SDimitry Andric   default:
89*0fca6ea1SDimitry Andric     InfoSize = sizeof(dxbc::PSV::v3::RuntimeInfo);
90*0fca6ea1SDimitry Andric     BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);
9106c3fb27SDimitry Andric   }
925f757f3fSDimitry Andric 
93*0fca6ea1SDimitry Andric   // Write the size of the info.
945f757f3fSDimitry Andric   support::endian::write(OS, InfoSize, llvm::endianness::little);
95*0fca6ea1SDimitry Andric 
9606c3fb27SDimitry Andric   // Write the info itself.
9706c3fb27SDimitry Andric   OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize);
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric   uint32_t ResourceCount = static_cast<uint32_t>(Resources.size());
10006c3fb27SDimitry Andric 
1015f757f3fSDimitry Andric   support::endian::write(OS, ResourceCount, llvm::endianness::little);
1025f757f3fSDimitry Andric   if (ResourceCount > 0)
1035f757f3fSDimitry Andric     support::endian::write(OS, BindingSize, llvm::endianness::little);
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric   for (const auto &Res : Resources)
10606c3fb27SDimitry Andric     OS.write(reinterpret_cast<const char *>(&Res), BindingSize);
1075f757f3fSDimitry Andric 
1085f757f3fSDimitry Andric   // PSV Version 0 stops after the resource list.
1095f757f3fSDimitry Andric   if (Version == 0)
1105f757f3fSDimitry Andric     return;
1115f757f3fSDimitry Andric 
112*0fca6ea1SDimitry Andric   support::endian::write(OS,
113*0fca6ea1SDimitry Andric                          static_cast<uint32_t>(DXConStrTabBuilder.getSize()),
1145f757f3fSDimitry Andric                          llvm::endianness::little);
1155f757f3fSDimitry Andric 
1165f757f3fSDimitry Andric   // Write the string table.
117*0fca6ea1SDimitry Andric   DXConStrTabBuilder.write(OS);
1185f757f3fSDimitry Andric 
1195f757f3fSDimitry Andric   // Write the index table size, then table.
1205f757f3fSDimitry Andric   support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()),
1215f757f3fSDimitry Andric                          llvm::endianness::little);
1225f757f3fSDimitry Andric   for (auto I : IndexBuffer)
1235f757f3fSDimitry Andric     support::endian::write(OS, I, llvm::endianness::little);
1245f757f3fSDimitry Andric 
1255f757f3fSDimitry Andric   if (SignatureElements.size() > 0) {
1265f757f3fSDimitry Andric     // write the size of the signature elements.
1275f757f3fSDimitry Andric     support::endian::write(OS,
1285f757f3fSDimitry Andric                            static_cast<uint32_t>(sizeof(v0::SignatureElement)),
1295f757f3fSDimitry Andric                            llvm::endianness::little);
1305f757f3fSDimitry Andric 
1315f757f3fSDimitry Andric     // write the signature elements.
1325f757f3fSDimitry Andric     OS.write(reinterpret_cast<const char *>(&SignatureElements[0]),
1335f757f3fSDimitry Andric              SignatureElements.size() * sizeof(v0::SignatureElement));
1345f757f3fSDimitry Andric   }
1355f757f3fSDimitry Andric 
1365f757f3fSDimitry Andric   for (const auto &MaskVector : OutputVectorMasks)
1375f757f3fSDimitry Andric     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
1385f757f3fSDimitry Andric                                  llvm::endianness::little);
1395f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks),
1405f757f3fSDimitry Andric                                llvm::endianness::little);
1415f757f3fSDimitry Andric   for (const auto &MaskVector : InputOutputMap)
1425f757f3fSDimitry Andric     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
1435f757f3fSDimitry Andric                                  llvm::endianness::little);
1445f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap),
1455f757f3fSDimitry Andric                                llvm::endianness::little);
1465f757f3fSDimitry Andric   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),
1475f757f3fSDimitry Andric                                llvm::endianness::little);
1485f757f3fSDimitry Andric }
1495f757f3fSDimitry Andric 
150*0fca6ea1SDimitry Andric void PSVRuntimeInfo::finalize(Triple::EnvironmentType Stage) {
151*0fca6ea1SDimitry Andric   IsFinalized = true;
152*0fca6ea1SDimitry Andric   BaseData.SigInputElements = static_cast<uint32_t>(InputElements.size());
153*0fca6ea1SDimitry Andric   BaseData.SigOutputElements = static_cast<uint32_t>(OutputElements.size());
154*0fca6ea1SDimitry Andric   BaseData.SigPatchOrPrimElements =
155*0fca6ea1SDimitry Andric       static_cast<uint32_t>(PatchOrPrimElements.size());
156*0fca6ea1SDimitry Andric 
157*0fca6ea1SDimitry Andric   SmallVector<StringRef, 32> SemanticNames;
158*0fca6ea1SDimitry Andric 
159*0fca6ea1SDimitry Andric   // Build a string table and set associated offsets to be written when
160*0fca6ea1SDimitry Andric   // write() is called
161*0fca6ea1SDimitry Andric   ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,
162*0fca6ea1SDimitry Andric                      SemanticNames, InputElements);
163*0fca6ea1SDimitry Andric   ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,
164*0fca6ea1SDimitry Andric                      SemanticNames, OutputElements);
165*0fca6ea1SDimitry Andric   ProcessElementList(DXConStrTabBuilder, IndexBuffer, SignatureElements,
166*0fca6ea1SDimitry Andric                      SemanticNames, PatchOrPrimElements);
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric   DXConStrTabBuilder.add(EntryName);
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric   DXConStrTabBuilder.finalize();
171*0fca6ea1SDimitry Andric   for (auto ElAndName : zip(SignatureElements, SemanticNames)) {
172*0fca6ea1SDimitry Andric     llvm::dxbc::PSV::v0::SignatureElement &El = std::get<0>(ElAndName);
173*0fca6ea1SDimitry Andric     StringRef Name = std::get<1>(ElAndName);
174*0fca6ea1SDimitry Andric     El.NameOffset = static_cast<uint32_t>(DXConStrTabBuilder.getOffset(Name));
175*0fca6ea1SDimitry Andric     if (sys::IsBigEndianHost)
176*0fca6ea1SDimitry Andric       El.swapBytes();
177*0fca6ea1SDimitry Andric   }
178*0fca6ea1SDimitry Andric 
179*0fca6ea1SDimitry Andric   BaseData.EntryNameOffset =
180*0fca6ea1SDimitry Andric       static_cast<uint32_t>(DXConStrTabBuilder.getOffset(EntryName));
181*0fca6ea1SDimitry Andric 
182*0fca6ea1SDimitry Andric   if (!sys::IsBigEndianHost)
183*0fca6ea1SDimitry Andric     return;
184*0fca6ea1SDimitry Andric   BaseData.swapBytes();
185*0fca6ea1SDimitry Andric   BaseData.swapBytes(Stage);
186*0fca6ea1SDimitry Andric   for (auto &Res : Resources)
187*0fca6ea1SDimitry Andric     Res.swapBytes();
188*0fca6ea1SDimitry Andric }
189*0fca6ea1SDimitry Andric 
1905f757f3fSDimitry Andric void Signature::write(raw_ostream &OS) {
1915f757f3fSDimitry Andric   SmallVector<dxbc::ProgramSignatureElement> SigParams;
1925f757f3fSDimitry Andric   SigParams.reserve(Params.size());
1935f757f3fSDimitry Andric   StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));
1945f757f3fSDimitry Andric 
1955f757f3fSDimitry Andric   // Name offsets are from the start of the part. Pre-calculate the offset to
1965f757f3fSDimitry Andric   // the start of the string table so that it can be added to the table offset.
1975f757f3fSDimitry Andric   uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +
1985f757f3fSDimitry Andric                         (sizeof(dxbc::ProgramSignatureElement) * Params.size());
1995f757f3fSDimitry Andric 
2005f757f3fSDimitry Andric   for (const auto &P : Params) {
2015f757f3fSDimitry Andric     // zero out the data
2025f757f3fSDimitry Andric     dxbc::ProgramSignatureElement FinalElement;
2035f757f3fSDimitry Andric     memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));
2045f757f3fSDimitry Andric     FinalElement.Stream = P.Stream;
2055f757f3fSDimitry Andric     FinalElement.NameOffset =
2065f757f3fSDimitry Andric         static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;
2075f757f3fSDimitry Andric     FinalElement.Index = P.Index;
2085f757f3fSDimitry Andric     FinalElement.SystemValue = P.SystemValue;
2095f757f3fSDimitry Andric     FinalElement.CompType = P.CompType;
2105f757f3fSDimitry Andric     FinalElement.Register = P.Register;
2115f757f3fSDimitry Andric     FinalElement.Mask = P.Mask;
2125f757f3fSDimitry Andric     FinalElement.ExclusiveMask = P.ExclusiveMask;
2135f757f3fSDimitry Andric     FinalElement.MinPrecision = P.MinPrecision;
2145f757f3fSDimitry Andric     SigParams.push_back(FinalElement);
2155f757f3fSDimitry Andric   }
2165f757f3fSDimitry Andric 
2175f757f3fSDimitry Andric   StrTabBuilder.finalizeInOrder();
2185f757f3fSDimitry Andric   stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,
2195f757f3fSDimitry Andric                              const dxbc::ProgramSignatureElement R) {
2205f757f3fSDimitry Andric     return std::tie(L.Stream, L.Register, L.NameOffset) <
2215f757f3fSDimitry Andric            std::tie(R.Stream, R.Register, R.NameOffset);
2225f757f3fSDimitry Andric   });
2235f757f3fSDimitry Andric   if (sys::IsBigEndianHost)
2245f757f3fSDimitry Andric     for (auto &El : SigParams)
2255f757f3fSDimitry Andric       El.swapBytes();
2265f757f3fSDimitry Andric 
2275f757f3fSDimitry Andric   dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),
2285f757f3fSDimitry Andric                                          sizeof(dxbc::ProgramSignatureHeader)};
2295f757f3fSDimitry Andric   if (sys::IsBigEndianHost)
2305f757f3fSDimitry Andric     Header.swapBytes();
2315f757f3fSDimitry Andric   OS.write(reinterpret_cast<const char *>(&Header),
2325f757f3fSDimitry Andric            sizeof(dxbc::ProgramSignatureHeader));
2335f757f3fSDimitry Andric   OS.write(reinterpret_cast<const char *>(SigParams.data()),
2345f757f3fSDimitry Andric            sizeof(dxbc::ProgramSignatureElement) * SigParams.size());
2355f757f3fSDimitry Andric   StrTabBuilder.write(OS);
23606c3fb27SDimitry Andric }
237