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