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