Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / unittests / Object / DXContainerTest.cpp
blobda640225617d4045b3fd5cb3cc61fd936ea356bf
1 //===- DXContainerTest.cpp - Tests for DXContainerFile --------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/DXContainer.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/BinaryFormat/Magic.h"
12 #include "llvm/ObjectYAML/DXContainerYAML.h"
13 #include "llvm/ObjectYAML/yaml2obj.h"
14 #include "llvm/Support/MemoryBufferRef.h"
15 #include "llvm/Testing/Support/Error.h"
16 #include "gtest/gtest.h"
18 using namespace llvm;
19 using namespace llvm::object;
21 template <std::size_t X> MemoryBufferRef getMemoryBuffer(uint8_t Data[X]) {
22 StringRef Obj(reinterpret_cast<char *>(&Data[0]), X);
23 return MemoryBufferRef(Obj, "");
26 TEST(DXCFile, IdentifyMagic) {
28 StringRef Buffer("DXBC");
29 EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
32 StringRef Buffer("DXBCBlahBlahBlah");
33 EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
37 TEST(DXCFile, ParseHeaderErrors) {
38 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43};
39 EXPECT_THAT_EXPECTED(
40 DXContainer::create(getMemoryBuffer<4>(Buffer)),
41 FailedWithMessage("Reading structure out of file bounds"));
44 TEST(DXCFile, EmptyFile) {
45 EXPECT_THAT_EXPECTED(
46 DXContainer::create(MemoryBufferRef(StringRef("", 0), "")),
47 FailedWithMessage("Reading structure out of file bounds"));
50 TEST(DXCFile, ParseHeader) {
51 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
54 0x70, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
55 DXContainer C =
56 llvm::cantFail(DXContainer::create(getMemoryBuffer<32>(Buffer)));
57 EXPECT_TRUE(memcmp(C.getHeader().Magic, "DXBC", 4) == 0);
58 EXPECT_TRUE(memcmp(C.getHeader().FileHash.Digest,
59 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0);
60 EXPECT_EQ(C.getHeader().Version.Major, 1u);
61 EXPECT_EQ(C.getHeader().Version.Minor, 0u);
64 TEST(DXCFile, ParsePartMissingOffsets) {
65 uint8_t Buffer[] = {
66 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
68 0x00, 0x00, 0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
70 EXPECT_THAT_EXPECTED(
71 DXContainer::create(getMemoryBuffer<32>(Buffer)),
72 FailedWithMessage("Reading structure out of file bounds"));
75 TEST(DXCFile, ParsePartInvalidOffsets) {
76 // This test covers a case where the part offset is beyond the buffer size.
77 uint8_t Buffer[] = {
78 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
80 0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
82 EXPECT_THAT_EXPECTED(
83 DXContainer::create(getMemoryBuffer<36>(Buffer)),
84 FailedWithMessage("Part offset points beyond boundary of the file"));
87 TEST(DXCFile, ParsePartTooSmallBuffer) {
88 // This test covers a case where there is insufficent space to read a full
89 // part name, but the offset for the part is inside the buffer.
90 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
93 0x26, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
94 0x24, 0x00, 0x00, 0x00, 0x46, 0x4B};
95 EXPECT_THAT_EXPECTED(
96 DXContainer::create(getMemoryBuffer<38>(Buffer)),
97 FailedWithMessage("File not large enough to read part name"));
100 TEST(DXCFile, ParsePartNoSize) {
101 // This test covers a case where the part's header is readable, but the size
102 // the part extends beyond the boundaries of the file.
103 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x0D, 0x00,
106 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
107 0x46, 0x4B, 0x45, 0x30, 0x00, 0x00};
108 EXPECT_THAT_EXPECTED(
109 DXContainer::create(getMemoryBuffer<42>(Buffer)),
110 FailedWithMessage("Reading part size out of file bounds"));
113 TEST(DXCFile, ParseOverlappingParts) {
114 // This test covers a case where a part's offset is inside the size range
115 // covered by the previous part.
116 uint8_t Buffer[] = {
117 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
119 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
120 0x2C, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x30, 0x08, 0x00, 0x00, 0x00,
121 0x46, 0x4B, 0x45, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 EXPECT_THAT_EXPECTED(
124 DXContainer::create(getMemoryBuffer<60>(Buffer)),
125 FailedWithMessage(
126 "Part offset for part 1 begins before the previous part ends"));
129 TEST(DXCFile, ParseEmptyParts) {
130 uint8_t Buffer[] = {
131 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
133 0x70, 0x0D, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
134 0x44, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
135 0x5C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
136 0x46, 0x4B, 0x45, 0x30, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x31,
137 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x32, 0x00, 0x00, 0x00, 0x00,
138 0x46, 0x4B, 0x45, 0x33, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x34,
139 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x35, 0x00, 0x00, 0x00, 0x00,
140 0x46, 0x4B, 0x45, 0x36, 0x00, 0x00, 0x00, 0x00,
142 DXContainer C =
143 llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
144 EXPECT_EQ(C.getHeader().PartCount, 7u);
146 // All the part sizes are 0, which makes a nice test of the range based for
147 int ElementsVisited = 0;
148 for (auto Part : C) {
149 EXPECT_EQ(Part.Part.Size, 0u);
150 EXPECT_EQ(Part.Data.size(), 0u);
151 ++ElementsVisited;
153 EXPECT_EQ(ElementsVisited, 7);
156 // These are all intended to be fake part names so that the parser doesn't
157 // try to parse the part data.
158 auto It = C.begin();
159 EXPECT_TRUE(memcmp(It->Part.Name, "FKE0", 4) == 0);
160 ++It;
161 EXPECT_TRUE(memcmp(It->Part.Name, "FKE1", 4) == 0);
162 ++It;
163 EXPECT_TRUE(memcmp(It->Part.Name, "FKE2", 4) == 0);
164 ++It;
165 EXPECT_TRUE(memcmp(It->Part.Name, "FKE3", 4) == 0);
166 ++It;
167 EXPECT_TRUE(memcmp(It->Part.Name, "FKE4", 4) == 0);
168 ++It;
169 EXPECT_TRUE(memcmp(It->Part.Name, "FKE5", 4) == 0);
170 ++It;
171 EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
172 ++It; // Don't increment past the end
173 EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
177 static Expected<DXContainer>
178 generateDXContainer(StringRef Yaml, SmallVectorImpl<char> &BinaryData) {
179 DXContainerYAML::Object Obj;
180 SMDiagnostic GenerateDiag;
181 yaml::Input YIn(
182 Yaml, /*Ctxt=*/nullptr,
183 [](const SMDiagnostic &Diag, void *DiagContext) {
184 *static_cast<SMDiagnostic *>(DiagContext) = Diag;
186 &GenerateDiag);
188 YIn >> Obj;
189 if (YIn.error())
190 return createStringError(YIn.error(), GenerateDiag.getMessage());
192 raw_svector_ostream OS(BinaryData);
193 std::string ErrorMsg;
194 if (!yaml::yaml2dxcontainer(
195 Obj, OS, [&ErrorMsg](const Twine &Msg) { ErrorMsg = Msg.str(); }))
196 return createStringError(YIn.error(), ErrorMsg);
198 MemoryBufferRef BinaryDataRef = MemoryBufferRef(OS.str(), "");
200 return DXContainer::create(BinaryDataRef);
203 TEST(DXCFile, PSVResourceIterators) {
204 const char *Yaml = R"(
205 --- !dxcontainer
206 Header:
207 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
208 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
209 Version:
210 Major: 1
211 Minor: 0
212 PartCount: 2
213 Parts:
214 - Name: PSV0
215 Size: 144
216 PSVInfo:
217 Version: 0
218 ShaderStage: 14
219 PayloadSizeInBytes: 4092
220 MinimumWaveLaneCount: 0
221 MaximumWaveLaneCount: 4294967295
222 ResourceStride: 16
223 Resources:
224 - Type: 1
225 Space: 1
226 LowerBound: 1
227 UpperBound: 1
228 - Type: 2
229 Space: 2
230 LowerBound: 2
231 UpperBound: 2
232 - Type: 3
233 Space: 3
234 LowerBound: 3
235 UpperBound: 3
236 - Name: DXIL
237 Size: 24
238 Program:
239 MajorVersion: 6
240 MinorVersion: 0
241 ShaderKind: 14
242 Size: 6
243 DXILMajorVersion: 0
244 DXILMinorVersion: 1
245 DXILSize: 0
249 SmallVector<char, 256> BinaryData;
250 auto C = generateDXContainer(Yaml, BinaryData);
252 ASSERT_THAT_EXPECTED(C, Succeeded());
254 const auto &PSVInfo = C->getPSVInfo();
255 ASSERT_TRUE(PSVInfo.has_value());
257 EXPECT_EQ(PSVInfo->getResourceCount(), 3u);
259 auto It = PSVInfo->getResources().begin();
261 EXPECT_TRUE(It == PSVInfo->getResources().begin());
263 dxbc::PSV::v2::ResourceBindInfo Binding;
265 Binding = *It;
266 EXPECT_EQ(Binding.Type, 1u);
267 EXPECT_EQ(Binding.Flags, 0u);
269 ++It;
270 Binding = *It;
272 EXPECT_EQ(Binding.Type, 2u);
273 EXPECT_EQ(Binding.Flags, 0u);
275 --It;
276 Binding = *It;
278 EXPECT_TRUE(It == PSVInfo->getResources().begin());
280 EXPECT_EQ(Binding.Type, 1u);
281 EXPECT_EQ(Binding.Flags, 0u);
283 --It;
284 Binding = *It;
286 EXPECT_EQ(Binding.Type, 1u);
287 EXPECT_EQ(Binding.Flags, 0u);
289 ++It;
290 Binding = *It;
292 EXPECT_EQ(Binding.Type, 2u);
293 EXPECT_EQ(Binding.Flags, 0u);
295 ++It;
296 Binding = *It;
298 EXPECT_EQ(Binding.Type, 3u);
299 EXPECT_EQ(Binding.Flags, 0u);
301 EXPECT_FALSE(It == PSVInfo->getResources().end());
303 ++It;
304 Binding = *It;
306 EXPECT_TRUE(It == PSVInfo->getResources().end());
307 EXPECT_FALSE(It != PSVInfo->getResources().end());
309 EXPECT_EQ(Binding.Type, 0u);
310 EXPECT_EQ(Binding.Flags, 0u);
313 auto Old = It++;
314 Binding = *Old;
316 EXPECT_TRUE(Old == PSVInfo->getResources().end());
317 EXPECT_FALSE(Old != PSVInfo->getResources().end());
319 EXPECT_EQ(Binding.Type, 0u);
320 EXPECT_EQ(Binding.Flags, 0u);
323 Binding = *It;
325 EXPECT_TRUE(It == PSVInfo->getResources().end());
327 EXPECT_EQ(Binding.Type, 0u);
328 EXPECT_EQ(Binding.Flags, 0u);
331 auto Old = It--;
332 Binding = *Old;
333 EXPECT_TRUE(Old == PSVInfo->getResources().end());
335 EXPECT_EQ(Binding.Type, 0u);
336 EXPECT_EQ(Binding.Flags, 0u);
339 Binding = *It;
341 EXPECT_EQ(Binding.Type, 3u);
342 EXPECT_EQ(Binding.Flags, 0u);
345 // The malicious file bits in these tests are mutations of the binary produced
346 // by the following YAML:
348 // --- !dxcontainer
349 // Header:
350 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
351 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
352 // Version:
353 // Major: 1
354 // Minor: 0
355 // PartCount: 3
356 // Parts:
357 // - Name: DXIL
358 // Size: 24
359 // Program:
360 // MajorVersion: 6
361 // MinorVersion: 0
362 // ShaderKind: 14
363 // Size: 6
364 // DXILMajorVersion: 0
365 // DXILMinorVersion: 1
366 // DXILSize: 0
367 // - Name: PSV0
368 // Size: 36
369 // PSVInfo:
370 // Version: 0
371 // ShaderStage: 5
372 // MinimumWaveLaneCount: 0
373 // MaximumWaveLaneCount: 0
374 // ResourceStride: 16
375 // Resources: []
376 // - Name: BLEH
377 // Size: 16
378 // ...
380 TEST(DXCFile, MaliciousFiles) {
382 // In this file blob, the file size is specified as 96 bytes (0x60), and the
383 // PSV0 data is specified as 24 bytes (0x18) which extends beyond the size of
384 // the file.
386 uint8_t Buffer[] = {
387 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
389 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
390 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
391 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
392 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 EXPECT_THAT_EXPECTED(
397 DXContainer::create(getMemoryBuffer<96>(Buffer)),
398 FailedWithMessage(
399 "Pipeline state data extends beyond the bounds of the part"));
402 // PSV extends beyond part, but in file range. In this blob the file size is
403 // 144 bytes (0x90), and the PSV part is 36 bytes (0x24), and the PSV data is
404 // 40 bytes (0x40).
406 uint8_t Buffer[] = {
407 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
409 0x90, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
410 0x4C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
411 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00,
412 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
413 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00,
414 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
417 0x42, 0x4C, 0x45, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420 EXPECT_THAT_EXPECTED(
421 DXContainer::create(getMemoryBuffer<144>(Buffer)),
422 FailedWithMessage(
423 "Pipeline state data extends beyond the bounds of the part"));
426 // In this file blob, the file is 116 bytes (0x74). The file structure is
427 // valid except that it specifies 1 16 byte resource binding which would
428 // extend beyond the range of the part and file.
430 uint8_t Buffer[] = {
431 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
433 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
434 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
435 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
436 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
437 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
438 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
439 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
442 EXPECT_THAT_EXPECTED(
443 DXContainer::create(getMemoryBuffer<116>(Buffer)),
444 FailedWithMessage(
445 "Resource binding data extends beyond the bounds of the part"));
448 // In this file blob, the file is 116 bytes (0x74). The file structure is
449 // valid except that it specifies 1 16 byte resource binding which would
450 // extend beyond the range of the part and into the `BLEH` part.
452 uint8_t Buffer[] = {
453 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
455 0x90, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
456 0x4C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
457 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00,
458 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
459 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00,
460 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
463 0x42, 0x4C, 0x45, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466 EXPECT_THAT_EXPECTED(
467 DXContainer::create(getMemoryBuffer<144>(Buffer)),
468 FailedWithMessage(
469 "Resource binding data extends beyond the bounds of the part"));
473 // This test verifies that the resource iterator follows the stride even if the
474 // stride doesn't match an expected or known value. In this test, the resource
475 // data is structured validly, with 32 bytes per resource. This test is based on
476 // editing the binary output constructed from this yaml.
478 // --- !dxcontainer
479 // Header:
480 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
481 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
482 // Version:
483 // Major: 1
484 // Minor: 0
485 // PartCount: 2
486 // Parts:
487 // - Name: DXIL
488 // Size: 24
489 // Program:
490 // MajorVersion: 6
491 // MinorVersion: 0
492 // ShaderKind: 14
493 // Size: 6
494 // DXILMajorVersion: 0
495 // DXILMinorVersion: 1
496 // DXILSize: 0
497 // - Name: PSV0
498 // Size: 100
499 // PSVInfo:
500 // Version: 0
501 // ShaderStage: 5
502 // MinimumWaveLaneCount: 0
503 // MaximumWaveLaneCount: 0
504 // ResourceStride: 16
505 // Resources:
506 // - Type: 1
507 // Space: 2
508 // LowerBound: 3
509 // UpperBound: 4
510 // - Type: 5
511 // Space: 6
512 // LowerBound: 7
513 // UpperBound: 8
514 // ...
515 TEST(DXCFile, PSVResourceIteratorsStride) {
516 uint8_t Buffer[] = {
517 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
519 0x28, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
520 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00,
521 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x64, 0x00, 0x00, 0x00,
522 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
524 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
525 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
527 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528 0x00, 0x00, 0x00, 0x00,
530 DXContainer C =
531 llvm::cantFail(DXContainer::create(getMemoryBuffer<180>(Buffer)));
533 const auto &PSVInfo = C.getPSVInfo();
534 ASSERT_TRUE(PSVInfo.has_value());
536 ASSERT_EQ(PSVInfo->getResourceCount(), 2u);
538 auto It = PSVInfo->getResources().begin();
540 EXPECT_TRUE(It == PSVInfo->getResources().begin());
542 dxbc::PSV::v2::ResourceBindInfo Binding;
544 Binding = *It;
545 EXPECT_EQ(Binding.Type, 1u);
546 EXPECT_EQ(Binding.Space, 2u);
547 EXPECT_EQ(Binding.LowerBound, 3u);
548 EXPECT_EQ(Binding.UpperBound, 4u);
550 ++It;
551 Binding = *It;
553 EXPECT_EQ(Binding.Type, 5u);
554 EXPECT_EQ(Binding.Space, 6u);
555 EXPECT_EQ(Binding.LowerBound, 7u);
556 EXPECT_EQ(Binding.UpperBound, 8u);
558 --It;
559 Binding = *It;
561 EXPECT_TRUE(It == PSVInfo->getResources().begin());
563 EXPECT_EQ(Binding.Type, 1u);
564 EXPECT_EQ(Binding.Space, 2u);
565 EXPECT_EQ(Binding.LowerBound, 3u);
566 EXPECT_EQ(Binding.UpperBound, 4u);
568 --It;
569 Binding = *It;
571 EXPECT_EQ(Binding.Type, 1u);
572 EXPECT_EQ(Binding.Space, 2u);
573 EXPECT_EQ(Binding.LowerBound, 3u);
574 EXPECT_EQ(Binding.UpperBound, 4u);
576 ++It;
577 Binding = *It;
579 EXPECT_EQ(Binding.Type, 5u);
580 EXPECT_EQ(Binding.Space, 6u);
581 EXPECT_EQ(Binding.LowerBound, 7u);
582 EXPECT_EQ(Binding.UpperBound, 8u);;
585 EXPECT_FALSE(It == PSVInfo->getResources().end());
587 ++It;
588 Binding = *It;
590 EXPECT_TRUE(It == PSVInfo->getResources().end());
591 EXPECT_FALSE(It != PSVInfo->getResources().end());
593 EXPECT_EQ(Binding.Type, 0u);
594 EXPECT_EQ(Binding.Flags, 0u);
597 // This test binary is created using mutations of the yaml in the SigElements
598 // test found under test/ObjectYAML/DXContainer/SigElements.yaml.
600 TEST(DXCFile, MisalignedStringTable) {
601 uint8_t Buffer[] = {
602 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
604 0xb4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
605 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x18, 0x00, 0x00, 0x00,
606 0x60, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
607 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x50, 0x53, 0x56, 0x30, 0x68, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
611 0x05, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x10, 0x20, 0x40,
612 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
616 EXPECT_THAT_EXPECTED(DXContainer::create(getMemoryBuffer<168>(Buffer)),
617 FailedWithMessage("String table misaligned"));
620 // This test binary is created using mutations of the yaml in the SigElements
621 // test found under test/ObjectYAML/DXContainer/SigElements.yaml.
622 TEST(DXCFile, SigElementsExtendBeyondPart) {
623 uint8_t Buffer[] = {
624 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
626 0xb4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
627 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x18, 0x00, 0x00, 0x00,
628 0x60, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
629 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x50, 0x53, 0x56, 0x30, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
633 0x05, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x08, 0x10, 0x20, 0x40,
634 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x00,
635 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
636 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x02, 0x00, 0x42, 0x00, 0x02, 0x00, 0x03, 0x00};
638 EXPECT_THAT_EXPECTED(
639 DXContainer::create(getMemoryBuffer<164>(Buffer)),
640 FailedWithMessage(
641 "Signature elements extend beyond the size of the part"));
644 TEST(DXCFile, MalformedSignature) {
646 The tests here exercise the DXContainer Signature section parser. These tests
647 are based on modifying the binary described by the following yaml:
649 --- !dxcontainer
650 Header:
651 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
652 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
653 Version:
654 Major: 1
655 Minor: 0
656 FileSize: 128
657 PartCount: 1
658 PartOffsets: [ 64 ]
659 Parts:
660 - Name: ISG1
661 Size: 52
662 Signature:
663 Parameters:
664 - Stream: 0
665 Name: AAA
666 Index: 0
667 SystemValue: Undefined
668 CompType: Float32
669 Register: 0
670 Mask: 7
671 ExclusiveMask: 2
672 MinPrecision: Default
675 The unmodified hex sequence is:
677 uint8_t Buffer[] = {
678 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80,
680 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00,
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
694 // This binary says the signature has 10 parameters, but the part data is
695 // only big enough for 1.
696 uint8_t Buffer[] = {
697 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
699 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
703 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
706 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
707 0x00, 0x00, 0x00, 0x00};
708 EXPECT_THAT_EXPECTED(
709 DXContainer::create(getMemoryBuffer<164>(Buffer)),
710 FailedWithMessage(
711 "Signature parameters extend beyond the part boundary"));
716 // This binary only has one parameter, but the start offset is beyond the
717 // size of the part.
718 uint8_t Buffer[] = {
719 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
721 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
725 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
726 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
727 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
728 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
729 0x00, 0x00, 0x00, 0x00};
730 EXPECT_THAT_EXPECTED(
731 DXContainer::create(getMemoryBuffer<164>(Buffer)),
732 FailedWithMessage(
733 "Signature parameters extend beyond the part boundary"));
738 // This parameter has a name offset of 3, which is before the start of the
739 // string table.
740 uint8_t Buffer[] = {
741 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
743 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
746 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
747 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00};
752 EXPECT_THAT_EXPECTED(
753 DXContainer::create(getMemoryBuffer<164>(Buffer)),
754 FailedWithMessage("Invalid parameter name offset: name starts before "
755 "the first name offset"));
759 // This parameter has a name offset of 255, which is after the end of the
760 // part.
761 uint8_t Buffer[] = {
762 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
764 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
768 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
771 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x00, 0x00, 0x00};
773 EXPECT_THAT_EXPECTED(
774 DXContainer::create(getMemoryBuffer<164>(Buffer)),
775 FailedWithMessage("Invalid parameter name offset: name starts after "
776 "the end of the part data"));