1 //===- llvm/MC/DXContainerPSVInfo.cpp - DXContainer PSVInfo -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
16 using namespace llvm::mcdxbc
;
17 using namespace llvm::dxbc::PSV
;
19 static constexpr size_t npos
= StringRef::npos
;
21 static size_t FindSequence(ArrayRef
<uint32_t> Buffer
,
22 ArrayRef
<uint32_t> Sequence
) {
23 if (Buffer
.size() < Sequence
.size())
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)))
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
);
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
;
58 size_t Idx
= FindSequence(IndexBuffer
, El
.Indices
);
60 FinalElement
.IndicesOffset
= static_cast<uint32_t>(IndexBuffer
.size());
61 IndexBuffer
.insert(IndexBuffer
.end(), El
.Indices
.begin(),
64 FinalElement
.IndicesOffset
= static_cast<uint32_t>(Idx
);
65 FinalElements
.push_back(FinalElement
);
69 void PSVRuntimeInfo::write(raw_ostream
&OS
, uint32_t Version
) const {
70 assert(IsFinalized
&& "finalize must be called before write");
76 InfoSize
= sizeof(dxbc::PSV::v0::RuntimeInfo
);
77 BindingSize
= sizeof(dxbc::PSV::v0::ResourceBindInfo
);
80 InfoSize
= sizeof(dxbc::PSV::v1::RuntimeInfo
);
81 BindingSize
= sizeof(dxbc::PSV::v0::ResourceBindInfo
);
84 InfoSize
= sizeof(dxbc::PSV::v2::RuntimeInfo
);
85 BindingSize
= sizeof(dxbc::PSV::v2::ResourceBindInfo
);
89 InfoSize
= sizeof(dxbc::PSV::v3::RuntimeInfo
);
90 BindingSize
= sizeof(dxbc::PSV::v2::ResourceBindInfo
);
93 // Write the size of the info.
94 support::endian::write(OS
, InfoSize
, llvm::endianness::little
);
96 // Write the info itself.
97 OS
.write(reinterpret_cast<const char *>(&BaseData
), InfoSize
);
99 uint32_t ResourceCount
= static_cast<uint32_t>(Resources
.size());
101 support::endian::write(OS
, ResourceCount
, llvm::endianness::little
);
102 if (ResourceCount
> 0)
103 support::endian::write(OS
, BindingSize
, llvm::endianness::little
);
105 for (const auto &Res
: Resources
)
106 OS
.write(reinterpret_cast<const char *>(&Res
), BindingSize
);
108 // PSV Version 0 stops after the resource list.
112 support::endian::write(OS
,
113 static_cast<uint32_t>(DXConStrTabBuilder
.getSize()),
114 llvm::endianness::little
);
116 // Write the string table.
117 DXConStrTabBuilder
.write(OS
);
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
);
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
);
131 // write the signature elements.
132 OS
.write(reinterpret_cast<const char *>(&SignatureElements
[0]),
133 SignatureElements
.size() * sizeof(v0::SignatureElement
));
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
);
150 void PSVRuntimeInfo::finalize(Triple::EnvironmentType Stage
) {
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());
157 SmallVector
<StringRef
, 32> SemanticNames
;
159 // Build a string table and set associated offsets to be written when
161 ProcessElementList(DXConStrTabBuilder
, IndexBuffer
, SignatureElements
,
162 SemanticNames
, InputElements
);
163 ProcessElementList(DXConStrTabBuilder
, IndexBuffer
, SignatureElements
,
164 SemanticNames
, OutputElements
);
165 ProcessElementList(DXConStrTabBuilder
, IndexBuffer
, SignatureElements
,
166 SemanticNames
, PatchOrPrimElements
);
168 DXConStrTabBuilder
.add(EntryName
);
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
)
179 BaseData
.EntryNameOffset
=
180 static_cast<uint32_t>(DXConStrTabBuilder
.getOffset(EntryName
));
182 if (!sys::IsBigEndianHost
)
184 BaseData
.swapBytes();
185 BaseData
.swapBytes(Stage
);
186 for (auto &Res
: Resources
)
190 void Signature::write(raw_ostream
&OS
) {
191 SmallVector
<dxbc::ProgramSignatureElement
> SigParams
;
192 SigParams
.reserve(Params
.size());
193 StringTableBuilder
StrTabBuilder((StringTableBuilder::DWARF
));
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());
200 for (const auto &P
: Params
) {
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
);
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
);
223 if (sys::IsBigEndianHost
)
224 for (auto &El
: SigParams
)
227 dxbc::ProgramSignatureHeader Header
= {static_cast<uint32_t>(Params
.size()),
228 sizeof(dxbc::ProgramSignatureHeader
)};
229 if (sys::IsBigEndianHost
)
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
);