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   default:
85     InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo);
86     BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);
87   }
88   // Write the size of the info.
89 
90   support::endian::write(OS, InfoSize, llvm::endianness::little);
91   // Write the info itself.
92   OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize);
93 
94   uint32_t ResourceCount = static_cast<uint32_t>(Resources.size());
95 
96   support::endian::write(OS, ResourceCount, llvm::endianness::little);
97   if (ResourceCount > 0)
98     support::endian::write(OS, BindingSize, llvm::endianness::little);
99 
100   for (const auto &Res : Resources)
101     OS.write(reinterpret_cast<const char *>(&Res), BindingSize);
102 
103   // PSV Version 0 stops after the resource list.
104   if (Version == 0)
105     return;
106 
107   StringTableBuilder StrTabBuilder((StringTableBuilder::DXContainer));
108   SmallVector<uint32_t, 64> IndexBuffer;
109   SmallVector<v0::SignatureElement, 32> SignatureElements;
110   SmallVector<StringRef, 32> SemanticNames;
111 
112   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
113                      SemanticNames, InputElements);
114   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
115                      SemanticNames, OutputElements);
116   ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
117                      SemanticNames, PatchOrPrimElements);
118 
119   StrTabBuilder.finalize();
120   for (auto ElAndName : zip(SignatureElements, SemanticNames)) {
121     v0::SignatureElement &El = std::get<0>(ElAndName);
122     StringRef Name = std::get<1>(ElAndName);
123     El.NameOffset = static_cast<uint32_t>(StrTabBuilder.getOffset(Name));
124     if (sys::IsBigEndianHost)
125       El.swapBytes();
126   }
127 
128   support::endian::write(OS, static_cast<uint32_t>(StrTabBuilder.getSize()),
129                          llvm::endianness::little);
130 
131   // Write the string table.
132   StrTabBuilder.write(OS);
133 
134   // Write the index table size, then table.
135   support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()),
136                          llvm::endianness::little);
137   for (auto I : IndexBuffer)
138     support::endian::write(OS, I, llvm::endianness::little);
139 
140   if (SignatureElements.size() > 0) {
141     // write the size of the signature elements.
142     support::endian::write(OS,
143                            static_cast<uint32_t>(sizeof(v0::SignatureElement)),
144                            llvm::endianness::little);
145 
146     // write the signature elements.
147     OS.write(reinterpret_cast<const char *>(&SignatureElements[0]),
148              SignatureElements.size() * sizeof(v0::SignatureElement));
149   }
150 
151   for (const auto &MaskVector : OutputVectorMasks)
152     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
153                                  llvm::endianness::little);
154   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks),
155                                llvm::endianness::little);
156   for (const auto &MaskVector : InputOutputMap)
157     support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
158                                  llvm::endianness::little);
159   support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap),
160                                llvm::endianness::little);
161   support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),
162                                llvm::endianness::little);
163 }
164 
write(raw_ostream & OS)165 void Signature::write(raw_ostream &OS) {
166   SmallVector<dxbc::ProgramSignatureElement> SigParams;
167   SigParams.reserve(Params.size());
168   StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));
169 
170   // Name offsets are from the start of the part. Pre-calculate the offset to
171   // the start of the string table so that it can be added to the table offset.
172   uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +
173                         (sizeof(dxbc::ProgramSignatureElement) * Params.size());
174 
175   for (const auto &P : Params) {
176     // zero out the data
177     dxbc::ProgramSignatureElement FinalElement;
178     memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));
179     FinalElement.Stream = P.Stream;
180     FinalElement.NameOffset =
181         static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;
182     FinalElement.Index = P.Index;
183     FinalElement.SystemValue = P.SystemValue;
184     FinalElement.CompType = P.CompType;
185     FinalElement.Register = P.Register;
186     FinalElement.Mask = P.Mask;
187     FinalElement.ExclusiveMask = P.ExclusiveMask;
188     FinalElement.MinPrecision = P.MinPrecision;
189     SigParams.push_back(FinalElement);
190   }
191 
192   StrTabBuilder.finalizeInOrder();
193   stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,
194                              const dxbc::ProgramSignatureElement R) {
195     return std::tie(L.Stream, L.Register, L.NameOffset) <
196            std::tie(R.Stream, R.Register, R.NameOffset);
197   });
198   if (sys::IsBigEndianHost)
199     for (auto &El : SigParams)
200       El.swapBytes();
201 
202   dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),
203                                          sizeof(dxbc::ProgramSignatureHeader)};
204   if (sys::IsBigEndianHost)
205     Header.swapBytes();
206   OS.write(reinterpret_cast<const char *>(&Header),
207            sizeof(dxbc::ProgramSignatureHeader));
208   OS.write(reinterpret_cast<const char *>(SigParams.data()),
209            sizeof(dxbc::ProgramSignatureElement) * SigParams.size());
210   StrTabBuilder.write(OS);
211 }
212