-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathDXContainerPSVInfo.cpp
211 lines (183 loc) · 8.11 KB
/
DXContainerPSVInfo.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//===- llvm/MC/DXContainerPSVInfo.cpp - DXContainer PSVInfo -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/DXContainerPSVInfo.h"
#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::mcdxbc;
using namespace llvm::dxbc::PSV;
static constexpr size_t npos = StringRef::npos;
static size_t FindSequence(ArrayRef<uint32_t> Buffer,
ArrayRef<uint32_t> Sequence) {
if (Buffer.size() < Sequence.size())
return npos;
for (size_t Idx = 0; Idx <= Buffer.size() - Sequence.size(); ++Idx) {
if (0 == memcmp(static_cast<const void *>(&Buffer[Idx]),
static_cast<const void *>(Sequence.begin()),
Sequence.size() * sizeof(uint32_t)))
return Idx;
}
return npos;
}
static void
ProcessElementList(StringTableBuilder &StrTabBuilder,
SmallVectorImpl<uint32_t> &IndexBuffer,
SmallVectorImpl<v0::SignatureElement> &FinalElements,
SmallVectorImpl<StringRef> &SemanticNames,
ArrayRef<PSVSignatureElement> Elements) {
for (const auto &El : Elements) {
// Put the name in the string table and the name list.
StrTabBuilder.add(El.Name);
SemanticNames.push_back(El.Name);
v0::SignatureElement FinalElement;
memset(&FinalElement, 0, sizeof(v0::SignatureElement));
FinalElement.Rows = static_cast<uint8_t>(El.Indices.size());
FinalElement.StartRow = El.StartRow;
FinalElement.Cols = El.Cols;
FinalElement.StartCol = El.StartCol;
FinalElement.Allocated = El.Allocated;
FinalElement.Kind = El.Kind;
FinalElement.Type = El.Type;
FinalElement.Mode = El.Mode;
FinalElement.DynamicMask = El.DynamicMask;
FinalElement.Stream = El.Stream;
size_t Idx = FindSequence(IndexBuffer, El.Indices);
if (Idx == npos) {
FinalElement.IndicesOffset = static_cast<uint32_t>(IndexBuffer.size());
IndexBuffer.insert(IndexBuffer.end(), El.Indices.begin(),
El.Indices.end());
} else
FinalElement.IndicesOffset = static_cast<uint32_t>(Idx);
FinalElements.push_back(FinalElement);
}
}
void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const {
assert(IsFinalized && "finalize must be called before write");
uint32_t InfoSize;
uint32_t BindingSize;
switch (Version) {
case 0:
InfoSize = sizeof(dxbc::PSV::v0::RuntimeInfo);
BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);
break;
case 1:
InfoSize = sizeof(dxbc::PSV::v1::RuntimeInfo);
BindingSize = sizeof(dxbc::PSV::v0::ResourceBindInfo);
break;
case 2:
default:
InfoSize = sizeof(dxbc::PSV::v2::RuntimeInfo);
BindingSize = sizeof(dxbc::PSV::v2::ResourceBindInfo);
}
// Write the size of the info.
support::endian::write(OS, InfoSize, llvm::endianness::little);
// Write the info itself.
OS.write(reinterpret_cast<const char *>(&BaseData), InfoSize);
uint32_t ResourceCount = static_cast<uint32_t>(Resources.size());
support::endian::write(OS, ResourceCount, llvm::endianness::little);
if (ResourceCount > 0)
support::endian::write(OS, BindingSize, llvm::endianness::little);
for (const auto &Res : Resources)
OS.write(reinterpret_cast<const char *>(&Res), BindingSize);
// PSV Version 0 stops after the resource list.
if (Version == 0)
return;
StringTableBuilder StrTabBuilder((StringTableBuilder::DXContainer));
SmallVector<uint32_t, 64> IndexBuffer;
SmallVector<v0::SignatureElement, 32> SignatureElements;
SmallVector<StringRef, 32> SemanticNames;
ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
SemanticNames, InputElements);
ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
SemanticNames, OutputElements);
ProcessElementList(StrTabBuilder, IndexBuffer, SignatureElements,
SemanticNames, PatchOrPrimElements);
StrTabBuilder.finalize();
for (auto ElAndName : zip(SignatureElements, SemanticNames)) {
v0::SignatureElement &El = std::get<0>(ElAndName);
StringRef Name = std::get<1>(ElAndName);
El.NameOffset = static_cast<uint32_t>(StrTabBuilder.getOffset(Name));
if (sys::IsBigEndianHost)
El.swapBytes();
}
support::endian::write(OS, static_cast<uint32_t>(StrTabBuilder.getSize()),
llvm::endianness::little);
// Write the string table.
StrTabBuilder.write(OS);
// Write the index table size, then table.
support::endian::write(OS, static_cast<uint32_t>(IndexBuffer.size()),
llvm::endianness::little);
for (auto I : IndexBuffer)
support::endian::write(OS, I, llvm::endianness::little);
if (SignatureElements.size() > 0) {
// write the size of the signature elements.
support::endian::write(OS,
static_cast<uint32_t>(sizeof(v0::SignatureElement)),
llvm::endianness::little);
// write the signature elements.
OS.write(reinterpret_cast<const char *>(&SignatureElements[0]),
SignatureElements.size() * sizeof(v0::SignatureElement));
}
for (const auto &MaskVector : OutputVectorMasks)
support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
llvm::endianness::little);
support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOrPrimMasks),
llvm::endianness::little);
for (const auto &MaskVector : InputOutputMap)
support::endian::write_array(OS, ArrayRef<uint32_t>(MaskVector),
llvm::endianness::little);
support::endian::write_array(OS, ArrayRef<uint32_t>(InputPatchMap),
llvm::endianness::little);
support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),
llvm::endianness::little);
}
void Signature::write(raw_ostream &OS) {
SmallVector<dxbc::ProgramSignatureElement> SigParams;
SigParams.reserve(Params.size());
StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));
// Name offsets are from the start of the part. Pre-calculate the offset to
// the start of the string table so that it can be added to the table offset.
uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +
(sizeof(dxbc::ProgramSignatureElement) * Params.size());
for (const auto &P : Params) {
// zero out the data
dxbc::ProgramSignatureElement FinalElement;
memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));
FinalElement.Stream = P.Stream;
FinalElement.NameOffset =
static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;
FinalElement.Index = P.Index;
FinalElement.SystemValue = P.SystemValue;
FinalElement.CompType = P.CompType;
FinalElement.Register = P.Register;
FinalElement.Mask = P.Mask;
FinalElement.ExclusiveMask = P.ExclusiveMask;
FinalElement.MinPrecision = P.MinPrecision;
SigParams.push_back(FinalElement);
}
StrTabBuilder.finalizeInOrder();
stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,
const dxbc::ProgramSignatureElement R) {
return std::tie(L.Stream, L.Register, L.NameOffset) <
std::tie(R.Stream, R.Register, R.NameOffset);
});
if (sys::IsBigEndianHost)
for (auto &El : SigParams)
El.swapBytes();
dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),
sizeof(dxbc::ProgramSignatureHeader)};
if (sys::IsBigEndianHost)
Header.swapBytes();
OS.write(reinterpret_cast<const char *>(&Header),
sizeof(dxbc::ProgramSignatureHeader));
OS.write(reinterpret_cast<const char *>(SigParams.data()),
sizeof(dxbc::ProgramSignatureElement) * SigParams.size());
StrTabBuilder.write(OS);
}