1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief SPIR-V Assembly Tests for Integer Types
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSpvAsmTypeTests.hpp"
25
26 #include "tcuRGBA.hpp"
27 #include "tcuStringTemplate.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkMemUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vktTestCase.hpp"
35
36 #include "deStringUtil.hpp"
37
38 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
39 #include "vktSpvAsmComputeShaderCase.hpp"
40 #include "vktSpvAsmComputeShaderTestUtil.hpp"
41 #include "vktTestGroupUtil.hpp"
42 #include "spirv/unified1/spirv.h"
43 #include "spirv/unified1/GLSL.std.450.h"
44
45 #include <cmath>
46
47 #define TEST_DATASET_SIZE 10
48
49 #define UNDEFINED_SPIRV_TEST_TYPE "testtype"
50
51 namespace de
52 {
53 // Specialize template to have output as integers instead of chars
54 template <>
toString(const int8_t & value)55 inline std::string toString<int8_t>(const int8_t &value)
56 {
57 std::ostringstream s;
58 s << static_cast<int32_t>(value);
59 return s.str();
60 }
61
62 template <>
toString(const uint8_t & value)63 inline std::string toString<uint8_t>(const uint8_t &value)
64 {
65 std::ostringstream s;
66 s << static_cast<uint32_t>(value);
67 return s.str();
68 }
69 } // namespace de
70
71 namespace vkt
72 {
73 namespace SpirVAssembly
74 {
75
76 using namespace vk;
77 using std::map;
78 using std::string;
79 using std::vector;
80 using tcu::RGBA;
81 using tcu::StringTemplate;
82
createComputeTest(ComputeShaderSpec & computeResources,const tcu::StringTemplate & shaderTemplate,const map<string,string> & fragments,tcu::TestCaseGroup & group,const std::string & namePrefix)83 void createComputeTest(ComputeShaderSpec &computeResources, const tcu::StringTemplate &shaderTemplate,
84 const map<string, string> &fragments, tcu::TestCaseGroup &group, const std::string &namePrefix)
85 {
86 const string testName = namePrefix + "_comp";
87
88 computeResources.assembly = shaderTemplate.specialize(fragments);
89 computeResources.numWorkGroups = tcu::IVec3(1, 1, 1);
90
91 group.addChild(new SpvAsmComputeShaderCase(group.getTestContext(), testName.c_str(), computeResources));
92 }
93
94 // The compute shader switch tests output a single 32-bit integer.
verifyComputeSwitchResult(const vector<Resource> &,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,tcu::TestLog & log)95 bool verifyComputeSwitchResult(const vector<Resource> &, const vector<AllocationSp> &outputAllocations,
96 const vector<Resource> &expectedOutputs, tcu::TestLog &log)
97 {
98 DE_ASSERT(outputAllocations.size() == 1);
99 DE_ASSERT(expectedOutputs.size() == 1);
100
101 vector<uint8_t> expectedBytes;
102 expectedOutputs[0].getBytes(expectedBytes);
103 DE_ASSERT(expectedBytes.size() == sizeof(int32_t));
104
105 const int32_t *obtained = reinterpret_cast<const int32_t *>(outputAllocations[0]->getHostPtr());
106 const int32_t *expected = reinterpret_cast<const int32_t *>(expectedBytes.data());
107
108 if (*obtained != *expected)
109 {
110 log << tcu::TestLog::Message << "Error: found unexpected result for compute switch: expected " << *expected
111 << ", obtained " << *obtained << tcu::TestLog::EndMessage;
112 return false;
113 }
114
115 return true;
116 }
117
118 enum InputRange
119 {
120 RANGE_FULL = 0,
121 RANGE_BIT_WIDTH,
122 RANGE_BIT_WIDTH_SUM,
123
124 RANGE_LAST
125 };
126
127 enum InputWidth
128 {
129 WIDTH_DEFAULT = 0,
130 WIDTH_8,
131 WIDTH_16,
132 WIDTH_32,
133 WIDTH_64,
134 WIDTH_8_8,
135 WIDTH_8_16,
136 WIDTH_8_32,
137 WIDTH_8_64,
138 WIDTH_16_8,
139 WIDTH_16_16,
140 WIDTH_16_32,
141 WIDTH_16_64,
142 WIDTH_32_8,
143 WIDTH_32_16,
144 WIDTH_32_32,
145 WIDTH_32_64,
146 WIDTH_64_8,
147 WIDTH_64_16,
148 WIDTH_64_32,
149 WIDTH_64_64,
150
151 WIDTH_LAST
152 };
153
154 enum InputType
155 {
156 TYPE_I8 = 0,
157 TYPE_U8,
158 TYPE_I16,
159 TYPE_U16,
160 TYPE_I32,
161 TYPE_U32,
162 TYPE_I64,
163 TYPE_U64,
164
165 TYPE_LAST
166 };
167
getConstituentIndex(uint32_t ndx,uint32_t vectorSize)168 uint32_t getConstituentIndex(uint32_t ndx, uint32_t vectorSize)
169 {
170 DE_ASSERT(vectorSize != 0u);
171 return (ndx / vectorSize) / (1u + (ndx % vectorSize));
172 }
173
isScalarInput(uint32_t spirvOperation,uint32_t numInput)174 bool isScalarInput(uint32_t spirvOperation, uint32_t numInput)
175 {
176 switch (spirvOperation)
177 {
178 case SpvOpBitFieldInsert:
179 return (numInput > 1);
180 case SpvOpBitFieldSExtract:
181 return (numInput > 0);
182 case SpvOpBitFieldUExtract:
183 return (numInput > 0);
184 default:
185 return false;
186 }
187 }
188
isBooleanResultTest(uint32_t spirvOperation)189 bool isBooleanResultTest(uint32_t spirvOperation)
190 {
191 switch (spirvOperation)
192 {
193 case SpvOpIEqual:
194 return true;
195 case SpvOpINotEqual:
196 return true;
197 case SpvOpUGreaterThan:
198 return true;
199 case SpvOpSGreaterThan:
200 return true;
201 case SpvOpUGreaterThanEqual:
202 return true;
203 case SpvOpSGreaterThanEqual:
204 return true;
205 case SpvOpULessThan:
206 return true;
207 case SpvOpSLessThan:
208 return true;
209 case SpvOpULessThanEqual:
210 return true;
211 case SpvOpSLessThanEqual:
212 return true;
213 default:
214 return false;
215 }
216 }
217
isConstantOrVariableTest(uint32_t spirvOperation)218 bool isConstantOrVariableTest(uint32_t spirvOperation)
219 {
220 switch (spirvOperation)
221 {
222 case SpvOpConstantNull:
223 return true;
224 case SpvOpConstant:
225 return true;
226 case SpvOpConstantComposite:
227 return true;
228 case SpvOpVariable:
229 return true;
230 case SpvOpSpecConstant:
231 return true;
232 case SpvOpSpecConstantComposite:
233 return true;
234 default:
235 return false;
236 }
237 }
238
getSpvOperationStr(uint32_t spirvOperation)239 const char *getSpvOperationStr(uint32_t spirvOperation)
240 {
241 switch (spirvOperation)
242 {
243 case SpvOpSNegate:
244 return "OpSNegate";
245 case SpvOpIAdd:
246 return "OpIAdd";
247 case SpvOpISub:
248 return "OpISub";
249 case SpvOpIMul:
250 return "OpIMul";
251 case SpvOpSDiv:
252 return "OpSDiv";
253 case SpvOpUDiv:
254 return "OpUDiv";
255 case SpvOpSRem:
256 return "OpSRem";
257 case SpvOpSMod:
258 return "OpSMod";
259 case SpvOpUMod:
260 return "OpUMod";
261 case SpvOpShiftRightLogical:
262 return "OpShiftRightLogical";
263 case SpvOpShiftRightArithmetic:
264 return "OpShiftRightArithmetic";
265 case SpvOpShiftLeftLogical:
266 return "OpShiftLeftLogical";
267 case SpvOpBitwiseOr:
268 return "OpBitwiseOr";
269 case SpvOpBitwiseXor:
270 return "OpBitwiseXor";
271 case SpvOpBitwiseAnd:
272 return "OpBitwiseAnd";
273 case SpvOpNot:
274 return "OpNot";
275 case SpvOpIEqual:
276 return "OpIEqual";
277 case SpvOpINotEqual:
278 return "OpINotEqual";
279 case SpvOpUGreaterThan:
280 return "OpUGreaterThan";
281 case SpvOpSGreaterThan:
282 return "OpSGreaterThan";
283 case SpvOpUGreaterThanEqual:
284 return "OpUGreaterThanEqual";
285 case SpvOpSGreaterThanEqual:
286 return "OpSGreaterThanEqual";
287 case SpvOpULessThan:
288 return "OpULessThan";
289 case SpvOpSLessThan:
290 return "OpSLessThan";
291 case SpvOpULessThanEqual:
292 return "OpULessThanEqual";
293 case SpvOpSLessThanEqual:
294 return "OpSLessThanEqual";
295 case SpvOpBitFieldInsert:
296 return "OpBitFieldInsert";
297 case SpvOpBitFieldSExtract:
298 return "OpBitFieldSExtract";
299 case SpvOpBitFieldUExtract:
300 return "OpBitFieldUExtract";
301 case SpvOpBitReverse:
302 return "OpBitReverse";
303 case SpvOpBitCount:
304 return "OpBitCount";
305 case SpvOpConstant:
306 return "OpConstant";
307 case SpvOpConstantComposite:
308 return "OpConstantComposite";
309 case SpvOpConstantNull:
310 return "OpConstantNull";
311 case SpvOpVariable:
312 return "OpVariable";
313 case SpvOpSpecConstant:
314 return "OpSpecConstant";
315 case SpvOpSpecConstantComposite:
316 return "OpSpecConstantComposite";
317 default:
318 return "";
319 }
320 }
321
getGLSLstd450OperationStr(uint32_t spirvOperation)322 const char *getGLSLstd450OperationStr(uint32_t spirvOperation)
323 {
324 switch (spirvOperation)
325 {
326 case GLSLstd450SAbs:
327 return "SAbs";
328 case GLSLstd450SSign:
329 return "SSign";
330 case GLSLstd450SMin:
331 return "SMin";
332 case GLSLstd450UMin:
333 return "UMin";
334 case GLSLstd450SMax:
335 return "SMax";
336 case GLSLstd450UMax:
337 return "UMax";
338 case GLSLstd450SClamp:
339 return "SClamp";
340 case GLSLstd450UClamp:
341 return "UClamp";
342 case GLSLstd450FindILsb:
343 return "FindILsb";
344 case GLSLstd450FindSMsb:
345 return "FindSMsb";
346 case GLSLstd450FindUMsb:
347 return "FindUMsb";
348 default:
349 DE_FATAL("Not implemented");
350 return "";
351 }
352 }
353
getBooleanResultType(uint32_t vectorSize)354 string getBooleanResultType(uint32_t vectorSize)
355 {
356 if (vectorSize > 1)
357 return "v" + de::toString(vectorSize) + "bool";
358 else
359 return "bool";
360 }
361
getInputWidth(InputWidth inputWidth,uint32_t ndx)362 uint32_t getInputWidth(InputWidth inputWidth, uint32_t ndx)
363 {
364 switch (inputWidth)
365 {
366 case WIDTH_8:
367 DE_ASSERT(ndx < 1);
368 return 8;
369 case WIDTH_16:
370 DE_ASSERT(ndx < 1);
371 return 16;
372 case WIDTH_32:
373 DE_ASSERT(ndx < 1);
374 return 32;
375 case WIDTH_64:
376 DE_ASSERT(ndx < 1);
377 return 64;
378 case WIDTH_8_8:
379 DE_ASSERT(ndx < 2);
380 return 8;
381 case WIDTH_8_16:
382 DE_ASSERT(ndx < 2);
383 return (ndx == 0) ? 8 : 16;
384 case WIDTH_8_32:
385 DE_ASSERT(ndx < 2);
386 return (ndx == 0) ? 8 : 32;
387 case WIDTH_8_64:
388 DE_ASSERT(ndx < 2);
389 return (ndx == 0) ? 8 : 64;
390 case WIDTH_16_8:
391 DE_ASSERT(ndx < 2);
392 return (ndx == 0) ? 16 : 8;
393 case WIDTH_16_16:
394 DE_ASSERT(ndx < 2);
395 return 16;
396 case WIDTH_16_32:
397 DE_ASSERT(ndx < 2);
398 return (ndx == 0) ? 16 : 32;
399 case WIDTH_16_64:
400 DE_ASSERT(ndx < 2);
401 return (ndx == 0) ? 16 : 64;
402 case WIDTH_32_8:
403 DE_ASSERT(ndx < 2);
404 return (ndx == 0) ? 32 : 8;
405 case WIDTH_32_16:
406 DE_ASSERT(ndx < 2);
407 return (ndx == 0) ? 32 : 16;
408 case WIDTH_32_32:
409 DE_ASSERT(ndx < 2);
410 return 32;
411 case WIDTH_32_64:
412 DE_ASSERT(ndx < 2);
413 return (ndx == 0) ? 32 : 64;
414 case WIDTH_64_8:
415 DE_ASSERT(ndx < 2);
416 return (ndx == 0) ? 64 : 8;
417 case WIDTH_64_16:
418 DE_ASSERT(ndx < 2);
419 return (ndx == 0) ? 64 : 16;
420 case WIDTH_64_32:
421 DE_ASSERT(ndx < 2);
422 return (ndx == 0) ? 64 : 32;
423 case WIDTH_64_64:
424 DE_ASSERT(ndx < 2);
425 return 64;
426 default:
427 DE_FATAL("Not implemented");
428 return 0;
429 }
430 }
431
has8BitInputWidth(InputWidth inputWidth)432 bool has8BitInputWidth(InputWidth inputWidth)
433 {
434 switch (inputWidth)
435 {
436 case WIDTH_8:
437 return true;
438 case WIDTH_16:
439 return false;
440 case WIDTH_32:
441 return false;
442 case WIDTH_64:
443 return false;
444 case WIDTH_8_8:
445 return true;
446 case WIDTH_8_16:
447 return true;
448 case WIDTH_8_32:
449 return true;
450 case WIDTH_8_64:
451 return true;
452 case WIDTH_16_8:
453 return true;
454 case WIDTH_16_16:
455 return false;
456 case WIDTH_16_32:
457 return false;
458 case WIDTH_16_64:
459 return false;
460 case WIDTH_32_8:
461 return true;
462 case WIDTH_32_16:
463 return false;
464 case WIDTH_32_32:
465 return false;
466 case WIDTH_32_64:
467 return false;
468 case WIDTH_64_8:
469 return true;
470 case WIDTH_64_16:
471 return false;
472 case WIDTH_64_32:
473 return false;
474 case WIDTH_64_64:
475 return false;
476 default:
477 return false;
478 }
479 }
480
has16BitInputWidth(InputWidth inputWidth)481 bool has16BitInputWidth(InputWidth inputWidth)
482 {
483 switch (inputWidth)
484 {
485 case WIDTH_8:
486 return false;
487 case WIDTH_16:
488 return true;
489 case WIDTH_32:
490 return false;
491 case WIDTH_64:
492 return false;
493 case WIDTH_8_8:
494 return false;
495 case WIDTH_8_16:
496 return true;
497 case WIDTH_8_32:
498 return false;
499 case WIDTH_8_64:
500 return false;
501 case WIDTH_16_8:
502 return true;
503 case WIDTH_16_16:
504 return true;
505 case WIDTH_16_32:
506 return true;
507 case WIDTH_16_64:
508 return true;
509 case WIDTH_32_8:
510 return false;
511 case WIDTH_32_16:
512 return true;
513 case WIDTH_32_32:
514 return false;
515 case WIDTH_32_64:
516 return false;
517 case WIDTH_64_8:
518 return false;
519 case WIDTH_64_16:
520 return true;
521 case WIDTH_64_32:
522 return false;
523 case WIDTH_64_64:
524 return false;
525 default:
526 return false;
527 }
528 }
529
has64BitInputWidth(InputWidth inputWidth)530 bool has64BitInputWidth(InputWidth inputWidth)
531 {
532 switch (inputWidth)
533 {
534 case WIDTH_8:
535 return false;
536 case WIDTH_16:
537 return false;
538 case WIDTH_32:
539 return false;
540 case WIDTH_64:
541 return true;
542 case WIDTH_8_8:
543 return false;
544 case WIDTH_8_16:
545 return false;
546 case WIDTH_8_32:
547 return false;
548 case WIDTH_8_64:
549 return true;
550 case WIDTH_16_8:
551 return false;
552 case WIDTH_16_16:
553 return false;
554 case WIDTH_16_32:
555 return false;
556 case WIDTH_16_64:
557 return true;
558 case WIDTH_32_8:
559 return false;
560 case WIDTH_32_16:
561 return false;
562 case WIDTH_32_32:
563 return false;
564 case WIDTH_32_64:
565 return true;
566 case WIDTH_64_8:
567 return true;
568 case WIDTH_64_16:
569 return true;
570 case WIDTH_64_32:
571 return true;
572 case WIDTH_64_64:
573 return true;
574 default:
575 return false;
576 }
577 }
578
getInputType(uint32_t inputWidth,bool isSigned)579 InputType getInputType(uint32_t inputWidth, bool isSigned)
580 {
581 switch (inputWidth)
582 {
583 case 8:
584 return (isSigned) ? TYPE_I8 : TYPE_U8;
585 case 16:
586 return (isSigned) ? TYPE_I16 : TYPE_U16;
587 case 32:
588 return (isSigned) ? TYPE_I32 : TYPE_U32;
589 case 64:
590 return (isSigned) ? TYPE_I64 : TYPE_U64;
591 default:
592 DE_FATAL("Not possible");
593 return TYPE_LAST;
594 }
595 }
596
getOtherSizeTypes(InputType inputType,uint32_t vectorSize,InputWidth inputWidth)597 string getOtherSizeTypes(InputType inputType, uint32_t vectorSize, InputWidth inputWidth)
598 {
599 const uint32_t inputWidthValues[] = {8, 16, 32, 64};
600
601 for (uint32_t widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(inputWidthValues); widthNdx++)
602 {
603 const uint32_t typeWidth = inputWidthValues[widthNdx];
604 const InputType typeUnsigned = getInputType(typeWidth, false);
605 const InputType typeSigned = getInputType(typeWidth, true);
606
607 if ((inputType == typeUnsigned) || (inputType == typeSigned))
608 {
609 const bool isSigned = (inputType == typeSigned);
610 const string signPrefix = (isSigned) ? "i" : "u";
611 const string signBit = (isSigned) ? "1" : "0";
612
613 string str = "";
614
615 if (has8BitInputWidth(inputWidth) && typeWidth != 8)
616 {
617 // 8-bit scalar type
618 str += "%" + signPrefix + "8 = OpTypeInt 8 " + signBit + "\n";
619
620 // 8-bit vector type
621 if (vectorSize > 1)
622 str += "%v" + de::toString(vectorSize) + signPrefix + "8 = OpTypeVector %" + signPrefix + "8 " +
623 de::toString(vectorSize) + "\n";
624 }
625
626 if (has16BitInputWidth(inputWidth) && typeWidth != 16)
627 {
628 // 16-bit scalar type
629 str += "%" + signPrefix + "16 = OpTypeInt 16 " + signBit + "\n";
630
631 // 16-bit vector type
632 if (vectorSize > 1)
633 str += "%v" + de::toString(vectorSize) + signPrefix + "16 = OpTypeVector %" + signPrefix + "16 " +
634 de::toString(vectorSize) + "\n";
635 }
636
637 if (has64BitInputWidth(inputWidth) && typeWidth != 64)
638 {
639 // 64-bit scalar type
640 str += "%" + signPrefix + "64 = OpTypeInt 64 " + signBit + "\n";
641
642 // 64-bit vector type
643 if (vectorSize > 1)
644 str += "%v" + de::toString(vectorSize) + signPrefix + "64 = OpTypeVector %" + signPrefix + "64 " +
645 de::toString(vectorSize) + "\n";
646 }
647
648 return str;
649 }
650 }
651
652 DE_FATAL("Not possible");
653 return "";
654 }
655
getSpirvCapabilityStr(const char * spirvCapability,InputWidth inputWidth)656 string getSpirvCapabilityStr(const char *spirvCapability, InputWidth inputWidth)
657 {
658 string str = "";
659
660 if (spirvCapability)
661 {
662 if (has8BitInputWidth(inputWidth) || deStringEqual("Int8", spirvCapability))
663 str += "OpCapability Int8\n";
664
665 if (has16BitInputWidth(inputWidth) || deStringEqual("Int16", spirvCapability))
666 str += "OpCapability Int16\n";
667
668 if (has64BitInputWidth(inputWidth) || deStringEqual("Int64", spirvCapability))
669 str += "OpCapability Int64\n";
670
671 if (deStringEqual("Int8", spirvCapability))
672 str += "OpCapability UniformAndStorageBuffer8BitAccess\n";
673
674 if (deStringEqual("Int16", spirvCapability))
675 str += "OpCapability UniformAndStorageBuffer16BitAccess\n";
676 }
677 else
678 {
679 if (has8BitInputWidth(inputWidth))
680 str += "OpCapability Int8\n";
681
682 if (has16BitInputWidth(inputWidth))
683 str += "OpCapability Int16\n";
684
685 if (has64BitInputWidth(inputWidth))
686 str += "OpCapability Int64\n";
687 }
688
689 return str;
690 }
691
getBinaryFullOperationWithInputWidthStr(string resultName,string spirvOperation,InputType inputType,string spirvTestType,uint32_t vectorSize,InputWidth inputWidth)692 string getBinaryFullOperationWithInputWidthStr(string resultName, string spirvOperation, InputType inputType,
693 string spirvTestType, uint32_t vectorSize, InputWidth inputWidth)
694 {
695 const uint32_t inputWidthValues[] = {8, 16, 32, 64};
696
697 for (uint32_t widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(inputWidthValues); widthNdx++)
698 {
699 const uint32_t typeWidth = inputWidthValues[widthNdx];
700 const InputType typeUnsigned = getInputType(typeWidth, false);
701 const InputType typeSigned = getInputType(typeWidth, true);
702
703 if ((inputType == typeUnsigned) || (inputType == typeSigned))
704 {
705 const bool isSigned = (inputType == typeSigned);
706 const string signPrefix = (isSigned) ? "i" : "u";
707 const string typePrefix = (vectorSize == 1) ? "%" : "%v" + de::toString(vectorSize);
708 const uint32_t input1Width = getInputWidth(inputWidth, 0);
709
710 const string inputTypeStr =
711 (input1Width == typeWidth) ? "%testtype" : typePrefix + signPrefix + de::toString(input1Width);
712
713 string str = "";
714
715 // Create intermediate value with different width
716 if (input1Width != typeWidth)
717 str += "%input1_val_" + de::toString(input1Width) + " = OpSConvert " + inputTypeStr + " %input1_val\n";
718
719 // Input with potentially different width
720 const string input1Str =
721 "%input1_val" + ((input1Width != typeWidth) ? "_" + de::toString(input1Width) : "");
722
723 str += resultName + " = " + spirvOperation + " %" + spirvTestType + " %input0_val " + input1Str + "\n";
724
725 return str;
726 }
727 }
728
729 DE_FATAL("Not possible");
730 return "";
731 }
732
getFullOperationWithDifferentInputWidthStr(string resultName,string spirvOperation,InputType inputType,string spirvTestType,InputWidth inputWidth,bool isQuaternary)733 string getFullOperationWithDifferentInputWidthStr(string resultName, string spirvOperation, InputType inputType,
734 string spirvTestType, InputWidth inputWidth, bool isQuaternary)
735 {
736 const bool isSigned = (inputType == TYPE_I32);
737
738 const uint32_t offsetWidth = getInputWidth(inputWidth, 0);
739 const uint32_t countWidth = getInputWidth(inputWidth, 1);
740
741 const string offsetType = ((isSigned) ? "i" : "u") + de::toString(offsetWidth);
742 const string countType = ((isSigned) ? "i" : "u") + de::toString(countWidth);
743
744 const string offsetNdx = (isQuaternary) ? "2" : "1";
745 const string countNdx = (isQuaternary) ? "3" : "2";
746
747 string str = "";
748
749 // Create intermediate values with different width
750 if (offsetWidth != 32)
751 str += "%input" + offsetNdx + "_val_" + de::toString(offsetWidth) + " = OpSConvert %" + offsetType + " %input" +
752 offsetNdx + "_val\n";
753 if (countWidth != 32)
754 str += "%input" + countNdx + "_val_" + de::toString(countWidth) + " = OpSConvert %" + countType + " %input" +
755 countNdx + "_val\n";
756
757 // Inputs with potentially different width
758 const string offsetStr =
759 "%input" + offsetNdx + "_val" + ((offsetWidth != 32) ? "_" + de::toString(offsetWidth) : "");
760 const string countStr = "%input" + countNdx + "_val" + ((countWidth != 32) ? "_" + de::toString(countWidth) : "");
761
762 if (isQuaternary)
763 str += resultName + " = " + spirvOperation + " %" + spirvTestType + " %input0_val %input1_val " + offsetStr +
764 " " + countStr + "\n";
765 else
766 str += resultName + " = " + spirvOperation + " %" + spirvTestType + " %input0_val " + offsetStr + " " +
767 countStr + "\n";
768
769 return str;
770 }
771
requiredFeaturesFromStrings(const std::vector<std::string> & features,VulkanFeatures & requestedFeatures)772 static inline void requiredFeaturesFromStrings(const std::vector<std::string> &features,
773 VulkanFeatures &requestedFeatures)
774 {
775 for (uint32_t featureNdx = 0; featureNdx < features.size(); ++featureNdx)
776 {
777 const std::string &feature = features[featureNdx];
778
779 if (feature == "shaderInt16")
780 requestedFeatures.coreFeatures.shaderInt16 = VK_TRUE;
781 else if (feature == "shaderInt64")
782 requestedFeatures.coreFeatures.shaderInt64 = VK_TRUE;
783 else
784 DE_ASSERT(0); // Not implemented. Don't add to here. Just use VulkanFeatures
785 }
786 }
787
788 template <class T>
789 class SpvAsmTypeTests : public tcu::TestCaseGroup
790 {
791 public:
792 typedef T (*OpUnaryFuncType)(T);
793 typedef T (*OpBinaryFuncType)(T, T);
794 typedef T (*OpTernaryFuncType)(T, T, T);
795 typedef T (*OpQuaternaryFuncType)(T, T, T, T);
796 typedef bool (*UnaryFilterFuncType)(T);
797 typedef bool (*BinaryFilterFuncType)(T, T);
798 typedef bool (*TernaryFilterFuncType)(T, T, T);
799 typedef bool (*QuaternaryFilterFuncType)(T, T, T, T);
800 SpvAsmTypeTests(tcu::TestContext &testCtx, const char *name, const char *deviceFeature, const char *spirvCapability,
801 const char *spirvType, InputType inputType, uint32_t typeSize, uint32_t vectorSize);
802 ~SpvAsmTypeTests(void);
803 void createTests(const char *testName, uint32_t spirvOperation, OpUnaryFuncType op, UnaryFilterFuncType filter,
804 InputRange inputRange, InputWidth inputWidth, const char *spirvExtension,
805 const bool returnHighPart = false);
806 void createTests(const char *testName, uint32_t spirvOperation, OpBinaryFuncType op, BinaryFilterFuncType filter,
807 InputRange inputRange, InputWidth inputWidth, const char *spirvExtension,
808 const bool returnHighPart = false);
809 void createTests(const char *testName, uint32_t spirvOperation, OpTernaryFuncType op, TernaryFilterFuncType filter,
810 InputRange inputRange, InputWidth inputWidth, const char *spirvExtension,
811 const bool returnHighPart = false);
812 void createTests(const char *testName, uint32_t spirvOperation, OpQuaternaryFuncType op,
813 QuaternaryFilterFuncType filter, InputRange inputRange, InputWidth inputWidth,
814 const char *spirvExtension, const bool returnHighPart = false);
815 void createSwitchTests(void);
816 void getConstantDataset(vector<T> inputDataset, vector<T> &outputDataset, uint32_t spirvOperation);
817 virtual void getDataset(vector<T> &input, uint32_t numElements) = 0;
818 virtual void pushResource(vector<Resource> &resource, const vector<T> &data) = 0;
819
820 static bool filterNone(T a);
821 static bool filterNone(T a, T b);
822 static bool filterNone(T a, T b, T c);
823 static bool filterNone(T a, T b, T c, T d);
824 static bool filterZero(T a, T b);
825 static bool filterNegativesAndZero(T a, T b);
826 static bool filterMinGtMax(T, T a, T b);
827
828 static T zero(T);
829 static T zero(T, T);
830 static T zero(T, T, T);
831 static T zero(T, T, T, T);
832
833 static string replicate(const std::string &replicant, const uint32_t count);
834
835 protected:
836 de::Random m_rnd;
837 T m_cases[3];
838
839 private:
840 std::string createInputDecoration(uint32_t numInput);
841 std::string createInputPreMain(uint32_t numInput, uint32_t spirvOpertaion);
842 std::string createConstantDeclaration(vector<T> &dataset, uint32_t spirvOperation);
843 std::string createInputTestfun(uint32_t numInput, uint32_t spirvOpertaion);
844 uint32_t combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
845 OpUnaryFuncType operation, UnaryFilterFuncType filter, InputRange inputRange);
846 uint32_t combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
847 OpBinaryFuncType operation, BinaryFilterFuncType filter, InputRange inputRange);
848 uint32_t combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
849 OpTernaryFuncType operation, TernaryFilterFuncType filter, InputRange inputRange);
850 uint32_t combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
851 OpQuaternaryFuncType operation, QuaternaryFilterFuncType filter, InputRange inputRange);
852 uint32_t fillResources(GraphicsResources &resources, ComputeShaderSpec &computeResources, const vector<T> &data);
853 void createStageTests(const char *testName, GraphicsResources &resources, ComputeShaderSpec &computeResources,
854 uint32_t numElements, vector<string> &decorations, vector<string> &pre_mains,
855 vector<string> &testfuns, string &operation, InputWidth inputWidth, const char *funVariables,
856 const char *spirvExtension = DE_NULL);
857 void finalizeFullOperation(string &fullOperation, const string &resultName, const bool returnHighPart,
858 const bool isBooleanResult);
859
860 static bool verifyResult(const vector<Resource> &inputs, const vector<AllocationSp> &outputAllocations,
861 const vector<Resource> &expectedOutputs, uint32_t skip, tcu::TestLog &log);
862 static bool verifyDefaultResult(const vector<Resource> &inputs, const vector<AllocationSp> &outputAllocations,
863 const vector<Resource> &expectedOutputs, tcu::TestLog &log);
864 static bool verifyVec3Result(const vector<Resource> &inputs, const vector<AllocationSp> &outputAllocations,
865 const vector<Resource> &expectedOutputs, tcu::TestLog &log);
866 const char *const m_deviceFeature;
867 const char *const m_spirvCapability;
868 const char *const m_spirvType;
869 InputType m_inputType;
870 uint32_t m_typeSize;
871 uint32_t m_vectorSize;
872 std::string m_spirvTestType;
873 };
874
875 template <class T>
SpvAsmTypeTests(tcu::TestContext & testCtx,const char * name,const char * deviceFeature,const char * spirvCapability,const char * spirvType,InputType inputType,uint32_t typeSize,uint32_t vectorSize)876 SpvAsmTypeTests<T>::SpvAsmTypeTests(tcu::TestContext &testCtx, const char *name, const char *deviceFeature,
877 const char *spirvCapability, const char *spirvType, InputType inputType,
878 uint32_t typeSize, uint32_t vectorSize)
879 : tcu::TestCaseGroup(testCtx, name)
880 , m_rnd(deStringHash(name))
881 , m_deviceFeature(deviceFeature)
882 , m_spirvCapability(spirvCapability)
883 , m_spirvType(spirvType)
884 , m_inputType(inputType)
885 , m_typeSize(typeSize)
886 , m_vectorSize(vectorSize)
887 {
888 std::string scalarType;
889
890 DE_ASSERT(vectorSize >= 1 && vectorSize <= 4);
891
892 if (m_inputType == TYPE_I32)
893 scalarType = "i32";
894 else if (m_inputType == TYPE_U32)
895 scalarType = "u32";
896 else
897 scalarType = "";
898
899 if (scalarType.empty())
900 {
901 m_spirvTestType = UNDEFINED_SPIRV_TEST_TYPE;
902 }
903 else
904 {
905 if (m_vectorSize > 1)
906 m_spirvTestType = "v" + de::toString(m_vectorSize) + scalarType;
907 else
908 m_spirvTestType = scalarType;
909 }
910 }
911
912 template <class T>
~SpvAsmTypeTests(void)913 SpvAsmTypeTests<T>::~SpvAsmTypeTests(void)
914 {
915 }
916
917 template <class T>
createInputDecoration(uint32_t numInput)918 std::string SpvAsmTypeTests<T>::createInputDecoration(uint32_t numInput)
919 {
920 const StringTemplate decoration("OpDecorate %input${n_input} DescriptorSet 0\n"
921 "OpDecorate %input${n_input} Binding ${n_input}\n");
922 map<string, string> specs;
923
924 specs["n_input"] = de::toString(numInput);
925
926 return decoration.specialize(specs);
927 }
928
929 template <class T>
createInputPreMain(uint32_t numInput,uint32_t spirvOpertaion)930 std::string SpvAsmTypeTests<T>::createInputPreMain(uint32_t numInput, uint32_t spirvOpertaion)
931 {
932 const bool scalarInput = (m_vectorSize != 1) && isScalarInput(spirvOpertaion, numInput);
933 const string bufferType = (scalarInput) ? "%scalarbufptr" : "%bufptr";
934
935 return "%input" + de::toString(numInput) + " = OpVariable " + bufferType + " Uniform\n";
936 }
937
938 template <class T>
createInputTestfun(uint32_t numInput,uint32_t spirvOpertaion)939 std::string SpvAsmTypeTests<T>::createInputTestfun(uint32_t numInput, uint32_t spirvOpertaion)
940 {
941 const bool scalarInput = (m_vectorSize != 1) && isScalarInput(spirvOpertaion, numInput);
942 const string pointerType = (scalarInput) ? "%up_scalartype" : "%up_testtype";
943 const string valueType = (scalarInput) ? "%u32" : "%${testtype}";
944
945 const StringTemplate testfun("%input${n_input}_loc = OpAccessChain " + pointerType +
946 " %input${n_input} "
947 "%c_i32_0 %counter_val\n"
948 "%input${n_input}_val = OpLoad " +
949 valueType + " %input${n_input}_loc\n");
950 map<string, string> specs;
951
952 specs["n_input"] = de::toString(numInput);
953 specs["testtype"] = m_spirvTestType;
954
955 return testfun.specialize(specs);
956 }
957
958 template <class T>
combine(GraphicsResources & resources,ComputeShaderSpec & computeResources,vector<T> & data,OpUnaryFuncType operation,UnaryFilterFuncType filter,InputRange inputRange)959 uint32_t SpvAsmTypeTests<T>::combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
960 OpUnaryFuncType operation, UnaryFilterFuncType filter, InputRange inputRange)
961 {
962 DE_UNREF(inputRange);
963 const uint32_t datasize = static_cast<uint32_t>(data.size());
964 const uint32_t sizeWithPadding = (m_vectorSize == 3) ? 4 : m_vectorSize;
965 const uint32_t totalPadding = (m_vectorSize == 3) ? (datasize / m_vectorSize) : 0;
966 const uint32_t total = datasize + totalPadding;
967 uint32_t padCount = m_vectorSize;
968 uint32_t outputsSize;
969 vector<T> inputs;
970 vector<T> outputs;
971
972 inputs.reserve(total);
973 outputs.reserve(total);
974
975 /* According to spec, a three-component vector, with components of size N,
976 has a base alignment of 4 N */
977 for (uint32_t elemNdx = 0; elemNdx < datasize; ++elemNdx)
978 {
979 if (filter(data[elemNdx]))
980 {
981 inputs.push_back(data[elemNdx]);
982 outputs.push_back(operation(data[elemNdx]));
983 if (m_vectorSize == 3)
984 {
985 padCount--;
986 if (padCount == 0)
987 {
988 inputs.push_back(0);
989 outputs.push_back(0);
990 padCount = m_vectorSize;
991 }
992 }
993 }
994 }
995
996 outputsSize = static_cast<uint32_t>(outputs.size());
997
998 /* Ensure we have pushed a multiple of vector size, including padding if
999 required */
1000 while (outputsSize % sizeWithPadding != 0)
1001 {
1002 inputs.pop_back();
1003 outputs.pop_back();
1004 outputsSize--;
1005 }
1006
1007 pushResource(resources.inputs, inputs);
1008 pushResource(resources.outputs, outputs);
1009
1010 pushResource(computeResources.inputs, inputs);
1011 pushResource(computeResources.outputs, outputs);
1012
1013 return outputsSize / sizeWithPadding;
1014 }
1015
1016 template <class T>
combine(GraphicsResources & resources,ComputeShaderSpec & computeResources,vector<T> & data,OpBinaryFuncType operation,BinaryFilterFuncType filter,InputRange inputRange)1017 uint32_t SpvAsmTypeTests<T>::combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
1018 OpBinaryFuncType operation, BinaryFilterFuncType filter, InputRange inputRange)
1019 {
1020 const uint32_t datasize = static_cast<uint32_t>(data.size());
1021 const uint32_t sizeWithPadding = (m_vectorSize == 3) ? 4 : m_vectorSize;
1022 const uint32_t totalData = datasize * datasize;
1023 const uint32_t totalPadding = (m_vectorSize == 3) ? (totalData / m_vectorSize) : 0;
1024 const uint32_t total = totalData + totalPadding;
1025 uint32_t padCount = m_vectorSize;
1026 uint32_t outputsSize;
1027 vector<T> inputs0;
1028 vector<T> inputs1;
1029 vector<T> outputs;
1030
1031 inputs0.reserve(total);
1032 inputs1.reserve(total);
1033 outputs.reserve(total);
1034
1035 /* According to spec, a three-component vector, with components of size N,
1036 has a base alignment of 4 N */
1037 for (uint32_t elemNdx1 = 0; elemNdx1 < datasize; ++elemNdx1)
1038 for (uint32_t elemNdx2 = 0; elemNdx2 < datasize; ++elemNdx2)
1039 {
1040 if (filter(data[elemNdx1], data[elemNdx2]))
1041 {
1042 switch (inputRange)
1043 {
1044 case RANGE_FULL:
1045 {
1046 inputs0.push_back(data[elemNdx1]);
1047 inputs1.push_back(data[elemNdx2]);
1048 outputs.push_back(operation(data[elemNdx1], data[elemNdx2]));
1049 break;
1050 }
1051 case RANGE_BIT_WIDTH:
1052 {
1053 // Make sure shift count doesn't exceed the bit width
1054 const T shift = data[elemNdx2] & static_cast<T>(m_typeSize - 1u);
1055 inputs0.push_back(data[elemNdx1]);
1056 inputs1.push_back(shift);
1057 outputs.push_back(operation(data[elemNdx1], shift));
1058 break;
1059 }
1060 default:
1061 DE_FATAL("Not implemented");
1062 }
1063
1064 if (m_vectorSize == 3)
1065 {
1066 padCount--;
1067 if (padCount == 0)
1068 {
1069 inputs0.push_back(0);
1070 inputs1.push_back(0);
1071 outputs.push_back(0);
1072 padCount = m_vectorSize;
1073 }
1074 }
1075 }
1076 }
1077
1078 outputsSize = static_cast<uint32_t>(outputs.size());
1079
1080 /* Ensure we have pushed a multiple of vector size, including padding if
1081 required */
1082 while (outputsSize % sizeWithPadding != 0)
1083 {
1084 inputs0.pop_back();
1085 inputs1.pop_back();
1086 outputs.pop_back();
1087 outputsSize--;
1088 }
1089
1090 pushResource(resources.inputs, inputs0);
1091 pushResource(resources.inputs, inputs1);
1092 pushResource(resources.outputs, outputs);
1093
1094 pushResource(computeResources.inputs, inputs0);
1095 pushResource(computeResources.inputs, inputs1);
1096 pushResource(computeResources.outputs, outputs);
1097
1098 return outputsSize / sizeWithPadding;
1099 }
1100
1101 template <class T>
combine(GraphicsResources & resources,ComputeShaderSpec & computeResources,vector<T> & data,OpTernaryFuncType operation,TernaryFilterFuncType filter,InputRange inputRange)1102 uint32_t SpvAsmTypeTests<T>::combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
1103 OpTernaryFuncType operation, TernaryFilterFuncType filter, InputRange inputRange)
1104 {
1105 const uint32_t datasize = static_cast<uint32_t>(data.size());
1106 const uint32_t sizeWithPadding = (m_vectorSize == 3) ? 4 : m_vectorSize;
1107 const uint32_t totalData = datasize * datasize * datasize;
1108 const uint32_t totalPadding = (m_vectorSize == 3) ? (totalData / m_vectorSize) : 0;
1109 const uint32_t total = totalData + totalPadding;
1110 uint32_t padCount = m_vectorSize;
1111 uint32_t outputsSize;
1112 vector<T> inputs0;
1113 vector<T> inputs1;
1114 vector<T> inputs2;
1115 vector<T> outputs;
1116
1117 inputs0.reserve(total);
1118 inputs1.reserve(total);
1119 inputs2.reserve(total);
1120 outputs.reserve(total);
1121
1122 // Reduce the amount of input data in tests without filtering
1123 uint32_t datasize2 = (inputRange == RANGE_BIT_WIDTH_SUM) ? 4u * m_vectorSize : datasize;
1124 T bitOffset = static_cast<T>(0);
1125 T bitCount = static_cast<T>(0);
1126
1127 /* According to spec, a three-component vector, with components of size N,
1128 has a base alignment of 4 N */
1129 for (uint32_t elemNdx1 = 0; elemNdx1 < datasize; ++elemNdx1)
1130 for (uint32_t elemNdx2 = 0; elemNdx2 < datasize2; ++elemNdx2)
1131 for (uint32_t elemNdx3 = 0; elemNdx3 < datasize2; ++elemNdx3)
1132 {
1133 if (filter(data[elemNdx1], data[elemNdx2], data[elemNdx3]))
1134 {
1135 switch (inputRange)
1136 {
1137 case RANGE_FULL:
1138 {
1139 inputs0.push_back(data[elemNdx1]);
1140 inputs1.push_back(data[elemNdx2]);
1141 inputs2.push_back(data[elemNdx3]);
1142 outputs.push_back(operation(data[elemNdx1], data[elemNdx2], data[elemNdx3]));
1143 break;
1144 }
1145 case RANGE_BIT_WIDTH_SUM:
1146 {
1147 if (elemNdx3 % m_vectorSize == 0)
1148 {
1149 bitOffset = static_cast<T>(m_rnd.getUint32() & (m_typeSize - 1u));
1150 bitCount = static_cast<T>(m_rnd.getUint32() & (m_typeSize - 1u));
1151 }
1152
1153 // Make sure the sum of offset and count doesn't exceed bit width
1154 if ((uint32_t)(bitOffset + bitCount) > m_typeSize)
1155 bitCount = static_cast<T>(m_typeSize - bitOffset);
1156
1157 inputs0.push_back(data[elemNdx1]);
1158 inputs1.push_back(bitOffset);
1159 inputs2.push_back(bitCount);
1160 outputs.push_back(operation(data[elemNdx1], bitOffset, bitCount));
1161 break;
1162 }
1163 default:
1164 DE_FATAL("Not implemented");
1165 }
1166 if (m_vectorSize == 3)
1167 {
1168 padCount--;
1169 if (padCount == 0)
1170 {
1171 inputs0.push_back(0);
1172 inputs1.push_back(0);
1173 inputs2.push_back(0);
1174 outputs.push_back(0);
1175 padCount = m_vectorSize;
1176 }
1177 }
1178 }
1179 }
1180 outputsSize = static_cast<uint32_t>(outputs.size());
1181
1182 /* Ensure we have pushed a multiple of vector size, including padding if
1183 required */
1184 while (outputsSize % sizeWithPadding != 0)
1185 {
1186 inputs0.pop_back();
1187 inputs1.pop_back();
1188 inputs2.pop_back();
1189 outputs.pop_back();
1190 outputsSize--;
1191 }
1192
1193 pushResource(resources.inputs, inputs0);
1194 pushResource(resources.inputs, inputs1);
1195 pushResource(resources.inputs, inputs2);
1196 pushResource(resources.outputs, outputs);
1197
1198 pushResource(computeResources.inputs, inputs0);
1199 pushResource(computeResources.inputs, inputs1);
1200 pushResource(computeResources.inputs, inputs2);
1201 pushResource(computeResources.outputs, outputs);
1202
1203 return outputsSize / sizeWithPadding;
1204 }
1205
1206 template <class T>
combine(GraphicsResources & resources,ComputeShaderSpec & computeResources,vector<T> & data,OpQuaternaryFuncType operation,QuaternaryFilterFuncType filter,InputRange inputRange)1207 uint32_t SpvAsmTypeTests<T>::combine(GraphicsResources &resources, ComputeShaderSpec &computeResources, vector<T> &data,
1208 OpQuaternaryFuncType operation, QuaternaryFilterFuncType filter,
1209 InputRange inputRange)
1210 {
1211 const uint32_t datasize = static_cast<uint32_t>(data.size());
1212 const uint32_t sizeWithPadding = (m_vectorSize == 3) ? 4 : m_vectorSize;
1213 const uint32_t totalData = datasize * datasize;
1214 const uint32_t totalPadding = (m_vectorSize == 3) ? (totalData / m_vectorSize) : 0;
1215 const uint32_t total = totalData + totalPadding;
1216 uint32_t padCount = m_vectorSize;
1217 uint32_t outputsSize;
1218 vector<T> inputs0;
1219 vector<T> inputs1;
1220 vector<T> inputs2;
1221 vector<T> inputs3;
1222 vector<T> outputs;
1223
1224 inputs0.reserve(total);
1225 inputs1.reserve(total);
1226 inputs2.reserve(total);
1227 inputs3.reserve(total);
1228 outputs.reserve(total);
1229
1230 // Reduce the amount of input data in tests without filtering
1231 uint32_t datasize2 = (inputRange == RANGE_BIT_WIDTH_SUM) ? 2u * m_vectorSize : datasize;
1232 T bitOffset = static_cast<T>(0);
1233 T bitCount = static_cast<T>(0);
1234
1235 /* According to spec, a three-component vector, with components of size N,
1236 has a base alignment of 4 N */
1237 for (uint32_t elemNdx1 = 0; elemNdx1 < datasize; ++elemNdx1)
1238 for (uint32_t elemNdx2 = 0; elemNdx2 < datasize2; ++elemNdx2)
1239 for (uint32_t elemNdx3 = 0; elemNdx3 < datasize2; ++elemNdx3)
1240 for (uint32_t elemNdx4 = 0; elemNdx4 < datasize2; ++elemNdx4)
1241 {
1242 if (filter(data[elemNdx1], data[elemNdx2], data[elemNdx3], data[elemNdx4]))
1243 {
1244 switch (inputRange)
1245 {
1246 case RANGE_FULL:
1247 {
1248 inputs0.push_back(data[elemNdx1]);
1249 inputs1.push_back(data[elemNdx2]);
1250 inputs2.push_back(data[elemNdx3]);
1251 inputs3.push_back(data[elemNdx3]);
1252 outputs.push_back(
1253 operation(data[elemNdx1], data[elemNdx2], data[elemNdx3], data[elemNdx4]));
1254 break;
1255 }
1256 case RANGE_BIT_WIDTH_SUM:
1257 {
1258 if (elemNdx4 % m_vectorSize == 0)
1259 {
1260 bitOffset = static_cast<T>(m_rnd.getUint32() & (m_typeSize - 1u));
1261 bitCount = static_cast<T>(m_rnd.getUint32() & (m_typeSize - 1u));
1262 }
1263
1264 // Make sure the sum of offset and count doesn't exceed bit width
1265 if ((uint32_t)(bitOffset + bitCount) > m_typeSize)
1266 bitCount -= bitOffset + bitCount - static_cast<T>(m_typeSize);
1267
1268 inputs0.push_back(data[elemNdx1]);
1269 inputs1.push_back(data[elemNdx2]);
1270 inputs2.push_back(bitOffset);
1271 inputs3.push_back(bitCount);
1272 outputs.push_back(operation(data[elemNdx1], data[elemNdx2], bitOffset, bitCount));
1273 break;
1274 }
1275 default:
1276 DE_FATAL("Not implemented");
1277 }
1278 if (m_vectorSize == 3)
1279 {
1280 padCount--;
1281 if (padCount == 0)
1282 {
1283 inputs0.push_back(0);
1284 inputs1.push_back(0);
1285 inputs2.push_back(0);
1286 inputs3.push_back(0);
1287 outputs.push_back(0);
1288 padCount = m_vectorSize;
1289 }
1290 }
1291 }
1292 }
1293
1294 outputsSize = static_cast<uint32_t>(outputs.size());
1295
1296 /* Ensure we have pushed a multiple of vector size, including padding if
1297 required */
1298 while (outputsSize % sizeWithPadding != 0)
1299 {
1300 inputs0.pop_back();
1301 inputs1.pop_back();
1302 inputs2.pop_back();
1303 inputs3.pop_back();
1304 outputs.pop_back();
1305 outputsSize--;
1306 }
1307
1308 pushResource(resources.inputs, inputs0);
1309 pushResource(resources.inputs, inputs1);
1310 pushResource(resources.inputs, inputs2);
1311 pushResource(resources.inputs, inputs3);
1312 pushResource(resources.outputs, outputs);
1313
1314 pushResource(computeResources.inputs, inputs0);
1315 pushResource(computeResources.inputs, inputs1);
1316 pushResource(computeResources.inputs, inputs2);
1317 pushResource(computeResources.inputs, inputs3);
1318 pushResource(computeResources.outputs, outputs);
1319
1320 return outputsSize / sizeWithPadding;
1321 }
1322
1323 // This one is used for switch tests.
1324 template <class T>
fillResources(GraphicsResources & resources,ComputeShaderSpec & computeResources,const vector<T> & data)1325 uint32_t SpvAsmTypeTests<T>::fillResources(GraphicsResources &resources, ComputeShaderSpec &computeResources,
1326 const vector<T> &data)
1327 {
1328 vector<T> outputs;
1329
1330 outputs.reserve(data.size());
1331
1332 for (uint32_t elemNdx = 0; elemNdx < data.size(); ++elemNdx)
1333 {
1334 if (data[elemNdx] == m_cases[0])
1335 outputs.push_back(100);
1336 else if (data[elemNdx] == m_cases[1])
1337 outputs.push_back(110);
1338 else if (data[elemNdx] == m_cases[2])
1339 outputs.push_back(120);
1340 else
1341 outputs.push_back(10);
1342 }
1343
1344 pushResource(resources.inputs, data);
1345 pushResource(resources.inputs, outputs);
1346
1347 pushResource(computeResources.inputs, data);
1348 pushResource(computeResources.inputs, outputs);
1349
1350 // Prepare an array of 32-bit integer values with a single integer. The expected value is 1.
1351 vector<int32_t> expectedOutput;
1352 expectedOutput.push_back(1);
1353 computeResources.outputs.push_back(Resource(BufferSp(new Int32Buffer(expectedOutput))));
1354 computeResources.verifyIO = verifyComputeSwitchResult;
1355
1356 return static_cast<uint32_t>(outputs.size());
1357 }
1358
1359 template <class T>
createStageTests(const char * testName,GraphicsResources & resources,ComputeShaderSpec & computeResources,uint32_t numElements,vector<string> & decorations,vector<string> & pre_mains,vector<string> & testfuns,string & operation,InputWidth inputWidth,const char * funVariables,const char * spirvExtension)1360 void SpvAsmTypeTests<T>::createStageTests(const char *testName, GraphicsResources &resources,
1361 ComputeShaderSpec &computeResources, uint32_t numElements,
1362 vector<string> &decorations, vector<string> &pre_mains,
1363 vector<string> &testfuns, string &operation, InputWidth inputWidth,
1364 const char *funVariables, const char *spirvExtension)
1365 {
1366 // Roughly equivalent to the following GLSL compute shader:
1367 //
1368 // vec4 testfun(in vec4 param);
1369 //
1370 // void main()
1371 // {
1372 // vec4 in_color = vec4(0.0, 0.0, 0.0, 1.0);
1373 // vec4 out_color = testfun(in_color);
1374 // }
1375 //
1376 // The input and output colors are irrelevant, but testfun will iterate over the input buffers and calculate results on the output
1377 // buffer. After the compute shader has run, we can verify the output buffer contains the expected results.
1378 const tcu::StringTemplate computeShaderTemplate(R"(
1379 OpCapability Shader
1380 ${capability:opt}
1381 ${extension:opt}
1382 OpMemoryModel Logical GLSL450
1383 OpEntryPoint GLCompute %BP_main "main"
1384 OpExecutionMode %BP_main LocalSize 1 1 1
1385 ${execution_mode:opt}
1386 ${debug:opt}
1387 ${moduleprocessed:opt}
1388 ${IF_decoration:opt}
1389 ${decoration:opt}
1390 )" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
1391 R"(
1392 %BP_color = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1
1393 ${pre_main:opt}
1394 ${IF_variable:opt}
1395 %BP_main = OpFunction %void None %voidf
1396 %BP_label_main = OpLabel
1397 ${IF_carryforward:opt}
1398 ${post_interface_op_comp:opt}
1399 %BP_in_color = OpVariable %fp_v4f32 Function
1400 %BP_out_color = OpVariable %fp_v4f32 Function
1401 OpStore %BP_in_color %BP_color
1402 %BP_tmp1 = OpLoad %v4f32 %BP_in_color
1403 %BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1
1404 OpStore %BP_out_color %BP_tmp2
1405 OpReturn
1406 OpFunctionEnd
1407
1408 ${testfun}
1409 )");
1410
1411 const StringTemplate decoration("OpDecorate %output DescriptorSet 0\n"
1412 "OpDecorate %output Binding ${output_binding}\n"
1413 "OpDecorate %a${num_elements}testtype ArrayStride ${typesize}\n"
1414 "OpDecorate %buf BufferBlock\n"
1415 "OpMemberDecorate %buf 0 Offset 0\n");
1416
1417 const StringTemplate vecDecoration("OpDecorate %a${num_elements}scalartype ArrayStride ${typesize}\n"
1418 "OpDecorate %scalarbuf BufferBlock\n"
1419 "OpMemberDecorate %scalarbuf 0 Offset 0\n");
1420
1421 const StringTemplate pre_pre_main("%c_u32_${num_elements} = OpConstant %u32 ${num_elements}\n"
1422 "%c_i32_${num_elements} = OpConstant %i32 ${num_elements}\n");
1423
1424 const StringTemplate scalar_pre_main("%testtype = ${scalartype}\n");
1425
1426 const StringTemplate vector_pre_main("%scalartype = ${scalartype}\n"
1427 "%testtype = OpTypeVector %scalartype ${vector_size}\n");
1428
1429 const StringTemplate pre_main_consts("%c_shift = OpConstant %u32 16\n"
1430 "${constant_zero}\n"
1431 "${constant_one}\n");
1432
1433 const StringTemplate pre_main_constv("%c_shift1 = OpConstant %u32 16\n"
1434 "%c_shift = OpConstantComposite %v${vector_size}u32 ${shift_initializers}\n"
1435 "${bvec}\n"
1436 "${constant_zero}\n"
1437 "${constant_one}\n"
1438 "%a${num_elements}scalartype = OpTypeArray %u32 %c_u32_${num_elements}\n"
1439 "%up_scalartype = OpTypePointer Uniform %u32\n"
1440 "%scalarbuf = OpTypeStruct %a${num_elements}scalartype\n"
1441 "%scalarbufptr = OpTypePointer Uniform %scalarbuf\n");
1442
1443 const StringTemplate post_pre_main("%a${num_elements}testtype = OpTypeArray %${testtype} "
1444 "%c_u32_${num_elements}\n"
1445 "%up_testtype = OpTypePointer Uniform %${testtype}\n"
1446 "%buf = OpTypeStruct %a${num_elements}testtype\n"
1447 "%bufptr = OpTypePointer Uniform %buf\n"
1448 "%output = OpVariable %bufptr Uniform\n"
1449 "${other_size_types}\n"
1450 "${u32_function_pointer}\n");
1451
1452 const StringTemplate pre_testfun("%test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
1453 "%param = OpFunctionParameter %v4f32\n"
1454 "%entry = OpLabel\n"
1455 "%op_constant = OpVariable %fp_${testtype} Function\n" +
1456 string(funVariables) +
1457 "%counter = OpVariable %fp_i32 Function\n"
1458 "OpStore %counter %c_i32_0\n"
1459 "OpBranch %loop\n"
1460
1461 "%loop = OpLabel\n"
1462 "%counter_val = OpLoad %i32 %counter\n"
1463 "%lt = OpSLessThan %bool %counter_val %c_i32_${num_elements}\n"
1464 "OpLoopMerge %exit %inc None\n"
1465 "OpBranchConditional %lt %write %exit\n"
1466
1467 "%write = OpLabel\n"
1468 "%output_loc = OpAccessChain %up_testtype %output %c_i32_0 "
1469 "%counter_val\n");
1470
1471 const StringTemplate post_testfun("OpStore %output_loc %op_result\n"
1472 "OpBranch %inc\n"
1473
1474 "%inc = OpLabel\n"
1475 "%counter_val_next = OpIAdd %i32 %counter_val %c_i32_1\n"
1476 "OpStore %counter %counter_val_next\n"
1477 "OpBranch %loop\n"
1478
1479 "%exit = OpLabel\n"
1480 "OpReturnValue %param\n"
1481
1482 "OpFunctionEnd\n");
1483
1484 const bool uses8bit(m_inputType == TYPE_I8 || m_inputType == TYPE_U8 || has8BitInputWidth(inputWidth));
1485 const string vectorSizeStr(de::toString(m_vectorSize));
1486 std::vector<std::string> noExtensions;
1487 std::vector<std::string> features;
1488 RGBA defaultColors[4];
1489 map<string, string> fragments;
1490 map<string, string> specs;
1491 VulkanFeatures requiredFeatures;
1492 std::string spirvExtensions;
1493 std::string spirvCapabilities;
1494
1495 getDefaultColors(defaultColors);
1496
1497 if (m_vectorSize == 3)
1498 {
1499 resources.verifyIO = verifyVec3Result;
1500 computeResources.verifyIO = verifyVec3Result;
1501 }
1502 else
1503 {
1504 resources.verifyIO = verifyDefaultResult;
1505 computeResources.verifyIO = verifyDefaultResult;
1506 }
1507
1508 // All of the following tests write their results into an output SSBO, therefore they require the following features.
1509 requiredFeatures.coreFeatures.vertexPipelineStoresAndAtomics = true;
1510 requiredFeatures.coreFeatures.fragmentStoresAndAtomics = true;
1511
1512 if (m_deviceFeature)
1513 features.insert(features.begin(), m_deviceFeature);
1514
1515 if (inputWidth != WIDTH_DEFAULT)
1516 {
1517 if (has16BitInputWidth(inputWidth))
1518 features.insert(features.begin(), "shaderInt16");
1519 if (has64BitInputWidth(inputWidth))
1520 features.insert(features.begin(), "shaderInt64");
1521 }
1522
1523 if (uses8bit)
1524 {
1525 requiredFeatures.extFloat16Int8.shaderInt8 = true;
1526 }
1527
1528 if (m_inputType == TYPE_I8 || m_inputType == TYPE_U8)
1529 {
1530 requiredFeatures.ext8BitStorage.uniformAndStorageBuffer8BitAccess = true;
1531 spirvExtensions += "OpExtension \"SPV_KHR_8bit_storage\"\n";
1532 }
1533
1534 if (m_inputType == TYPE_I16 || m_inputType == TYPE_U16)
1535 {
1536 requiredFeatures.ext16BitStorage.uniformAndStorageBuffer16BitAccess = true;
1537 spirvExtensions += "OpExtension \"SPV_KHR_16bit_storage\"\n";
1538 }
1539
1540 specs["testtype"] = m_spirvTestType;
1541 specs["scalartype"] = m_spirvType;
1542 specs["typesize"] = de::toString(((m_vectorSize == 3) ? 4 : m_vectorSize) * m_typeSize / 8);
1543 specs["vector_size"] = vectorSizeStr;
1544 specs["num_elements"] = de::toString(numElements);
1545 specs["output_binding"] = de::toString(resources.inputs.size());
1546 specs["shift_initializers"] = replicate(" %c_shift1", m_vectorSize);
1547
1548 specs["bvec"] = (m_vectorSize == 1 || m_vectorSize == 4) ?
1549 ("") :
1550 ("%v" + vectorSizeStr + "bool = OpTypeVector %bool " + vectorSizeStr);
1551
1552 specs["constant_zero"] =
1553 (m_vectorSize == 1) ?
1554 ("%c_zero = OpConstant %u32 0\n") :
1555 ("%c_zero = OpConstantComposite %v" + vectorSizeStr + "u32" + replicate(" %c_u32_0", m_vectorSize));
1556
1557 specs["constant_one"] =
1558 (m_vectorSize == 1) ?
1559 ("%c_one = OpConstant %u32 1\n") :
1560 ("%c_one = OpConstantComposite %v" + vectorSizeStr + "u32" + replicate(" %c_u32_1", m_vectorSize));
1561
1562 specs["other_size_types"] =
1563 (inputWidth == WIDTH_DEFAULT) ? ("") : getOtherSizeTypes(m_inputType, m_vectorSize, inputWidth);
1564
1565 specs["u32_function_pointer"] =
1566 deStringEqual(m_spirvTestType.c_str(), "i32") ?
1567 ("") :
1568 ("%fp_" + m_spirvTestType + " = OpTypePointer Function %" + m_spirvTestType + "\n");
1569
1570 if (spirvExtension)
1571 spirvExtensions += "%ext1 = OpExtInstImport \"" + string(spirvExtension) + "\"";
1572
1573 for (uint32_t elemNdx = 0; elemNdx < decorations.size(); ++elemNdx)
1574 fragments["decoration"] += decorations[elemNdx];
1575 fragments["decoration"] += decoration.specialize(specs);
1576
1577 if (m_vectorSize > 1)
1578 fragments["decoration"] += vecDecoration.specialize(specs);
1579
1580 fragments["pre_main"] = pre_pre_main.specialize(specs);
1581 if (specs["testtype"].compare(UNDEFINED_SPIRV_TEST_TYPE) == 0)
1582 {
1583 if (m_vectorSize > 1)
1584 fragments["pre_main"] += vector_pre_main.specialize(specs);
1585 else
1586 fragments["pre_main"] += scalar_pre_main.specialize(specs);
1587 }
1588
1589 if (m_vectorSize > 1)
1590 fragments["pre_main"] += pre_main_constv.specialize(specs);
1591 else
1592 fragments["pre_main"] += pre_main_consts.specialize(specs);
1593
1594 fragments["pre_main"] += post_pre_main.specialize(specs);
1595 for (uint32_t elemNdx = 0; elemNdx < pre_mains.size(); ++elemNdx)
1596 fragments["pre_main"] += pre_mains[elemNdx];
1597
1598 fragments["testfun"] = pre_testfun.specialize(specs);
1599 for (uint32_t elemNdx = 0; elemNdx < testfuns.size(); ++elemNdx)
1600 fragments["testfun"] += testfuns[elemNdx];
1601 fragments["testfun"] += operation + post_testfun.specialize(specs);
1602
1603 spirvCapabilities += getSpirvCapabilityStr(m_spirvCapability, inputWidth);
1604
1605 fragments["extension"] = spirvExtensions;
1606 fragments["capability"] = spirvCapabilities;
1607
1608 requiredFeaturesFromStrings(features, requiredFeatures);
1609
1610 createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, noExtensions, this,
1611 requiredFeatures);
1612
1613 computeResources.requestedVulkanFeatures = requiredFeatures;
1614 computeResources.requestedVulkanFeatures.coreFeatures.vertexPipelineStoresAndAtomics = false;
1615 computeResources.requestedVulkanFeatures.coreFeatures.fragmentStoresAndAtomics = false;
1616
1617 createComputeTest(computeResources, computeShaderTemplate, fragments, *this, testName);
1618 }
1619
1620 template <class T>
valueToStr(const T v)1621 std::string valueToStr(const T v)
1622 {
1623 std::stringstream s;
1624 s << v;
1625 return s.str();
1626 }
1627
1628 template <>
valueToStr(const uint8_t v)1629 std::string valueToStr<uint8_t>(const uint8_t v)
1630 {
1631 std::stringstream s;
1632 s << (uint16_t)v;
1633 return s.str();
1634 }
1635
1636 template <>
valueToStr(const int8_t v)1637 std::string valueToStr<int8_t>(const int8_t v)
1638 {
1639 std::stringstream s;
1640 s << (int16_t)v;
1641 return s.str();
1642 }
1643
1644 template <class T>
verifyResult(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,uint32_t skip,tcu::TestLog & log)1645 bool SpvAsmTypeTests<T>::verifyResult(const vector<Resource> &inputs, const vector<AllocationSp> &outputAllocations,
1646 const vector<Resource> &expectedOutputs, uint32_t skip, tcu::TestLog &log)
1647 {
1648 DE_ASSERT(outputAllocations.size() == 1);
1649 DE_ASSERT(inputs.size() > 0 && inputs.size() < 5);
1650
1651 const T *input[4] = {DE_NULL};
1652 vector<uint8_t> inputBytes[4];
1653 vector<uint8_t> expectedBytes;
1654
1655 expectedOutputs[0].getBytes(expectedBytes);
1656 const uint32_t count = static_cast<uint32_t>(expectedBytes.size() / sizeof(T));
1657 const T *obtained = static_cast<const T *>(outputAllocations[0]->getHostPtr());
1658 const T *expected = reinterpret_cast<const T *>(&expectedBytes.front());
1659
1660 for (uint32_t ndxCount = 0; ndxCount < inputs.size(); ndxCount++)
1661 {
1662 inputs[ndxCount].getBytes(inputBytes[ndxCount]);
1663 input[ndxCount] = reinterpret_cast<const T *>(&inputBytes[ndxCount].front());
1664 }
1665
1666 for (uint32_t ndxCount = 0; ndxCount < count; ++ndxCount)
1667 {
1668 /* Skip padding */
1669 if (((ndxCount + 1) % skip) == 0)
1670 continue;
1671
1672 if (obtained[ndxCount] != expected[ndxCount])
1673 {
1674 std::stringstream inputStream;
1675 inputStream << "(";
1676 for (uint32_t ndxIndex = 0; ndxIndex < inputs.size(); ++ndxIndex)
1677 {
1678 inputStream << valueToStr(input[ndxIndex][ndxCount]);
1679 if (ndxIndex < inputs.size() - 1)
1680 inputStream << ",";
1681 }
1682 inputStream << ")";
1683 log << tcu::TestLog::Message << "Error: found unexpected result for inputs " << inputStream.str()
1684 << ": expected " << valueToStr(expected[ndxCount]) << ", obtained " << valueToStr(obtained[ndxCount])
1685 << tcu::TestLog::EndMessage;
1686 return false;
1687 }
1688 }
1689
1690 return true;
1691 }
1692
1693 template <class T>
verifyDefaultResult(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,tcu::TestLog & log)1694 bool SpvAsmTypeTests<T>::verifyDefaultResult(const vector<Resource> &inputs,
1695 const vector<AllocationSp> &outputAllocations,
1696 const vector<Resource> &expectedOutputs, tcu::TestLog &log)
1697 {
1698 return verifyResult(inputs, outputAllocations, expectedOutputs, ~0, log);
1699 }
1700
1701 template <class T>
verifyVec3Result(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,tcu::TestLog & log)1702 bool SpvAsmTypeTests<T>::verifyVec3Result(const vector<Resource> &inputs, const vector<AllocationSp> &outputAllocations,
1703 const vector<Resource> &expectedOutputs, tcu::TestLog &log)
1704 {
1705 return verifyResult(inputs, outputAllocations, expectedOutputs, 4, log);
1706 }
1707
1708 template <class T>
createConstantDeclaration(vector<T> & dataset,uint32_t spirvOperation)1709 string SpvAsmTypeTests<T>::createConstantDeclaration(vector<T> &dataset, uint32_t spirvOperation)
1710 {
1711 const bool isVariableTest = (SpvOpVariable == spirvOperation);
1712 const bool isConstantNullTest = (SpvOpConstantNull == spirvOperation) || isVariableTest;
1713 const bool isConstantCompositeTest =
1714 (SpvOpConstantComposite == spirvOperation) || (isConstantNullTest && m_vectorSize > 1);
1715 const bool isConstantTest = (SpvOpConstant == spirvOperation) || isConstantCompositeTest || isConstantNullTest;
1716 const bool isSpecConstantTest = (SpvOpSpecConstant == spirvOperation);
1717 const bool isSpecConstantCompositeTest = (SpvOpSpecConstantComposite == spirvOperation);
1718
1719 const string testScalarType = (m_inputType == TYPE_I32) ? "i32" : (m_inputType == TYPE_U32) ? "u32" : "scalartype";
1720 const string constantType = (m_vectorSize > 1) ? testScalarType : m_spirvTestType;
1721 const string constantName = (m_vectorSize > 1) ? "%c_constituent_" : "%c_testtype_";
1722
1723 string str = "";
1724
1725 // Declare scalar specialization constants
1726 if (isSpecConstantTest)
1727 {
1728 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1729 str += constantName + de::toString(constantNdx) + " = OpSpecConstant %" + constantType + " " +
1730 de::toString(dataset[constantNdx]) + "\n";
1731 }
1732
1733 // Declare specialization constant composites
1734 if (isSpecConstantCompositeTest)
1735 {
1736 // Constituents are a mix of OpConstantNull, OpConstants and OpSpecializationConstants
1737 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1738 {
1739 const char *constantOp[] = {"OpConstant", "OpSpecConstant"};
1740
1741 if (constantNdx == 0u)
1742 str += constantName + de::toString(constantNdx) + " = OpConstantNull %" + constantType + "\n";
1743 else
1744 str += constantName + de::toString(constantNdx) + " = " + constantOp[constantNdx % 2] + " %" +
1745 constantType + " " + de::toString(dataset[constantNdx]) + "\n";
1746 }
1747
1748 for (uint32_t compositeNdx = 0u; compositeNdx < (uint32_t)dataset.size(); compositeNdx++)
1749 {
1750 str += "%c_testtype_" + de::toString(compositeNdx) + " = OpSpecConstantComposite %" + m_spirvTestType;
1751
1752 for (uint32_t componentNdx = 0u; componentNdx < m_vectorSize; componentNdx++)
1753 str += " %c_constituent_" +
1754 de::toString(getConstituentIndex(compositeNdx * m_vectorSize + componentNdx, m_vectorSize));
1755
1756 str += "\n";
1757 }
1758 }
1759
1760 // Declare scalar constants
1761 if (isConstantTest || isVariableTest)
1762 {
1763 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1764 {
1765 if (isConstantNullTest && constantNdx == 0u)
1766 str += constantName + de::toString(constantNdx) + " = OpConstantNull %" + constantType + "\n";
1767 else
1768 str += constantName + de::toString(constantNdx) + " = OpConstant %" + constantType + " " +
1769 de::toString(dataset[constantNdx]) + "\n";
1770 }
1771 }
1772
1773 // Declare constant composites
1774 if (isConstantCompositeTest)
1775 {
1776 for (uint32_t compositeNdx = 0u; compositeNdx < (uint32_t)dataset.size(); compositeNdx++)
1777 {
1778 str += "%c_testtype_" + de::toString(compositeNdx) + " = OpConstantComposite %" + m_spirvTestType;
1779
1780 for (uint32_t componentNdx = 0u; componentNdx < m_vectorSize; componentNdx++)
1781 str += " %c_constituent_" +
1782 de::toString(getConstituentIndex(compositeNdx * m_vectorSize + componentNdx, m_vectorSize));
1783
1784 str += "\n";
1785 }
1786 }
1787
1788 return str;
1789 }
1790
1791 template <class T>
getVariableStr(vector<T> & dataset,const char * spirvType,uint32_t spirvOperation)1792 string getVariableStr(vector<T> &dataset, const char *spirvType, uint32_t spirvOperation)
1793 {
1794 const bool isVariableTest = (SpvOpVariable == spirvOperation);
1795 string str = "";
1796
1797 // Declare variables with initializers
1798 if (isVariableTest)
1799 for (size_t i = 0u; i < dataset.size(); i++)
1800 str += "%testvariable_" + de::toString(i) + " = OpVariable %fp_" + spirvType + " Function %c_testtype_" +
1801 de::toString(i) + "\n";
1802
1803 return str;
1804 }
1805
1806 template <class T>
createTests(const char * testName,uint32_t spirvOperation,OpUnaryFuncType operation,UnaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)1807 void SpvAsmTypeTests<T>::createTests(const char *testName, uint32_t spirvOperation, OpUnaryFuncType operation,
1808 UnaryFilterFuncType filter, InputRange inputRange, InputWidth inputWidth,
1809 const char *spirvExtension, const bool returnHighPart)
1810 {
1811 DE_ASSERT(!isBooleanResultTest(spirvOperation));
1812
1813 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
1814 OpUnaryFuncType zeroFunc = &zero;
1815 vector<T> dataset;
1816 vector<string> decorations;
1817 vector<string> pre_mains;
1818 vector<string> testfuns;
1819 GraphicsResources resources;
1820 ComputeShaderSpec computeResources;
1821 map<string, string> fragments;
1822 map<string, string> specs;
1823
1824 if (isConstantOrVariableTest(spirvOperation))
1825 {
1826 DE_ASSERT(!spirvExtension);
1827
1828 const uint32_t inputSize = TEST_DATASET_SIZE;
1829 const uint32_t outputSize = TEST_DATASET_SIZE * m_vectorSize;
1830 vector<T> inputDataset;
1831
1832 inputDataset.reserve(inputSize);
1833 dataset.reserve(outputSize);
1834
1835 getDataset(inputDataset, inputSize);
1836 getConstantDataset(inputDataset, dataset, spirvOperation);
1837
1838 const uint32_t totalElements =
1839 combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1840
1841 pre_mains.reserve(1);
1842 pre_mains.push_back(createConstantDeclaration(inputDataset, spirvOperation));
1843
1844 string fullOperation = "OpBranch %switchStart\n"
1845 "%switchStart = OpLabel\n"
1846 "OpSelectionMerge %switchEnd None\n"
1847 "OpSwitch %counter_val %caseDefault";
1848
1849 for (uint32_t caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1850 fullOperation += " " + de::toString(caseNdx) + " " + "%case" + de::toString(caseNdx);
1851
1852 fullOperation += "\n";
1853
1854 const string funVariables = getVariableStr(inputDataset, m_spirvTestType.c_str(), spirvOperation);
1855
1856 if (SpvOpVariable == spirvOperation)
1857 {
1858 for (uint32_t caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1859 fullOperation += "%case" + de::toString(caseNdx) +
1860 " = OpLabel\n"
1861 "%temp_" +
1862 de::toString(caseNdx) + " = OpLoad %" + m_spirvTestType + " %testvariable_" +
1863 de::toString(caseNdx) +
1864 "\n"
1865 "OpStore %op_constant %temp_" +
1866 de::toString(caseNdx) +
1867 "\n"
1868 "OpBranch %switchEnd\n";
1869 }
1870 else
1871 {
1872 for (uint32_t caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1873 fullOperation += "%case" + de::toString(caseNdx) +
1874 " = OpLabel\n"
1875 "OpStore %op_constant %c_testtype_" +
1876 de::toString(caseNdx) +
1877 "\n"
1878 "OpBranch %switchEnd\n";
1879 }
1880
1881 fullOperation += "%caseDefault = OpLabel\n"
1882 "OpBranch %switchEnd\n"
1883 "%switchEnd = OpLabel\n" +
1884 resultName + " = OpLoad %" + m_spirvTestType + " %op_constant\n";
1885
1886 finalizeFullOperation(fullOperation, resultName, returnHighPart, false);
1887
1888 createStageTests(testName, resources, computeResources, totalElements, decorations, pre_mains, testfuns,
1889 fullOperation, inputWidth, funVariables.c_str(), spirvExtension);
1890 }
1891 else
1892 {
1893 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
1894 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
1895 const uint32_t totalElements =
1896 combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1897
1898 decorations.reserve(1);
1899 pre_mains.reserve(1);
1900 testfuns.reserve(1);
1901
1902 decorations.push_back(createInputDecoration(0));
1903 pre_mains.push_back(createInputPreMain(0, spirvOperation));
1904 testfuns.push_back(createInputTestfun(0, spirvOperation));
1905
1906 string full_operation(spirvExtension ? resultName + " = OpExtInst %" + m_spirvTestType + " %ext1 " +
1907 getGLSLstd450OperationStr(spirvOperation) + " %input0_val\n" :
1908 resultName + " = " + getSpvOperationStr(spirvOperation) + " %" +
1909 m_spirvTestType + " %input0_val\n");
1910
1911 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
1912
1913 createStageTests(testName, resources, computeResources, totalElements, decorations, pre_mains, testfuns,
1914 full_operation, inputWidth, "", spirvExtension);
1915 }
1916 }
1917
1918 template <class T>
createTests(const char * testName,uint32_t spirvOperation,OpBinaryFuncType operation,BinaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)1919 void SpvAsmTypeTests<T>::createTests(const char *testName, uint32_t spirvOperation, OpBinaryFuncType operation,
1920 BinaryFilterFuncType filter, InputRange inputRange, InputWidth inputWidth,
1921 const char *spirvExtension, const bool returnHighPart)
1922 {
1923 const bool isBoolean = isBooleanResultTest(spirvOperation);
1924 const string resultName = (returnHighPart || isBoolean) ? "%op_result_pre" : "%op_result";
1925 const string resultType = isBoolean ? getBooleanResultType(m_vectorSize) : m_spirvTestType;
1926 OpBinaryFuncType zeroFunc = &zero;
1927 vector<T> dataset;
1928 vector<string> decorations;
1929 vector<string> pre_mains;
1930 vector<string> testfuns;
1931 GraphicsResources resources;
1932 ComputeShaderSpec computeResources;
1933 map<string, string> fragments;
1934 map<string, string> specs;
1935 string full_operation;
1936
1937 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
1938 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
1939 const uint32_t totalElements =
1940 combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1941
1942 decorations.reserve(2);
1943 pre_mains.reserve(2);
1944 testfuns.reserve(2);
1945
1946 for (uint32_t elemNdx = 0; elemNdx < 2; ++elemNdx)
1947 {
1948 decorations.push_back(createInputDecoration(elemNdx));
1949 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
1950 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
1951 }
1952
1953 if (spirvOperation != DE_NULL)
1954 {
1955 if (inputWidth == WIDTH_DEFAULT)
1956 full_operation = spirvExtension ?
1957 resultName + " = OpExtInst %" + resultType + " %ext1 " +
1958 getGLSLstd450OperationStr(spirvOperation) + " %input0_val %input1_val\n" :
1959 resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + resultType +
1960 " %input0_val %input1_val\n";
1961 else
1962 full_operation = getBinaryFullOperationWithInputWidthStr(
1963 resultName, getSpvOperationStr(spirvOperation), m_inputType, m_spirvTestType, m_vectorSize, inputWidth);
1964 }
1965 else
1966 {
1967 if (deStringBeginsWith(testName, "mul_sdiv"))
1968 {
1969 DE_ASSERT(spirvExtension == DE_NULL);
1970 full_operation = "%op_result2 = OpIMul %" + m_spirvTestType + " %input0_val %input1_val\n";
1971 full_operation += resultName + " = OpSDiv %" + m_spirvTestType + " %op_result2 %input1_val\n";
1972 }
1973 if (deStringBeginsWith(testName, "mul_udiv"))
1974 {
1975 DE_ASSERT(spirvExtension == DE_NULL);
1976 full_operation = "%op_result2 = OpIMul %" + m_spirvTestType + " %input0_val %input1_val\n";
1977 full_operation += resultName + " = OpUDiv %" + m_spirvTestType + " %op_result2 %input1_val\n";
1978 }
1979 }
1980
1981 finalizeFullOperation(full_operation, resultName, returnHighPart, isBoolean);
1982
1983 createStageTests(testName, resources, computeResources, totalElements, decorations, pre_mains, testfuns,
1984 full_operation, inputWidth, "", spirvExtension);
1985 }
1986
1987 template <class T>
createTests(const char * testName,uint32_t spirvOperation,OpTernaryFuncType operation,TernaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)1988 void SpvAsmTypeTests<T>::createTests(const char *testName, uint32_t spirvOperation, OpTernaryFuncType operation,
1989 TernaryFilterFuncType filter, InputRange inputRange, InputWidth inputWidth,
1990 const char *spirvExtension, const bool returnHighPart)
1991 {
1992 DE_ASSERT(!isBooleanResultTest(spirvOperation));
1993
1994 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
1995 OpTernaryFuncType zeroFunc = &zero;
1996 vector<T> dataset;
1997 vector<string> decorations;
1998 vector<string> pre_mains;
1999 vector<string> testfuns;
2000 GraphicsResources resources;
2001 ComputeShaderSpec computeResources;
2002 map<string, string> fragments;
2003 map<string, string> specs;
2004
2005 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
2006 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
2007 const uint32_t totalElements =
2008 combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
2009
2010 decorations.reserve(3);
2011 pre_mains.reserve(3);
2012 testfuns.reserve(3);
2013
2014 for (uint32_t elemNdx = 0; elemNdx < 3; ++elemNdx)
2015 {
2016 decorations.push_back(createInputDecoration(elemNdx));
2017 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
2018 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
2019 }
2020
2021 string full_operation = "";
2022
2023 if (inputWidth == WIDTH_DEFAULT)
2024 full_operation =
2025 (spirvExtension ? resultName + " = OpExtInst %" + m_spirvTestType + " %ext1 " +
2026 getGLSLstd450OperationStr(spirvOperation) + " %input0_val %input1_val %input2_val\n" :
2027 resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + m_spirvTestType +
2028 " %input0_val %input1_val %input2_val\n");
2029 else
2030 full_operation = getFullOperationWithDifferentInputWidthStr(resultName, getSpvOperationStr(spirvOperation),
2031 m_inputType, m_spirvTestType, inputWidth, false);
2032
2033 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
2034
2035 createStageTests(testName, resources, computeResources, totalElements, decorations, pre_mains, testfuns,
2036 full_operation, inputWidth, "", spirvExtension);
2037 }
2038
2039 template <class T>
createTests(const char * testName,uint32_t spirvOperation,OpQuaternaryFuncType operation,QuaternaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)2040 void SpvAsmTypeTests<T>::createTests(const char *testName, uint32_t spirvOperation, OpQuaternaryFuncType operation,
2041 QuaternaryFilterFuncType filter, InputRange inputRange, InputWidth inputWidth,
2042 const char *spirvExtension, const bool returnHighPart)
2043 {
2044 DE_ASSERT(!spirvExtension);
2045 DE_ASSERT(!isBooleanResultTest(spirvOperation));
2046
2047 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
2048 OpQuaternaryFuncType zeroFunc = &zero;
2049 vector<T> dataset;
2050 vector<string> decorations;
2051 vector<string> pre_mains;
2052 vector<string> testfuns;
2053 GraphicsResources resources;
2054 ComputeShaderSpec computeResources;
2055 map<string, string> fragments;
2056 map<string, string> specs;
2057 string full_operation;
2058
2059 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
2060 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
2061 const uint32_t totalElements =
2062 combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
2063
2064 decorations.reserve(4);
2065 pre_mains.reserve(4);
2066 testfuns.reserve(4);
2067
2068 for (uint32_t elemNdx = 0; elemNdx < 4; ++elemNdx)
2069 {
2070 decorations.push_back(createInputDecoration(elemNdx));
2071 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
2072 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
2073 }
2074
2075 if (inputWidth == WIDTH_DEFAULT)
2076 full_operation = resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + m_spirvTestType +
2077 " %input0_val %input1_val %input2_val %input3_val\n";
2078 else
2079 full_operation = getFullOperationWithDifferentInputWidthStr(resultName, getSpvOperationStr(spirvOperation),
2080 m_inputType, m_spirvTestType, inputWidth, true);
2081
2082 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
2083
2084 createStageTests(testName, resources, computeResources, totalElements, decorations, pre_mains, testfuns,
2085 full_operation, inputWidth, "", spirvExtension);
2086 }
2087
2088 template <class T>
createSwitchTests(void)2089 void SpvAsmTypeTests<T>::createSwitchTests(void)
2090 {
2091 // The switch case test function is a bit different from the normal one. It uses two input buffers for input data and expected
2092 // results. The shader itself will calculate results based on input data and compare them to the expected results in the second
2093 // buffer, instead of verifying results on the CPU.
2094 //
2095 // The test function will return the color passed to it if the obtained results match the expected results, and will return (0.5,
2096 // 0.5, 0.5, 1.0) if they do not. For graphic stages, this returned color will be used to draw things and we can verify the output
2097 // image as usual with the graphics shader test utils. For compute shaders, this does not work.
2098 //
2099 // In this case, we will pass black as the input color for the test function, and will verify it returns black. We will write a
2100 // single integer in an output storage buffer as a boolean value indicating if the returned color matches the input color, to be
2101 // checked after the shader runs. Roughly equivalent to the following GLSL code:
2102 //
2103 // layout(binding = 2) buffer BlockType { int values[]; } block;
2104 //
2105 // vec4 testfun(in vec4 param);
2106 //
2107 // void main()
2108 // {
2109 // vec4 in_color = vec4(0.0, 0.0, 0.0, 1.0);
2110 // vec4 out_color = testfun(in_color);
2111 // block.values[0] = int(all(equal(in_color, out_color)));
2112 // }
2113 const tcu::StringTemplate computeShaderSwitchTemplate(R"(
2114 OpCapability Shader
2115 ${capability:opt}
2116 ${extension:opt}
2117 OpMemoryModel Logical GLSL450
2118 OpEntryPoint GLCompute %BP_main "main"
2119 OpExecutionMode %BP_main LocalSize 1 1 1
2120 ${execution_mode:opt}
2121 ${debug:opt}
2122 ${moduleprocessed:opt}
2123 ${IF_decoration:opt}
2124 ${decoration:opt}
2125 OpDecorate %rta_i32 ArrayStride 4
2126 OpMemberDecorate %BlockType 0 Offset 0
2127 OpDecorate %BlockType BufferBlock
2128 OpDecorate %block DescriptorSet 0
2129 OpDecorate %block Binding 2
2130 )" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
2131 R"(
2132 %rta_i32 = OpTypeRuntimeArray %i32
2133 %BlockType = OpTypeStruct %rta_i32
2134 %up_BlockType = OpTypePointer Uniform %BlockType
2135 %block = OpVariable %up_BlockType Uniform
2136 %BP_color = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1
2137 ${pre_main:opt}
2138 ${IF_variable:opt}
2139 %up_i32 = OpTypePointer Uniform %i32
2140 %BP_main = OpFunction %void None %voidf
2141 %BP_label_main = OpLabel
2142 ${IF_carryforward:opt}
2143 ${post_interface_op_comp:opt}
2144 %BP_in_color = OpVariable %fp_v4f32 Function
2145 %BP_out_color = OpVariable %fp_v4f32 Function
2146 OpStore %BP_in_color %BP_color
2147 %BP_tmp1 = OpLoad %v4f32 %BP_in_color
2148 %BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1
2149 OpStore %BP_out_color %BP_tmp2
2150
2151 %BP_tmp3 = OpLoad %v4f32 %BP_in_color
2152 %BP_tmp4 = OpLoad %v4f32 %BP_out_color
2153 %BP_tmp5 = OpFOrdEqual %v4bool %BP_tmp3 %BP_tmp4
2154 %BP_tmp6 = OpAll %bool %BP_tmp5
2155 %BP_tmp7 = OpSelect %i32 %BP_tmp6 %c_i32_1 %c_i32_0
2156 %BP_tmp8 = OpAccessChain %up_i32 %block %c_i32_0 %c_i32_0
2157 OpStore %BP_tmp8 %BP_tmp7
2158
2159 OpReturn
2160 OpFunctionEnd
2161
2162 ${testfun}
2163 )");
2164
2165 const StringTemplate decoration("OpDecorate %input DescriptorSet 0\n"
2166 "OpDecorate %input Binding 0\n"
2167 "OpDecorate %input NonWritable\n"
2168 "OpDecorate %expectedOutput DescriptorSet 0\n"
2169 "OpDecorate %expectedOutput Binding 1\n"
2170 "OpDecorate %expectedOutput NonWritable\n"
2171 "OpDecorate %a${num_elements}testtype ArrayStride ${typesize}\n"
2172 "OpDecorate %buf BufferBlock\n"
2173 "OpMemberDecorate %buf 0 Offset 0\n");
2174
2175 const StringTemplate pre_pre_main("%fp_bool = OpTypePointer Function %bool\n"
2176 "%c_u32_${num_elements} = OpConstant %u32 ${num_elements}\n"
2177 "%c_i32_${num_elements} = OpConstant %i32 ${num_elements}\n");
2178
2179 const StringTemplate scalar_pre_main("%testtype = ${scalartype}\n");
2180
2181 const StringTemplate post_pre_main(
2182 "%c_casedefault = OpConstant %${testtype} 10\n"
2183 "%c_case0 = OpConstant %${testtype} 100\n"
2184 "%c_case1 = OpConstant %${testtype} 110\n"
2185 "%c_case2 = OpConstant %${testtype} 120\n"
2186 "%fail_color = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_1\n"
2187 "%a${num_elements}testtype = OpTypeArray %${testtype} %c_u32_${num_elements}\n"
2188 "%up_testtype = OpTypePointer Uniform %${testtype}\n"
2189 "%buf = OpTypeStruct %a${num_elements}testtype\n"
2190 "%bufptr = OpTypePointer Uniform %buf\n"
2191 "%input = OpVariable %bufptr Uniform\n"
2192 "%expectedOutput = OpVariable %bufptr Uniform\n");
2193
2194 const StringTemplate testfun(
2195 "%test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
2196 "%param = OpFunctionParameter %v4f32\n"
2197
2198 "%entry = OpLabel\n"
2199 "%counter = OpVariable %fp_i32 Function\n"
2200 "%return = OpVariable %fp_v4f32 Function\n"
2201 "%works = OpVariable %fp_bool Function\n"
2202 "OpStore %counter %c_i32_0\n"
2203 "OpStore %return %param\n"
2204 "OpBranch %loop\n"
2205
2206 "%loop = OpLabel\n"
2207 "%counter_val = OpLoad %i32 %counter\n"
2208 "%lt = OpSLessThan %bool %counter_val %c_i32_${num_elements}\n"
2209 "OpLoopMerge %loop_exit %inc None\n"
2210 "OpBranchConditional %lt %load %loop_exit\n"
2211
2212 "%load = OpLabel\n"
2213 "%input_loc = OpAccessChain %up_testtype %input %c_i32_0 %counter_val\n"
2214 "%input_val = OpLoad %${testtype} %input_loc\n"
2215 "%expectedOutput_loc = OpAccessChain %up_testtype %expectedOutput %c_i32_0 %counter_val\n"
2216 "%expectedOutput_val = OpLoad %${testtype} %expectedOutput_loc\n"
2217
2218 "OpSelectionMerge %switch_exit None\n"
2219 "OpSwitch %input_val %default ${case0} %case0 ${case1} %case1 ${case2} %case2\n"
2220
2221 "%default = OpLabel\n"
2222 "%is_default = OpIEqual %bool %expectedOutput_val %c_casedefault\n"
2223 "OpBranch %switch_exit\n"
2224
2225 "%case0 = OpLabel\n"
2226 "%is_case0 = OpIEqual %bool %expectedOutput_val %c_case0\n"
2227 "OpBranch %switch_exit\n"
2228
2229 "%case1 = OpLabel\n"
2230 "%is_case1 = OpIEqual %bool %expectedOutput_val %c_case1\n"
2231 "OpBranch %switch_exit\n"
2232
2233 "%case2 = OpLabel\n"
2234 "%is_case2 = OpIEqual %bool %expectedOutput_val %c_case2\n"
2235 "OpBranch %switch_exit\n"
2236
2237 "%switch_exit = OpLabel\n"
2238 "%case_result = OpPhi %bool %is_default %default %is_case0 %case0 %is_case1 %case1 %is_case2 %case2\n"
2239 "OpSelectionMerge %result_end None\n"
2240 "OpBranchConditional %case_result %result_correct %result_incorrect\n"
2241
2242 "%result_correct = OpLabel\n"
2243 "OpBranch %result_end\n"
2244
2245 "%result_incorrect = OpLabel\n"
2246 "%counter_val_end = OpIAdd %i32 %counter_val %c_i32_${num_elements}\n"
2247 "OpStore %counter %counter_val_end\n"
2248 "OpStore %return %fail_color\n"
2249 "OpBranch %result_end\n"
2250
2251 "%result_end = OpLabel\n"
2252 "OpBranch %inc\n"
2253
2254 "%inc = OpLabel\n"
2255 "%counter_val_next = OpIAdd %i32 %counter_val %c_i32_1\n"
2256 "OpStore %counter %counter_val_next\n"
2257 "OpBranch %loop\n"
2258
2259 "%loop_exit = OpLabel\n"
2260 "%return_val = OpLoad %v4f32 %return\n"
2261 "OpReturnValue %return_val\n"
2262
2263 "OpFunctionEnd\n");
2264
2265 const bool uses8bit(m_inputType == TYPE_I8 || m_inputType == TYPE_U8);
2266
2267 GraphicsResources resources;
2268 ComputeShaderSpec computeResources;
2269 RGBA defaultColors[4];
2270 map<string, string> fragments;
2271 map<string, string> specs;
2272 std::vector<string> noExtensions;
2273 std::vector<string> features;
2274 VulkanFeatures requiredFeatures;
2275 vector<T> dataset;
2276 uint32_t numElements;
2277 std::string spirvExtensions;
2278 std::string spirvCapabilities;
2279
2280 getDefaultColors(defaultColors);
2281
2282 dataset.reserve(TEST_DATASET_SIZE);
2283 getDataset(dataset, TEST_DATASET_SIZE);
2284 numElements = fillResources(resources, computeResources, dataset);
2285
2286 if (m_deviceFeature)
2287 features.insert(features.begin(), m_deviceFeature);
2288
2289 if (uses8bit)
2290 {
2291 requiredFeatures.extFloat16Int8.shaderInt8 = true;
2292 }
2293
2294 if (m_inputType == TYPE_I8 || m_inputType == TYPE_U8)
2295 {
2296 requiredFeatures.ext8BitStorage.uniformAndStorageBuffer8BitAccess = true;
2297 spirvExtensions += "OpExtension \"SPV_KHR_8bit_storage\"\n";
2298 }
2299
2300 if (m_inputType == TYPE_I16 || m_inputType == TYPE_U16)
2301 {
2302 requiredFeatures.ext16BitStorage.uniformAndStorageBuffer16BitAccess = true;
2303 spirvExtensions += "OpExtension \"SPV_KHR_16bit_storage\"\n";
2304 }
2305
2306 specs["testtype"] = m_spirvTestType;
2307 specs["scalartype"] = m_spirvType;
2308 specs["typesize"] = de::toString(m_typeSize / 8);
2309 specs["num_elements"] = de::toString(numElements);
2310 specs["case0"] = de::toString(m_cases[0]);
2311 specs["case1"] = de::toString(m_cases[1]);
2312 specs["case2"] = de::toString(m_cases[2]);
2313
2314 fragments["decoration"] = decoration.specialize(specs);
2315
2316 fragments["pre_main"] = pre_pre_main.specialize(specs);
2317 if (specs["testtype"].compare(UNDEFINED_SPIRV_TEST_TYPE) == 0)
2318 fragments["pre_main"] += scalar_pre_main.specialize(specs);
2319 fragments["pre_main"] += post_pre_main.specialize(specs);
2320
2321 fragments["testfun"] = testfun.specialize(specs);
2322
2323 spirvCapabilities += getSpirvCapabilityStr(m_spirvCapability, WIDTH_DEFAULT);
2324
2325 fragments["extension"] = spirvExtensions;
2326 fragments["capability"] = spirvCapabilities;
2327
2328 requiredFeaturesFromStrings(features, requiredFeatures);
2329 computeResources.requestedVulkanFeatures = requiredFeatures;
2330
2331 const string testName = "switch";
2332
2333 createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, noExtensions, this,
2334 requiredFeatures);
2335 createComputeTest(computeResources, computeShaderSwitchTemplate, fragments, *this, testName);
2336 }
2337
2338 template <class T>
getConstantDataset(vector<T> inputDataset,vector<T> & outputDataset,uint32_t spirvOperation)2339 void SpvAsmTypeTests<T>::getConstantDataset(vector<T> inputDataset, vector<T> &outputDataset, uint32_t spirvOperation)
2340 {
2341 const uint32_t numElements = (uint32_t)inputDataset.size();
2342
2343 if ((SpvOpConstant == spirvOperation) || (SpvOpSpecConstant == spirvOperation))
2344 {
2345 for (uint32_t elementNdx = 0u; elementNdx < numElements; elementNdx++)
2346 outputDataset.push_back(inputDataset[elementNdx]);
2347 }
2348 else
2349 {
2350 for (uint32_t elementNdx = 0; elementNdx < numElements * m_vectorSize; elementNdx++)
2351 outputDataset.push_back(inputDataset[getConstituentIndex(elementNdx, m_vectorSize)]);
2352 }
2353 }
2354
2355 template <class T>
finalizeFullOperation(string & fullOperation,const string & resultName,const bool returnHighPart,const bool isBooleanResult)2356 void SpvAsmTypeTests<T>::finalizeFullOperation(string &fullOperation, const string &resultName,
2357 const bool returnHighPart, const bool isBooleanResult)
2358 {
2359 DE_ASSERT(!fullOperation.empty());
2360
2361 if (returnHighPart)
2362 {
2363 DE_ASSERT(sizeof(T) == sizeof(int16_t));
2364 DE_ASSERT((m_inputType == TYPE_I16) || (m_inputType == TYPE_U16));
2365
2366 const bool signedness = (m_inputType == TYPE_I16);
2367 const string convertOp = signedness ? "OpSConvert" : "OpUConvert";
2368 const string convertPrefix = (m_vectorSize == 1) ? "" : "v" + de::toString(m_vectorSize);
2369 const string convertType = convertPrefix + "u32";
2370
2371 // Zero extend value to double-width value, then return high part
2372 fullOperation += "%op_result_a = OpUConvert %" + convertType + " " + resultName + "\n";
2373 fullOperation += "%op_result_b = OpShiftRightLogical %" + convertType + " %op_result_a %c_shift\n";
2374 fullOperation += "%op_result = " + convertOp + " %" + m_spirvTestType + " %op_result_b\n";
2375 }
2376 else if (isBooleanResult)
2377 {
2378 const string selectType = (m_vectorSize == 1) ? ("u32") : ("v" + de::toString(m_vectorSize) + "u32");
2379
2380 // Convert boolean values to result format
2381 if (m_inputType == TYPE_U32)
2382 {
2383 fullOperation += "%op_result = OpSelect %" + selectType + " %op_result_pre %c_one %c_zero\n";
2384 }
2385 else
2386 {
2387 fullOperation += "%op_result_u32 = OpSelect %" + selectType + " %op_result_pre %c_one %c_zero\n";
2388
2389 if (m_typeSize == 32)
2390 fullOperation += "%op_result = OpBitcast %" + m_spirvTestType + " %op_result_u32\n";
2391 else
2392 fullOperation += "%op_result = OpSConvert %" + m_spirvTestType + " %op_result_u32\n";
2393 }
2394 }
2395 else
2396 {
2397 DE_ASSERT(resultName == "%op_result");
2398 }
2399 }
2400
2401 template <class T>
filterNone(T)2402 bool SpvAsmTypeTests<T>::filterNone(T)
2403 {
2404 return true;
2405 }
2406
2407 template <class T>
filterNone(T,T)2408 bool SpvAsmTypeTests<T>::filterNone(T, T)
2409 {
2410 return true;
2411 }
2412
2413 template <class T>
filterNone(T,T,T)2414 bool SpvAsmTypeTests<T>::filterNone(T, T, T)
2415 {
2416 return true;
2417 }
2418
2419 template <class T>
filterNone(T,T,T,T)2420 bool SpvAsmTypeTests<T>::filterNone(T, T, T, T)
2421 {
2422 return true;
2423 }
2424
2425 template <class T>
filterZero(T,T b)2426 bool SpvAsmTypeTests<T>::filterZero(T, T b)
2427 {
2428 if (b == static_cast<T>(0))
2429 return false;
2430 else
2431 return true;
2432 }
2433
2434 template <class T>
filterNegativesAndZero(T a,T b)2435 bool SpvAsmTypeTests<T>::filterNegativesAndZero(T a, T b)
2436 {
2437 if (a < static_cast<T>(0) || b <= static_cast<T>(0))
2438 return false;
2439 else
2440 return true;
2441 }
2442
2443 template <class T>
filterMinGtMax(T,T a,T b)2444 bool SpvAsmTypeTests<T>::filterMinGtMax(T, T a, T b)
2445 {
2446 if (a > b)
2447 return false;
2448 else
2449 return true;
2450 }
2451
2452 template <class T>
zero(T)2453 T SpvAsmTypeTests<T>::zero(T)
2454 {
2455 return static_cast<T>(0.0);
2456 }
2457
2458 template <class T>
zero(T,T)2459 T SpvAsmTypeTests<T>::zero(T, T)
2460 {
2461 return static_cast<T>(0.0);
2462 }
2463
2464 template <class T>
zero(T,T,T)2465 T SpvAsmTypeTests<T>::zero(T, T, T)
2466 {
2467 return static_cast<T>(0.0);
2468 }
2469
2470 template <class T>
zero(T,T,T,T)2471 T SpvAsmTypeTests<T>::zero(T, T, T, T)
2472 {
2473 return static_cast<T>(0.0);
2474 }
2475
2476 template <class T>
replicate(const std::string & replicant,const uint32_t count)2477 std::string SpvAsmTypeTests<T>::replicate(const std::string &replicant, const uint32_t count)
2478 {
2479 std::string result;
2480
2481 for (uint32_t i = 0; i < count; ++i)
2482 result += replicant;
2483
2484 return result;
2485 }
2486
2487 class SpvAsmTypeInt8Tests : public SpvAsmTypeTests<int8_t>
2488 {
2489 public:
2490 SpvAsmTypeInt8Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2491 ~SpvAsmTypeInt8Tests(void);
2492 void getDataset(vector<int8_t> &input, uint32_t numElements);
2493 void pushResource(vector<Resource> &resource, const vector<int8_t> &data);
2494 };
2495
SpvAsmTypeInt8Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2496 SpvAsmTypeInt8Tests::SpvAsmTypeInt8Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2497 : SpvAsmTypeTests(testCtx, "i8", DE_NULL, "Int8", "OpTypeInt 8 1", TYPE_I8, 8, vectorSize)
2498 {
2499 m_cases[0] = -42;
2500 m_cases[1] = 73;
2501 m_cases[2] = 121;
2502 }
2503
~SpvAsmTypeInt8Tests(void)2504 SpvAsmTypeInt8Tests::~SpvAsmTypeInt8Tests(void)
2505 {
2506 }
2507
getDataset(vector<int8_t> & input,uint32_t numElements)2508 void SpvAsmTypeInt8Tests::getDataset(vector<int8_t> &input, uint32_t numElements)
2509 {
2510 // Push first special cases
2511 input.push_back(0);
2512 input.push_back(static_cast<int8_t>(deIntMinValue32(8))); // A 8-bit negative number
2513 input.push_back(static_cast<int8_t>(deIntMaxValue32(8))); // A 8-bit positive number
2514
2515 // Push switch cases
2516 input.push_back(m_cases[0]);
2517 input.push_back(m_cases[1]);
2518 input.push_back(m_cases[2]);
2519
2520 numElements -= static_cast<uint32_t>(input.size());
2521
2522 // Random values
2523 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2524 input.push_back(static_cast<int8_t>(m_rnd.getUint8()));
2525 }
2526
pushResource(vector<Resource> & resource,const vector<int8_t> & data)2527 void SpvAsmTypeInt8Tests::pushResource(vector<Resource> &resource, const vector<int8_t> &data)
2528 {
2529 resource.push_back(Resource(BufferSp(new Int8Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2530 }
2531
2532 class SpvAsmTypeInt16Tests : public SpvAsmTypeTests<int16_t>
2533 {
2534 public:
2535 SpvAsmTypeInt16Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2536 ~SpvAsmTypeInt16Tests(void);
2537 void getDataset(vector<int16_t> &input, uint32_t numElements);
2538 void pushResource(vector<Resource> &resource, const vector<int16_t> &data);
2539 };
2540
SpvAsmTypeInt16Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2541 SpvAsmTypeInt16Tests::SpvAsmTypeInt16Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2542 : SpvAsmTypeTests(testCtx, "i16", "shaderInt16", "Int16", "OpTypeInt 16 1", TYPE_I16, 16, vectorSize)
2543 {
2544 m_cases[0] = -3221;
2545 m_cases[1] = 3210;
2546 m_cases[2] = 19597;
2547 }
2548
~SpvAsmTypeInt16Tests(void)2549 SpvAsmTypeInt16Tests::~SpvAsmTypeInt16Tests(void)
2550 {
2551 }
2552
getDataset(vector<int16_t> & input,uint32_t numElements)2553 void SpvAsmTypeInt16Tests::getDataset(vector<int16_t> &input, uint32_t numElements)
2554 {
2555 // Push first special cases
2556 input.push_back(0);
2557 input.push_back(static_cast<int16_t>(deIntMinValue32(16))); // A 16-bit negative number
2558 input.push_back(static_cast<int16_t>(deIntMaxValue32(16))); // A 16-bit positive number
2559
2560 // Push switch cases
2561 input.push_back(m_cases[0]);
2562 input.push_back(m_cases[1]);
2563 input.push_back(m_cases[2]);
2564
2565 numElements -= static_cast<uint32_t>(input.size());
2566
2567 // Random values
2568 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2569 input.push_back(static_cast<int16_t>(m_rnd.getUint16()));
2570 }
2571
pushResource(vector<Resource> & resource,const vector<int16_t> & data)2572 void SpvAsmTypeInt16Tests::pushResource(vector<Resource> &resource, const vector<int16_t> &data)
2573 {
2574 resource.push_back(Resource(BufferSp(new Int16Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2575 }
2576
2577 class SpvAsmTypeInt32Tests : public SpvAsmTypeTests<int32_t>
2578 {
2579 public:
2580 SpvAsmTypeInt32Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2581 ~SpvAsmTypeInt32Tests(void);
2582 void getDataset(vector<int32_t> &input, uint32_t numElements);
2583 void pushResource(vector<Resource> &resource, const vector<int32_t> &data);
2584 };
2585
SpvAsmTypeInt32Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2586 SpvAsmTypeInt32Tests::SpvAsmTypeInt32Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2587 : SpvAsmTypeTests(testCtx, "i32", DE_NULL, DE_NULL, "OpTypeInt 32 1", TYPE_I32, 32, vectorSize)
2588 {
2589 m_cases[0] = -3221;
2590 m_cases[1] = 3210;
2591 m_cases[2] = 268438669;
2592 }
2593
~SpvAsmTypeInt32Tests(void)2594 SpvAsmTypeInt32Tests::~SpvAsmTypeInt32Tests(void)
2595 {
2596 }
2597
getDataset(vector<int32_t> & input,uint32_t numElements)2598 void SpvAsmTypeInt32Tests::getDataset(vector<int32_t> &input, uint32_t numElements)
2599 {
2600 // Push first special cases
2601 input.push_back(0);
2602 input.push_back(deIntMinValue32(32) + 1); // So MIN = -MAX
2603 input.push_back(deIntMaxValue32(32));
2604
2605 // Push switch cases
2606 input.push_back(m_cases[0]);
2607 input.push_back(m_cases[1]);
2608 input.push_back(m_cases[2]);
2609
2610 numElements -= static_cast<uint32_t>(input.size());
2611
2612 // Random values
2613 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2614 input.push_back(static_cast<int32_t>(m_rnd.getUint32()));
2615 }
2616
pushResource(vector<Resource> & resource,const vector<int32_t> & data)2617 void SpvAsmTypeInt32Tests::pushResource(vector<Resource> &resource, const vector<int32_t> &data)
2618 {
2619 resource.push_back(Resource(BufferSp(new Int32Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2620 }
2621
2622 class SpvAsmTypeInt64Tests : public SpvAsmTypeTests<int64_t>
2623 {
2624 public:
2625 SpvAsmTypeInt64Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2626 ~SpvAsmTypeInt64Tests(void);
2627 void getDataset(vector<int64_t> &input, uint32_t numElements);
2628 void pushResource(vector<Resource> &resource, const vector<int64_t> &data);
2629 };
2630
SpvAsmTypeInt64Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2631 SpvAsmTypeInt64Tests::SpvAsmTypeInt64Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2632 : SpvAsmTypeTests(testCtx, "i64", "shaderInt64", "Int64", "OpTypeInt 64 1", TYPE_I64, 64, vectorSize)
2633 {
2634 m_cases[0] = 3210;
2635 m_cases[1] = -268438669;
2636 m_cases[2] = 26843866939192872;
2637 }
2638
~SpvAsmTypeInt64Tests(void)2639 SpvAsmTypeInt64Tests::~SpvAsmTypeInt64Tests(void)
2640 {
2641 }
2642
getDataset(vector<int64_t> & input,uint32_t numElements)2643 void SpvAsmTypeInt64Tests::getDataset(vector<int64_t> &input, uint32_t numElements)
2644 {
2645 // Push first special cases
2646 input.push_back(0);
2647 input.push_back(0xFFFF859A3BF78592); // A 64-bit negative number
2648 input.push_back(0x7FFF859A3BF78592); // A 64-bit positive number
2649
2650 // Push switch cases
2651 input.push_back(m_cases[0]);
2652 input.push_back(m_cases[1]);
2653 input.push_back(m_cases[2]);
2654
2655 numElements -= static_cast<uint32_t>(input.size());
2656
2657 // Random values
2658 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2659 input.push_back(static_cast<int64_t>(m_rnd.getUint64()));
2660 }
2661
pushResource(vector<Resource> & resource,const vector<int64_t> & data)2662 void SpvAsmTypeInt64Tests::pushResource(vector<Resource> &resource, const vector<int64_t> &data)
2663 {
2664 resource.push_back(Resource(BufferSp(new Int64Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2665 }
2666
2667 class SpvAsmTypeUint8Tests : public SpvAsmTypeTests<uint8_t>
2668 {
2669 public:
2670 SpvAsmTypeUint8Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2671 ~SpvAsmTypeUint8Tests(void);
2672 void getDataset(vector<uint8_t> &input, uint32_t numElements);
2673 void pushResource(vector<Resource> &resource, const vector<uint8_t> &data);
2674 };
2675
SpvAsmTypeUint8Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2676 SpvAsmTypeUint8Tests::SpvAsmTypeUint8Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2677 : SpvAsmTypeTests(testCtx, "u8", DE_NULL, "Int8", "OpTypeInt 8 0", TYPE_U8, 8, vectorSize)
2678 {
2679 m_cases[0] = 0;
2680 m_cases[1] = 73;
2681 m_cases[2] = 193;
2682 }
2683
~SpvAsmTypeUint8Tests(void)2684 SpvAsmTypeUint8Tests::~SpvAsmTypeUint8Tests(void)
2685 {
2686 }
2687
getDataset(vector<uint8_t> & input,uint32_t numElements)2688 void SpvAsmTypeUint8Tests::getDataset(vector<uint8_t> &input, uint32_t numElements)
2689 {
2690 // Push first special cases
2691 input.push_back(0); // Min value
2692 input.push_back(~0); // Max value
2693
2694 //Push switch cases
2695 input.push_back(m_cases[0]);
2696 input.push_back(m_cases[1]);
2697 input.push_back(m_cases[2]);
2698
2699 numElements -= static_cast<uint32_t>(input.size());
2700
2701 // Random values
2702 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2703 input.push_back(m_rnd.getUint8());
2704 }
2705
pushResource(vector<Resource> & resource,const vector<uint8_t> & data)2706 void SpvAsmTypeUint8Tests::pushResource(vector<Resource> &resource, const vector<uint8_t> &data)
2707 {
2708 resource.push_back(Resource(BufferSp(new Uint8Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2709 }
2710
2711 class SpvAsmTypeUint16Tests : public SpvAsmTypeTests<uint16_t>
2712 {
2713 public:
2714 SpvAsmTypeUint16Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2715 ~SpvAsmTypeUint16Tests(void);
2716 void getDataset(vector<uint16_t> &input, uint32_t numElements);
2717 void pushResource(vector<Resource> &resource, const vector<uint16_t> &data);
2718 };
2719
SpvAsmTypeUint16Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2720 SpvAsmTypeUint16Tests::SpvAsmTypeUint16Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2721 : SpvAsmTypeTests(testCtx, "u16", "shaderInt16", "Int16", "OpTypeInt 16 0", TYPE_U16, 16, vectorSize)
2722 {
2723 m_cases[0] = 0;
2724 m_cases[1] = 3210;
2725 m_cases[2] = 19597;
2726 }
2727
~SpvAsmTypeUint16Tests(void)2728 SpvAsmTypeUint16Tests::~SpvAsmTypeUint16Tests(void)
2729 {
2730 }
2731
getDataset(vector<uint16_t> & input,uint32_t numElements)2732 void SpvAsmTypeUint16Tests::getDataset(vector<uint16_t> &input, uint32_t numElements)
2733 {
2734 // Push first special cases
2735 input.push_back(0); // Min value
2736 input.push_back(~0); // Max value
2737
2738 //Push switch cases
2739 input.push_back(m_cases[0]);
2740 input.push_back(m_cases[1]);
2741 input.push_back(m_cases[2]);
2742
2743 numElements -= static_cast<uint32_t>(input.size());
2744
2745 // Random values
2746 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2747 input.push_back(m_rnd.getUint16());
2748 }
2749
pushResource(vector<Resource> & resource,const vector<uint16_t> & data)2750 void SpvAsmTypeUint16Tests::pushResource(vector<Resource> &resource, const vector<uint16_t> &data)
2751 {
2752 resource.push_back(Resource(BufferSp(new Uint16Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2753 }
2754
2755 class SpvAsmTypeUint32Tests : public SpvAsmTypeTests<uint32_t>
2756 {
2757 public:
2758 SpvAsmTypeUint32Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2759 ~SpvAsmTypeUint32Tests(void);
2760 void getDataset(vector<uint32_t> &input, uint32_t numElements);
2761 void pushResource(vector<Resource> &resource, const vector<uint32_t> &data);
2762 };
2763
SpvAsmTypeUint32Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2764 SpvAsmTypeUint32Tests::SpvAsmTypeUint32Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2765 : SpvAsmTypeTests(testCtx, "u32", DE_NULL, DE_NULL, "OpTypeInt 32 0", TYPE_U32, 32, vectorSize)
2766 {
2767 m_cases[0] = 0;
2768 m_cases[1] = 3210;
2769 m_cases[2] = 268438669;
2770 }
2771
~SpvAsmTypeUint32Tests(void)2772 SpvAsmTypeUint32Tests::~SpvAsmTypeUint32Tests(void)
2773 {
2774 }
2775
getDataset(vector<uint32_t> & input,uint32_t numElements)2776 void SpvAsmTypeUint32Tests::getDataset(vector<uint32_t> &input, uint32_t numElements)
2777 {
2778 // Push first special cases
2779 input.push_back(0); // Min value
2780 input.push_back(~0); // Max value
2781
2782 // Push switch cases
2783 input.push_back(m_cases[0]);
2784 input.push_back(m_cases[1]);
2785 input.push_back(m_cases[2]);
2786
2787 numElements -= static_cast<uint32_t>(input.size());
2788
2789 // Random values
2790 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2791 input.push_back(m_rnd.getUint32());
2792 }
2793
pushResource(vector<Resource> & resource,const vector<uint32_t> & data)2794 void SpvAsmTypeUint32Tests::pushResource(vector<Resource> &resource, const vector<uint32_t> &data)
2795 {
2796 resource.push_back(Resource(BufferSp(new Uint32Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2797 }
2798
2799 class SpvAsmTypeUint64Tests : public SpvAsmTypeTests<uint64_t>
2800 {
2801 public:
2802 SpvAsmTypeUint64Tests(tcu::TestContext &testCtx, uint32_t vectorSize);
2803 ~SpvAsmTypeUint64Tests(void);
2804 void getDataset(vector<uint64_t> &input, uint32_t numElements);
2805 void pushResource(vector<Resource> &resource, const vector<uint64_t> &data);
2806 };
2807
SpvAsmTypeUint64Tests(tcu::TestContext & testCtx,uint32_t vectorSize)2808 SpvAsmTypeUint64Tests::SpvAsmTypeUint64Tests(tcu::TestContext &testCtx, uint32_t vectorSize)
2809 : SpvAsmTypeTests(testCtx, "u64", "shaderInt64", "Int64", "OpTypeInt 64 0", TYPE_U64, 64, vectorSize)
2810 {
2811 m_cases[0] = 3210;
2812 m_cases[1] = 268438669;
2813 m_cases[2] = 26843866939192872;
2814 }
2815
~SpvAsmTypeUint64Tests(void)2816 SpvAsmTypeUint64Tests::~SpvAsmTypeUint64Tests(void)
2817 {
2818 }
2819
getDataset(vector<uint64_t> & input,uint32_t numElements)2820 void SpvAsmTypeUint64Tests::getDataset(vector<uint64_t> &input, uint32_t numElements)
2821 {
2822 // Push first special cases
2823 input.push_back(0); // Min value
2824 input.push_back(~0); // Max value
2825
2826 // Push switch cases
2827 input.push_back(m_cases[0]);
2828 input.push_back(m_cases[1]);
2829 input.push_back(m_cases[2]);
2830
2831 numElements -= static_cast<uint32_t>(input.size());
2832
2833 // Random values
2834 for (uint32_t elemNdx = 0; elemNdx < numElements; ++elemNdx)
2835 input.push_back(m_rnd.getUint64());
2836 }
2837
pushResource(vector<Resource> & resource,const vector<uint64_t> & data)2838 void SpvAsmTypeUint64Tests::pushResource(vector<Resource> &resource, const vector<uint64_t> &data)
2839 {
2840 resource.push_back(Resource(BufferSp(new Uint64Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2841 }
2842
2843 template <class T>
2844 class TestMath
2845 {
2846 public:
test_abs(T x)2847 static inline T test_abs(T x)
2848 {
2849 T t0 = static_cast<T>(0.0);
2850
2851 if (x >= t0)
2852 return x;
2853 else
2854 return test_negate(x);
2855 }
2856
test_add(T x,T y)2857 static inline T test_add(T x, T y)
2858 {
2859 return static_cast<T>(x + y);
2860 }
2861
test_clamp(T x,T minVal,T maxVal)2862 static inline T test_clamp(T x, T minVal, T maxVal)
2863 {
2864 return test_min(test_max(x, minVal), maxVal);
2865 }
2866
test_div(T x,T y)2867 static inline T test_div(T x, T y)
2868 {
2869 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
2870 // let's return 0
2871 if (y == static_cast<T>(0))
2872 return 0;
2873 else
2874 return static_cast<T>(x / y);
2875 }
2876
test_lsb(T x)2877 static inline T test_lsb(T x)
2878 {
2879 for (uint32_t i = 0; i < 8 * sizeof(T); i++)
2880 {
2881 if (x & (1u << i))
2882 return static_cast<T>(i);
2883 }
2884
2885 return static_cast<T>(-1.0);
2886 }
2887
test_max(T x,T y)2888 static inline T test_max(T x, T y)
2889 {
2890 if (x < y)
2891 return y;
2892 else
2893 return x;
2894 }
2895
test_min(T x,T y)2896 static inline T test_min(T x, T y)
2897 {
2898 if (y < x)
2899 return y;
2900 else
2901 return x;
2902 }
2903
test_mod(T x,T y)2904 static inline T test_mod(T x, T y)
2905 {
2906 T sign_x, sign_y;
2907
2908 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
2909 // let's return 0
2910 if (y == static_cast<T>(0))
2911 return 0;
2912
2913 if (x >= static_cast<T>(0))
2914 sign_x = 1;
2915 else
2916 sign_x = -1;
2917
2918 if (y >= static_cast<T>(0))
2919 sign_y = 1;
2920 else
2921 sign_y = -1;
2922
2923 return static_cast<T>(static_cast<T>(static_cast<T>(x) - static_cast<T>(y * static_cast<T>(x / y))) *
2924 static_cast<T>(sign_y * sign_x));
2925 }
2926
test_mul(T x,T y)2927 static inline T test_mul(T x, T y)
2928 {
2929 return static_cast<T>(x * y);
2930 }
2931
test_negate(T x)2932 static inline T test_negate(T x)
2933 {
2934 return static_cast<T>(static_cast<T>(0.0) - static_cast<T>(x));
2935 }
2936
test_rem(T x,T y)2937 static inline T test_rem(T x, T y)
2938 {
2939 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
2940 // let's return 0
2941 if (y == static_cast<T>(0))
2942 return 0;
2943
2944 return static_cast<T>(x % y);
2945 }
2946
test_sign(T x)2947 static inline T test_sign(T x)
2948 {
2949 T t0 = static_cast<T>(0.0);
2950
2951 if (x > t0)
2952 return static_cast<T>(1.0);
2953 else if (x < t0)
2954 return static_cast<T>(-1.0);
2955 else
2956 return t0;
2957 }
2958
test_sub(T x,T y)2959 static inline T test_sub(T x, T y)
2960 {
2961 return static_cast<T>(x - y);
2962 }
2963
test_msb(T)2964 static inline T test_msb(T)
2965 {
2966 TCU_THROW(InternalError, "Not implemented");
2967 }
2968
test_lsr(T x,T y)2969 static inline T test_lsr(T x, T y)
2970 {
2971 if (x >= static_cast<T>(0) || y == static_cast<T>(0))
2972 {
2973 return static_cast<T>(x >> y);
2974 }
2975 else
2976 {
2977 const T mask = de::leftZeroMask(y);
2978 return static_cast<T>((x >> y) & mask);
2979 }
2980 }
2981
test_asr(T x,T y)2982 static inline T test_asr(T x, T y)
2983 {
2984 const T bitmask = static_cast<T>(uint64_t(1) << (sizeof(T) * 8u - 1u));
2985
2986 if ((x & bitmask) && y > 0)
2987 {
2988 const T mask = de::leftSetMask(y);
2989 const T result = static_cast<T>((x >> y) | mask);
2990 return result;
2991 }
2992 else
2993 {
2994 return static_cast<T>(x >> y);
2995 }
2996 }
2997
test_lsl(T x,T y)2998 static inline T test_lsl(T x, T y)
2999 {
3000 return static_cast<T>(x << y);
3001 }
3002
test_bitwise_or(T x,T y)3003 static inline T test_bitwise_or(T x, T y)
3004 {
3005 return static_cast<T>(x | y);
3006 }
3007
test_bitwise_xor(T x,T y)3008 static inline T test_bitwise_xor(T x, T y)
3009 {
3010 return static_cast<T>(x ^ y);
3011 }
3012
test_bitwise_and(T x,T y)3013 static inline T test_bitwise_and(T x, T y)
3014 {
3015 return static_cast<T>(x & y);
3016 }
3017
test_not(T x)3018 static inline T test_not(T x)
3019 {
3020 return static_cast<T>(~x);
3021 }
3022
test_iequal(T x,T y)3023 static inline T test_iequal(T x, T y)
3024 {
3025 if (x == y)
3026 return static_cast<T>(1);
3027 else
3028 return static_cast<T>(0);
3029 }
3030
test_inotequal(T x,T y)3031 static inline T test_inotequal(T x, T y)
3032 {
3033 if (x != y)
3034 return static_cast<T>(1);
3035 else
3036 return static_cast<T>(0);
3037 }
3038
test_ugreaterthan(T x,T y)3039 static inline T test_ugreaterthan(T x, T y)
3040 {
3041 if (x > y)
3042 return static_cast<T>(1);
3043 else
3044 return static_cast<T>(0);
3045 }
3046
test_ulessthan(T x,T y)3047 static inline T test_ulessthan(T x, T y)
3048 {
3049 return test_ugreaterthan(y, x);
3050 }
3051
test_sgreaterthan(T x,T y)3052 static inline T test_sgreaterthan(T x, T y)
3053 {
3054 if (x > y)
3055 return static_cast<T>(1);
3056 else
3057 return static_cast<T>(0);
3058 }
3059
test_slessthan(T x,T y)3060 static inline T test_slessthan(T x, T y)
3061 {
3062 return test_sgreaterthan(y, x);
3063 }
3064
test_ugreaterthanequal(T x,T y)3065 static inline T test_ugreaterthanequal(T x, T y)
3066 {
3067 if (x >= y)
3068 return static_cast<T>(1);
3069 else
3070 return static_cast<T>(0);
3071 }
3072
test_ulessthanequal(T x,T y)3073 static inline T test_ulessthanequal(T x, T y)
3074 {
3075 return test_ugreaterthanequal(y, x);
3076 }
3077
test_sgreaterthanequal(T x,T y)3078 static inline T test_sgreaterthanequal(T x, T y)
3079 {
3080 if (x >= y)
3081 return static_cast<T>(1);
3082 else
3083 return static_cast<T>(0);
3084 }
3085
test_slessthanequal(T x,T y)3086 static inline T test_slessthanequal(T x, T y)
3087 {
3088 return test_sgreaterthanequal(y, x);
3089 }
3090
test_bitFieldInsert(T base,T insert,T offset,T count)3091 static inline T test_bitFieldInsert(T base, T insert, T offset, T count)
3092 {
3093 const T insertMask = de::rightSetMask(count);
3094
3095 return static_cast<T>((base & ~(insertMask << offset)) | ((insert & insertMask) << offset));
3096 }
3097
test_bitFieldSExtract(T x,T y,T z)3098 static inline T test_bitFieldSExtract(T x, T y, T z)
3099 {
3100 const T allZeros = static_cast<T>(0);
3101
3102 // Count can be 0, in which case the result will be 0
3103 if (z == allZeros)
3104 return allZeros;
3105
3106 const T extractMask = de::rightSetMask(z);
3107 const T signBit = static_cast<T>(x & (1 << (y + z - 1)));
3108 const T signMask = static_cast<T>(signBit ? ~extractMask : allZeros);
3109
3110 return static_cast<T>((signMask & ~extractMask) | ((x >> y) & extractMask));
3111 }
3112
test_bitFieldUExtract(T x,T y,T z)3113 static inline T test_bitFieldUExtract(T x, T y, T z)
3114 {
3115 const T allZeros = (static_cast<T>(0));
3116
3117 // Count can be 0, in which case the result will be 0
3118 if (z == allZeros)
3119 return allZeros;
3120
3121 const T extractMask = de::rightSetMask(z);
3122
3123 return static_cast<T>((x >> y) & extractMask);
3124 }
3125
test_bitReverse(T x)3126 static inline T test_bitReverse(T x)
3127 {
3128 T base = x;
3129 T result = static_cast<T>(0);
3130
3131 for (size_t bitNdx = 0u; bitNdx < sizeof(T) * 8u; bitNdx++)
3132 {
3133 result = static_cast<T>(result << 1) | (base & 1);
3134 base >>= 1;
3135 }
3136
3137 return result;
3138 }
3139
test_bitCount(T x)3140 static inline T test_bitCount(T x)
3141 {
3142 T count = static_cast<T>(0);
3143
3144 for (uint32_t bitNdx = 0u; bitNdx < (uint32_t)sizeof(T) * 8u; bitNdx++)
3145 if (x & (static_cast<T>(1) << bitNdx))
3146 count++;
3147
3148 return count;
3149 }
3150
test_constant(T a)3151 static inline T test_constant(T a)
3152 {
3153 return a;
3154 }
3155 };
3156
3157 class TestMathInt8 : public TestMath<int8_t>
3158 {
3159 public:
test_msb(int8_t x)3160 static inline int8_t test_msb(int8_t x)
3161 {
3162 if (x > 0)
3163 return static_cast<int8_t>(7 - deClz32((uint32_t)x));
3164 else if (x < 0)
3165 return static_cast<int8_t>(7 - deClz32(~(uint32_t)x));
3166 else
3167 return -1;
3168 }
3169
test_mul_div(int8_t x,int8_t y)3170 static inline int8_t test_mul_div(int8_t x, int8_t y)
3171 {
3172 int32_t x32 = static_cast<int32_t>(x);
3173 int32_t y32 = static_cast<int32_t>(y);
3174
3175 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3176 if (y == static_cast<int8_t>(0))
3177 return 0;
3178 else
3179 return static_cast<int8_t>(static_cast<int8_t>(x32 * y32) / y32);
3180 }
3181
test_ugreaterthan(int8_t x,int8_t y)3182 static inline int8_t test_ugreaterthan(int8_t x, int8_t y)
3183 {
3184 // Consume signed integers as unsigned integers
3185 if ((x & 0x80) ^ (y & 0x80))
3186 std::swap(x, y);
3187
3188 if (x > y)
3189 return static_cast<int8_t>(1);
3190 else
3191 return static_cast<int8_t>(0);
3192 }
3193
test_ulessthan(int8_t x,int8_t y)3194 static inline int8_t test_ulessthan(int8_t x, int8_t y)
3195 {
3196 return test_ugreaterthan(y, x);
3197 }
3198
test_ugreaterthanequal(int8_t x,int8_t y)3199 static inline int8_t test_ugreaterthanequal(int8_t x, int8_t y)
3200 {
3201 // Consume signed integers as unsigned integers
3202 if ((x & 0x80) ^ (y & 0x80))
3203 std::swap(x, y);
3204
3205 if (x >= y)
3206 return static_cast<int8_t>(1);
3207 else
3208 return static_cast<int8_t>(0);
3209 }
3210
test_ulessthanequal(int8_t x,int8_t y)3211 static inline int8_t test_ulessthanequal(int8_t x, int8_t y)
3212 {
3213 return test_ugreaterthanequal(y, x);
3214 }
3215 };
3216
3217 class TestMathInt16 : public TestMath<int16_t>
3218 {
3219 public:
test_msb(int16_t x)3220 static inline int16_t test_msb(int16_t x)
3221 {
3222 if (x > 0)
3223 return static_cast<int16_t>(15 - deClz32((uint32_t)x));
3224 else if (x < 0)
3225 return static_cast<int16_t>(15 - deClz32(~(uint32_t)x));
3226 else
3227 return -1;
3228 }
3229
test_mul_div(int16_t x,int16_t y)3230 static inline int16_t test_mul_div(int16_t x, int16_t y)
3231 {
3232 int32_t x32 = static_cast<int32_t>(x);
3233 int32_t y32 = static_cast<int32_t>(y);
3234
3235 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3236 if (y == static_cast<int16_t>(0))
3237 return 0;
3238 else
3239 return static_cast<int16_t>(static_cast<int16_t>(x32 * y32) / y32);
3240 }
3241
test_ugreaterthan(int16_t x,int16_t y)3242 static inline int16_t test_ugreaterthan(int16_t x, int16_t y)
3243 {
3244 // Consume signed integers as unsigned integers
3245 if ((x & 0x8000) ^ (y & 0x8000))
3246 std::swap(x, y);
3247
3248 if (x > y)
3249 return static_cast<int16_t>(1);
3250 else
3251 return static_cast<int16_t>(0);
3252 }
3253
test_ulessthan(int16_t x,int16_t y)3254 static inline int16_t test_ulessthan(int16_t x, int16_t y)
3255 {
3256 return test_ugreaterthan(y, x);
3257 }
3258
test_ugreaterthanequal(int16_t x,int16_t y)3259 static inline int16_t test_ugreaterthanequal(int16_t x, int16_t y)
3260 {
3261 // Consume signed integers as unsigned integers
3262 if ((x & 0x8000) ^ (y & 0x8000))
3263 std::swap(x, y);
3264
3265 if (x >= y)
3266 return static_cast<int16_t>(1);
3267 else
3268 return static_cast<int16_t>(0);
3269 }
3270
test_ulessthanequal(int16_t x,int16_t y)3271 static inline int16_t test_ulessthanequal(int16_t x, int16_t y)
3272 {
3273 return test_ugreaterthanequal(y, x);
3274 }
3275 };
3276
3277 class TestMathInt32 : public TestMath<int32_t>
3278 {
3279 public:
test_msb(int32_t x)3280 static inline int32_t test_msb(int32_t x)
3281 {
3282 if (x > 0)
3283 return 31 - deClz32((uint32_t)x);
3284 else if (x < 0)
3285 return 31 - deClz32(~(uint32_t)x);
3286 else
3287 return -1;
3288 }
3289
test_ugreaterthan(int32_t x,int32_t y)3290 static inline int32_t test_ugreaterthan(int32_t x, int32_t y)
3291 {
3292 // Consume signed integers as unsigned integers
3293 if ((x & 0x80000000) ^ (y & 0x80000000))
3294 std::swap(x, y);
3295
3296 if (x > y)
3297 return static_cast<int32_t>(1);
3298 else
3299 return static_cast<int32_t>(0);
3300 }
3301
test_ulessthan(int32_t x,int32_t y)3302 static inline int32_t test_ulessthan(int32_t x, int32_t y)
3303 {
3304 return test_ugreaterthan(y, x);
3305 }
3306
test_ugreaterthanequal(int32_t x,int32_t y)3307 static inline int32_t test_ugreaterthanequal(int32_t x, int32_t y)
3308 {
3309 // Consume signed integers as unsigned integers
3310 if ((x & 0x80000000) ^ (y & 0x80000000))
3311 std::swap(x, y);
3312
3313 if (x >= y)
3314 return static_cast<int32_t>(1);
3315 else
3316 return static_cast<int32_t>(0);
3317 }
3318
test_ulessthanequal(int32_t x,int32_t y)3319 static inline int32_t test_ulessthanequal(int32_t x, int32_t y)
3320 {
3321 return test_ugreaterthanequal(y, x);
3322 }
3323 };
3324
3325 class TestMathInt64 : public TestMath<int64_t>
3326 {
3327 public:
test_ugreaterthan(int64_t x,int64_t y)3328 static inline int64_t test_ugreaterthan(int64_t x, int64_t y)
3329 {
3330 // Consume signed integers as unsigned integers
3331 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3332 std::swap(x, y);
3333
3334 if (x > y)
3335 return static_cast<int64_t>(1);
3336 else
3337 return static_cast<int64_t>(0);
3338 }
3339
test_ulessthan(int64_t x,int64_t y)3340 static inline int64_t test_ulessthan(int64_t x, int64_t y)
3341 {
3342 return test_ugreaterthan(y, x);
3343 }
3344
test_ugreaterthanequal(int64_t x,int64_t y)3345 static inline int64_t test_ugreaterthanequal(int64_t x, int64_t y)
3346 {
3347 // Consume signed integers as unsigned integers
3348 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3349 std::swap(x, y);
3350
3351 if (x >= y)
3352 return static_cast<int64_t>(1);
3353 else
3354 return static_cast<int64_t>(0);
3355 }
3356
test_ulessthanequal(int64_t x,int64_t y)3357 static inline int64_t test_ulessthanequal(int64_t x, int64_t y)
3358 {
3359 return test_ugreaterthanequal(y, x);
3360 }
3361 };
3362
3363 class TestMathUint8 : public TestMath<uint8_t>
3364 {
3365 public:
test_msb(uint8_t x)3366 static inline uint32_t test_msb(uint8_t x)
3367 {
3368 if (x > 0)
3369 return 7 - deClz32((uint32_t)x);
3370 else
3371 return -1;
3372 }
3373
test_mul_div(uint8_t x,uint8_t y)3374 static inline uint8_t test_mul_div(uint8_t x, uint8_t y)
3375 {
3376 const uint32_t x32 = static_cast<uint32_t>(x);
3377 const uint32_t y32 = static_cast<uint32_t>(y);
3378
3379 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3380 if (y == static_cast<uint8_t>(0))
3381 return 0;
3382 else
3383 return static_cast<uint8_t>(static_cast<uint8_t>(x32 * y32) / y32);
3384 }
3385
test_sgreaterthan(uint8_t x,uint8_t y)3386 static inline uint8_t test_sgreaterthan(uint8_t x, uint8_t y)
3387 {
3388 // Consume unsigned integers as signed integers
3389 if ((x & 0x80) ^ (y & 0x80))
3390 std::swap(x, y);
3391
3392 if (x > y)
3393 return static_cast<uint8_t>(1);
3394 else
3395 return static_cast<uint8_t>(0);
3396 }
3397
test_slessthan(uint8_t x,uint8_t y)3398 static inline uint8_t test_slessthan(uint8_t x, uint8_t y)
3399 {
3400 return test_sgreaterthan(y, x);
3401 }
3402
test_sgreaterthanequal(uint8_t x,uint8_t y)3403 static inline uint8_t test_sgreaterthanequal(uint8_t x, uint8_t y)
3404 {
3405 // Consume unsigned integers as signed integers
3406 if ((x & 0x80) ^ (y & 0x80))
3407 std::swap(x, y);
3408
3409 if (x >= y)
3410 return static_cast<uint8_t>(1);
3411 else
3412 return static_cast<uint8_t>(0);
3413 }
3414
test_slessthanequal(uint8_t x,uint8_t y)3415 static inline uint8_t test_slessthanequal(uint8_t x, uint8_t y)
3416 {
3417 return test_sgreaterthanequal(y, x);
3418 }
3419 };
3420
3421 class TestMathUint16 : public TestMath<uint16_t>
3422 {
3423 public:
test_msb(uint16_t x)3424 static inline uint32_t test_msb(uint16_t x)
3425 {
3426 if (x > 0)
3427 return 15 - deClz32((uint32_t)x);
3428 else
3429 return -1;
3430 }
3431
test_mul_div(uint16_t x,uint16_t y)3432 static inline uint16_t test_mul_div(uint16_t x, uint16_t y)
3433 {
3434 const uint32_t x32 = static_cast<uint32_t>(x);
3435 const uint32_t y32 = static_cast<uint32_t>(y);
3436
3437 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3438 if (y == static_cast<uint16_t>(0))
3439 return 0;
3440 else
3441 return static_cast<uint16_t>(static_cast<uint16_t>(x32 * y32) / y32);
3442 }
3443
test_sgreaterthan(uint16_t x,uint16_t y)3444 static inline uint16_t test_sgreaterthan(uint16_t x, uint16_t y)
3445 {
3446 // Consume unsigned integers as signed integers
3447 if ((x & 0x8000) ^ (y & 0x8000))
3448 std::swap(x, y);
3449
3450 if (x > y)
3451 return static_cast<uint16_t>(1);
3452 else
3453 return static_cast<uint16_t>(0);
3454 }
3455
test_slessthan(uint16_t x,uint16_t y)3456 static inline uint16_t test_slessthan(uint16_t x, uint16_t y)
3457 {
3458 return test_sgreaterthan(y, x);
3459 }
3460
test_sgreaterthanequal(uint16_t x,uint16_t y)3461 static inline uint16_t test_sgreaterthanequal(uint16_t x, uint16_t y)
3462 {
3463 // Consume unsigned integers as signed integers
3464 if ((x & 0x8000) ^ (y & 0x8000))
3465 std::swap(x, y);
3466
3467 if (x >= y)
3468 return static_cast<uint16_t>(1);
3469 else
3470 return static_cast<uint16_t>(0);
3471 }
3472
test_slessthanequal(uint16_t x,uint16_t y)3473 static inline uint16_t test_slessthanequal(uint16_t x, uint16_t y)
3474 {
3475 return test_sgreaterthanequal(y, x);
3476 }
3477 };
3478
3479 class TestMathUint32 : public TestMath<uint32_t>
3480 {
3481 public:
test_msb(uint32_t x)3482 static inline uint32_t test_msb(uint32_t x)
3483 {
3484 if (x > 0)
3485 return 31 - deClz32(x);
3486 else
3487 return -1;
3488 }
3489
test_sgreaterthan(uint32_t x,uint32_t y)3490 static inline uint32_t test_sgreaterthan(uint32_t x, uint32_t y)
3491 {
3492 // Consume unsigned integers as signed integers
3493 if ((x & 0x80000000) ^ (y & 0x80000000))
3494 std::swap(x, y);
3495
3496 if (x > y)
3497 return static_cast<uint32_t>(1);
3498 else
3499 return static_cast<uint32_t>(0);
3500 }
3501
test_slessthan(uint32_t x,uint32_t y)3502 static inline uint32_t test_slessthan(uint32_t x, uint32_t y)
3503 {
3504 return test_sgreaterthan(y, x);
3505 }
3506
test_sgreaterthanequal(uint32_t x,uint32_t y)3507 static inline uint32_t test_sgreaterthanequal(uint32_t x, uint32_t y)
3508 {
3509 // Consume unsigned integers as signed integers
3510 if ((x & 0x80000000) ^ (y & 0x80000000))
3511 std::swap(x, y);
3512
3513 if (x >= y)
3514 return static_cast<uint32_t>(1);
3515 else
3516 return static_cast<uint32_t>(0);
3517 }
3518
test_slessthanequal(uint32_t x,uint32_t y)3519 static inline uint32_t test_slessthanequal(uint32_t x, uint32_t y)
3520 {
3521 return test_sgreaterthanequal(y, x);
3522 }
3523 };
3524
3525 class TestMathUint64 : public TestMath<uint64_t>
3526 {
3527 public:
test_sgreaterthan(uint64_t x,uint64_t y)3528 static inline uint64_t test_sgreaterthan(uint64_t x, uint64_t y)
3529 {
3530 // Consume unsigned integers as signed integers
3531 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3532 std::swap(x, y);
3533
3534 if (x > y)
3535 return static_cast<uint64_t>(1);
3536 else
3537 return static_cast<uint64_t>(0);
3538 }
3539
test_slessthan(uint64_t x,uint64_t y)3540 static inline uint64_t test_slessthan(uint64_t x, uint64_t y)
3541 {
3542 return test_sgreaterthan(y, x);
3543 }
3544
test_sgreaterthanequal(uint64_t x,uint64_t y)3545 static inline uint64_t test_sgreaterthanequal(uint64_t x, uint64_t y)
3546 {
3547 // Consume unsigned integers as signed integers
3548 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3549 std::swap(x, y);
3550
3551 if (x >= y)
3552 return static_cast<uint64_t>(1);
3553 else
3554 return static_cast<uint64_t>(0);
3555 }
3556
test_slessthanequal(uint64_t x,uint64_t y)3557 static inline uint64_t test_slessthanequal(uint64_t x, uint64_t y)
3558 {
3559 return test_sgreaterthanequal(y, x);
3560 }
3561 };
3562
3563 #define I8_FILTER_NONE SpvAsmTypeInt8Tests::filterNone
3564 #define I16_FILTER_NONE SpvAsmTypeInt16Tests::filterNone
3565 #define I32_FILTER_NONE SpvAsmTypeInt32Tests::filterNone
3566 #define I64_FILTER_NONE SpvAsmTypeInt64Tests::filterNone
3567 #define U8_FILTER_NONE SpvAsmTypeUint8Tests::filterNone
3568 #define U16_FILTER_NONE SpvAsmTypeUint16Tests::filterNone
3569 #define U32_FILTER_NONE SpvAsmTypeUint32Tests::filterNone
3570 #define U64_FILTER_NONE SpvAsmTypeUint64Tests::filterNone
3571
3572 #define I8_FILTER_ZERO SpvAsmTypeInt8Tests::filterZero
3573 #define I16_FILTER_ZERO SpvAsmTypeInt16Tests::filterZero
3574 #define I32_FILTER_ZERO SpvAsmTypeInt32Tests::filterZero
3575 #define I64_FILTER_ZERO SpvAsmTypeInt64Tests::filterZero
3576 #define U8_FILTER_ZERO SpvAsmTypeUint8Tests::filterZero
3577 #define U16_FILTER_ZERO SpvAsmTypeUint16Tests::filterZero
3578 #define U32_FILTER_ZERO SpvAsmTypeUint32Tests::filterZero
3579 #define U64_FILTER_ZERO SpvAsmTypeUint64Tests::filterZero
3580
3581 #define I8_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt8Tests::filterNegativesAndZero
3582 #define I16_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt16Tests::filterNegativesAndZero
3583 #define I32_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt32Tests::filterNegativesAndZero
3584 #define I64_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt64Tests::filterNegativesAndZero
3585 #define U8_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint8Tests::filterNegativesAndZero
3586 #define U16_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint16Tests::filterNegativesAndZero
3587 #define U32_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint32Tests::filterNegativesAndZero
3588 #define U64_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint64Tests::filterNegativesAndZero
3589
3590 #define I8_FILTER_MIN_GT_MAX SpvAsmTypeInt8Tests::filterMinGtMax
3591 #define I16_FILTER_MIN_GT_MAX SpvAsmTypeInt16Tests::filterMinGtMax
3592 #define I32_FILTER_MIN_GT_MAX SpvAsmTypeInt32Tests::filterMinGtMax
3593 #define I64_FILTER_MIN_GT_MAX SpvAsmTypeInt64Tests::filterMinGtMax
3594 #define U8_FILTER_MIN_GT_MAX SpvAsmTypeUint8Tests::filterMinGtMax
3595 #define U16_FILTER_MIN_GT_MAX SpvAsmTypeUint16Tests::filterMinGtMax
3596 #define U32_FILTER_MIN_GT_MAX SpvAsmTypeUint32Tests::filterMinGtMax
3597 #define U64_FILTER_MIN_GT_MAX SpvAsmTypeUint64Tests::filterMinGtMax
3598
3599 const string bitShiftTestPostfix[] = {"_shift8", "_shift16", "_shift32", "_shift64"};
3600
3601 const string bitFieldTestPostfix[] = {
3602 "_offset8_count8", "_offset8_count16", "_offset8_count32", "_offset8_count64",
3603 "_offset16_count8", "_offset16_count16", "_offset16_count32", "_offset16_count64",
3604 "_offset32_count8", "_offset32_count16", "_offset32_count32", "_offset32_count64",
3605 "_offset64_count8", "_offset64_count16", "_offset64_count32", "_offset64_count64",
3606 };
3607
3608 // Macro to create tests.
3609 // Syntax: MAKE_TEST_{S,V}_{I,U}_{8,1,3,6}
3610 //
3611 // 'S': create scalar test
3612 // 'V': create vector test
3613 //
3614 // 'I': create integer test
3615 // 'U': create unsigned integer test
3616 //
3617 // '8': create 8-bit test
3618 // '1': create 16-bit test
3619 // '3': create 32-bit test
3620 // '6': create 64-bit test
3621 //
3622 // 'W': bit width of some parameters in bit field and shift operations can be different from Result and Base
3623 // 'N': create 16-bit tests without 'test_high_part_zero' variants
3624
3625 #define MAKE_TEST_S_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3626 for (uint32_t ndx = 0; ndx < 1; ++ndx) \
3627 { \
3628 int8Tests[ndx]->createTests((name), (spirvOp), TestMathInt8::test_##op, I8_##filter, inputRange, \
3629 WIDTH_DEFAULT, (extension)); \
3630 int16Tests[ndx]->createTests((name), (spirvOp), TestMathInt16::test_##op, I16_##filter, inputRange, \
3631 WIDTH_DEFAULT, (extension)); \
3632 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathInt16::test_##op, I16_##filter, \
3633 inputRange, WIDTH_DEFAULT, (extension), true); \
3634 int32Tests[ndx]->createTests((name), (spirvOp), TestMathInt32::test_##op, I32_##filter, inputRange, \
3635 WIDTH_DEFAULT, (extension)); \
3636 int64Tests[ndx]->createTests((name), (spirvOp), TestMathInt64::test_##op, I64_##filter, inputRange, \
3637 WIDTH_DEFAULT, (extension)); \
3638 }
3639
3640 #define MAKE_TEST_V_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3641 for (uint32_t ndx = 1; ndx < 4; ++ndx) \
3642 { \
3643 int8Tests[ndx]->createTests((name), (spirvOp), TestMathInt8::test_##op, I8_##filter, inputRange, \
3644 WIDTH_DEFAULT, (extension)); \
3645 int16Tests[ndx]->createTests((name), (spirvOp), TestMathInt16::test_##op, I16_##filter, inputRange, \
3646 WIDTH_DEFAULT, (extension)); \
3647 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathInt16::test_##op, I16_##filter, \
3648 inputRange, WIDTH_DEFAULT, (extension), true); \
3649 int32Tests[ndx]->createTests((name), (spirvOp), TestMathInt32::test_##op, I32_##filter, inputRange, \
3650 WIDTH_DEFAULT, (extension)); \
3651 int64Tests[ndx]->createTests((name), (spirvOp), TestMathInt64::test_##op, I64_##filter, inputRange, \
3652 WIDTH_DEFAULT, (extension)); \
3653 }
3654
3655 #define MAKE_TEST_SV_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3656 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3657 { \
3658 int8Tests[ndx]->createTests((name), (spirvOp), TestMathInt8::test_##op, I8_##filter, inputRange, \
3659 WIDTH_DEFAULT, (extension)); \
3660 int16Tests[ndx]->createTests((name), (spirvOp), TestMathInt16::test_##op, I16_##filter, inputRange, \
3661 WIDTH_DEFAULT, (extension)); \
3662 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathInt16::test_##op, I16_##filter, \
3663 inputRange, WIDTH_DEFAULT, (extension), true); \
3664 int32Tests[ndx]->createTests((name), (spirvOp), TestMathInt32::test_##op, I32_##filter, inputRange, \
3665 WIDTH_DEFAULT, (extension)); \
3666 int64Tests[ndx]->createTests((name), (spirvOp), TestMathInt64::test_##op, I64_##filter, inputRange, \
3667 WIDTH_DEFAULT, (extension)); \
3668 }
3669
3670 #define MAKE_TEST_SV_I_8136_N(name, spirvOp, op, filter, inputRange, extension) \
3671 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3672 { \
3673 int8Tests[ndx]->createTests((name), (spirvOp), TestMathInt8::test_##op, I8_##filter, inputRange, \
3674 WIDTH_DEFAULT, (extension)); \
3675 int16Tests[ndx]->createTests((name), (spirvOp), TestMathInt16::test_##op, I16_##filter, inputRange, \
3676 WIDTH_DEFAULT, (extension)); \
3677 int32Tests[ndx]->createTests((name), (spirvOp), TestMathInt32::test_##op, I32_##filter, inputRange, \
3678 WIDTH_DEFAULT, (extension)); \
3679 int64Tests[ndx]->createTests((name), (spirvOp), TestMathInt64::test_##op, I64_##filter, inputRange, \
3680 WIDTH_DEFAULT, (extension)); \
3681 }
3682
3683 #define MAKE_TEST_SV_I_8136_W(name, spirvOp, op, filter, inputRange, extension) \
3684 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3685 for (uint32_t widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(bitShiftTestPostfix); ++widthNdx) \
3686 { \
3687 const InputWidth inputWidth = static_cast<InputWidth>(WIDTH_8 + widthNdx); \
3688 \
3689 int8Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3690 TestMathInt8::test_##op, I8_##filter, inputRange, inputWidth, (extension)); \
3691 int16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3692 TestMathInt16::test_##op, I16_##filter, inputRange, inputWidth, (extension)); \
3693 int16Tests[ndx]->createTests( \
3694 string(name + bitShiftTestPostfix[widthNdx] + "_test_high_part_zero").c_str(), (spirvOp), \
3695 TestMathInt16::test_##op, I16_##filter, inputRange, inputWidth, (extension), true); \
3696 int32Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3697 TestMathInt32::test_##op, I32_##filter, inputRange, inputWidth, (extension)); \
3698 int64Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3699 TestMathInt64::test_##op, I64_##filter, inputRange, inputWidth, (extension)); \
3700 }
3701
3702 #define MAKE_TEST_SV_I_1(name, spirvOp, op, filter, inputRange, extension) \
3703 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3704 { \
3705 int16Tests[ndx]->createTests((name), (spirvOp), TestMathInt16::test_##op, I16_##filter, inputRange, \
3706 WIDTH_DEFAULT, (extension)); \
3707 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathInt16::test_##op, I16_##filter, \
3708 inputRange, WIDTH_DEFAULT, (extension), true); \
3709 }
3710
3711 #define MAKE_TEST_SV_I_3(name, spirvOp, op, filter, inputRange, extension) \
3712 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3713 int32Tests[ndx]->createTests((name), (spirvOp), TestMathInt32::test_##op, I32_##filter, inputRange, \
3714 WIDTH_DEFAULT, (extension));
3715
3716 #define MAKE_TEST_SV_I_3_W(name, spirvOp, op, filter, inputRange, extension) \
3717 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3718 for (uint32_t width = 0; width < DE_LENGTH_OF_ARRAY(bitFieldTestPostfix); ++width) \
3719 { \
3720 int32Tests[ndx]->createTests(string(name + bitFieldTestPostfix[width]).c_str(), (spirvOp), \
3721 TestMathInt32::test_##op, I32_##filter, inputRange, \
3722 InputWidth(WIDTH_8_8 + width), (extension)); \
3723 }
3724
3725 #define MAKE_TEST_S_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3726 for (uint32_t ndx = 0; ndx < 1; ++ndx) \
3727 { \
3728 uint8Tests[ndx]->createTests((name), (spirvOp), TestMathUint8::test_##op, U8_##filter, inputRange, \
3729 WIDTH_DEFAULT, (extension)); \
3730 uint16Tests[ndx]->createTests((name), (spirvOp), TestMathUint16::test_##op, U16_##filter, inputRange, \
3731 WIDTH_DEFAULT, (extension)); \
3732 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathUint16::test_##op, \
3733 U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3734 uint32Tests[ndx]->createTests((name), (spirvOp), TestMathUint32::test_##op, U32_##filter, inputRange, \
3735 WIDTH_DEFAULT, (extension)); \
3736 uint64Tests[ndx]->createTests((name), (spirvOp), TestMathUint64::test_##op, U64_##filter, inputRange, \
3737 WIDTH_DEFAULT, (extension)); \
3738 }
3739
3740 #define MAKE_TEST_V_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3741 for (uint32_t ndx = 1; ndx < 4; ++ndx) \
3742 { \
3743 uint16Tests[ndx]->createTests((name), (spirvOp), TestMathUint16::test_##op, U16_##filter, inputRange, \
3744 WIDTH_DEFAULT, (extension)); \
3745 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathUint16::test_##op, \
3746 U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3747 uint32Tests[ndx]->createTests((name), (spirvOp), TestMathUint32::test_##op, U32_##filter, inputRange, \
3748 WIDTH_DEFAULT, (extension)); \
3749 uint64Tests[ndx]->createTests((name), (spirvOp), TestMathUint64::test_##op, U64_##filter, inputRange, \
3750 WIDTH_DEFAULT, (extension)); \
3751 }
3752
3753 #define MAKE_TEST_SV_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3754 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3755 { \
3756 uint8Tests[ndx]->createTests((name), (spirvOp), TestMathUint8::test_##op, U8_##filter, inputRange, \
3757 WIDTH_DEFAULT, (extension)); \
3758 uint16Tests[ndx]->createTests((name), (spirvOp), TestMathUint16::test_##op, U16_##filter, inputRange, \
3759 WIDTH_DEFAULT, (extension)); \
3760 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathUint16::test_##op, \
3761 U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3762 uint32Tests[ndx]->createTests((name), (spirvOp), TestMathUint32::test_##op, U32_##filter, inputRange, \
3763 WIDTH_DEFAULT, (extension)); \
3764 uint64Tests[ndx]->createTests((name), (spirvOp), TestMathUint64::test_##op, U64_##filter, inputRange, \
3765 WIDTH_DEFAULT, (extension)); \
3766 }
3767
3768 #define MAKE_TEST_SV_U_8136_N(name, spirvOp, op, filter, inputRange, extension) \
3769 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3770 { \
3771 uint8Tests[ndx]->createTests((name), (spirvOp), TestMathUint8::test_##op, U8_##filter, inputRange, \
3772 WIDTH_DEFAULT, (extension)); \
3773 uint16Tests[ndx]->createTests((name), (spirvOp), TestMathUint16::test_##op, U16_##filter, inputRange, \
3774 WIDTH_DEFAULT, (extension)); \
3775 uint32Tests[ndx]->createTests((name), (spirvOp), TestMathUint32::test_##op, U32_##filter, inputRange, \
3776 WIDTH_DEFAULT, (extension)); \
3777 uint64Tests[ndx]->createTests((name), (spirvOp), TestMathUint64::test_##op, U64_##filter, inputRange, \
3778 WIDTH_DEFAULT, (extension)); \
3779 }
3780
3781 #define MAKE_TEST_SV_U_8136_W(name, spirvOp, op, filter, inputRange, extension) \
3782 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3783 for (uint32_t widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(bitShiftTestPostfix); ++widthNdx) \
3784 { \
3785 const InputWidth inputWidth = static_cast<InputWidth>(WIDTH_8 + widthNdx); \
3786 \
3787 uint8Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3788 TestMathUint8::test_##op, U8_##filter, inputRange, inputWidth, (extension)); \
3789 uint16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3790 TestMathUint16::test_##op, U16_##filter, inputRange, inputWidth, \
3791 (extension)); \
3792 uint16Tests[ndx]->createTests( \
3793 string(name + bitShiftTestPostfix[widthNdx] + "_test_high_part_zero").c_str(), (spirvOp), \
3794 TestMathUint16::test_##op, U16_##filter, inputRange, inputWidth, (extension), true); \
3795 uint32Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3796 TestMathUint32::test_##op, U32_##filter, inputRange, inputWidth, \
3797 (extension)); \
3798 uint64Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3799 TestMathUint64::test_##op, U64_##filter, inputRange, inputWidth, \
3800 (extension)); \
3801 }
3802
3803 #define MAKE_TEST_SV_U_1(name, spirvOp, op, filter, inputRange, extension) \
3804 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3805 { \
3806 uint16Tests[ndx]->createTests((name), (spirvOp), TestMathUint16::test_##op, U16_##filter, inputRange, \
3807 WIDTH_DEFAULT, (extension)); \
3808 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), TestMathUint16::test_##op, \
3809 U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3810 }
3811
3812 #define MAKE_TEST_SV_U_3(name, spirvOp, op, filter, inputRange, extension) \
3813 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3814 uint32Tests[ndx]->createTests((name), (spirvOp), TestMathUint32::test_##op, U32_##filter, inputRange, \
3815 WIDTH_DEFAULT, (extension));
3816
3817 #define MAKE_TEST_SV_U_3_W(name, spirvOp, op, filter, inputRange, extension) \
3818 for (uint32_t ndx = 0; ndx < 4; ++ndx) \
3819 for (uint32_t width = 0; width < DE_LENGTH_OF_ARRAY(bitFieldTestPostfix); ++width) \
3820 { \
3821 uint32Tests[ndx]->createTests(string(name + bitFieldTestPostfix[width]).c_str(), (spirvOp), \
3822 TestMathUint32::test_##op, U32_##filter, inputRange, \
3823 InputWidth(WIDTH_8_8 + width), (extension)); \
3824 }
3825
createTypeTests(tcu::TestContext & testCtx)3826 tcu::TestCaseGroup *createTypeTests(tcu::TestContext &testCtx)
3827 {
3828 de::MovePtr<tcu::TestCaseGroup> typeTests(new tcu::TestCaseGroup(testCtx, "type"));
3829 de::MovePtr<tcu::TestCaseGroup> typeScalarTests(new tcu::TestCaseGroup(testCtx, "scalar"));
3830 de::MovePtr<tcu::TestCaseGroup> typeVectorTests[3];
3831
3832 de::MovePtr<SpvAsmTypeInt8Tests> int8Tests[4];
3833 de::MovePtr<SpvAsmTypeInt16Tests> int16Tests[4];
3834 de::MovePtr<SpvAsmTypeInt32Tests> int32Tests[4];
3835 de::MovePtr<SpvAsmTypeInt64Tests> int64Tests[4];
3836 de::MovePtr<SpvAsmTypeUint8Tests> uint8Tests[4];
3837 de::MovePtr<SpvAsmTypeUint16Tests> uint16Tests[4];
3838 de::MovePtr<SpvAsmTypeUint32Tests> uint32Tests[4];
3839 de::MovePtr<SpvAsmTypeUint64Tests> uint64Tests[4];
3840
3841 for (uint32_t ndx = 0; ndx < 3; ++ndx)
3842 {
3843 std::string testName = "vec" + de::toString(ndx + 2);
3844 typeVectorTests[ndx] = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, testName.c_str()));
3845 }
3846
3847 for (uint32_t ndx = 0; ndx < 4; ++ndx)
3848 {
3849 int8Tests[ndx] = de::MovePtr<SpvAsmTypeInt8Tests>(new SpvAsmTypeInt8Tests(testCtx, ndx + 1));
3850 int16Tests[ndx] = de::MovePtr<SpvAsmTypeInt16Tests>(new SpvAsmTypeInt16Tests(testCtx, ndx + 1));
3851 int32Tests[ndx] = de::MovePtr<SpvAsmTypeInt32Tests>(new SpvAsmTypeInt32Tests(testCtx, ndx + 1));
3852 int64Tests[ndx] = de::MovePtr<SpvAsmTypeInt64Tests>(new SpvAsmTypeInt64Tests(testCtx, ndx + 1));
3853 uint8Tests[ndx] = de::MovePtr<SpvAsmTypeUint8Tests>(new SpvAsmTypeUint8Tests(testCtx, ndx + 1));
3854 uint16Tests[ndx] = de::MovePtr<SpvAsmTypeUint16Tests>(new SpvAsmTypeUint16Tests(testCtx, ndx + 1));
3855 uint32Tests[ndx] = de::MovePtr<SpvAsmTypeUint32Tests>(new SpvAsmTypeUint32Tests(testCtx, ndx + 1));
3856 uint64Tests[ndx] = de::MovePtr<SpvAsmTypeUint64Tests>(new SpvAsmTypeUint64Tests(testCtx, ndx + 1));
3857 }
3858
3859 MAKE_TEST_SV_I_8136("negate", SpvOpSNegate, negate, FILTER_NONE, RANGE_FULL, DE_NULL)
3860 MAKE_TEST_SV_I_8136("add", SpvOpIAdd, add, FILTER_NONE, RANGE_FULL, DE_NULL)
3861 MAKE_TEST_SV_I_8136("sub", SpvOpISub, sub, FILTER_NONE, RANGE_FULL, DE_NULL)
3862 MAKE_TEST_SV_I_8136("mul", SpvOpIMul, mul, FILTER_NONE, RANGE_FULL, DE_NULL)
3863 MAKE_TEST_SV_I_8136("div", SpvOpSDiv, div, FILTER_ZERO, RANGE_FULL, DE_NULL)
3864 MAKE_TEST_SV_U_8136("div", SpvOpUDiv, div, FILTER_ZERO, RANGE_FULL, DE_NULL)
3865 MAKE_TEST_SV_I_8136("rem", SpvOpSRem, rem, FILTER_NEGATIVES_AND_ZERO, RANGE_FULL, DE_NULL)
3866 MAKE_TEST_SV_I_8136("mod", SpvOpSMod, mod, FILTER_NEGATIVES_AND_ZERO, RANGE_FULL, DE_NULL)
3867 MAKE_TEST_SV_U_8136("mod", SpvOpUMod, mod, FILTER_ZERO, RANGE_FULL, DE_NULL)
3868 MAKE_TEST_SV_I_8136("abs", GLSLstd450SAbs, abs, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3869 MAKE_TEST_SV_I_8136("sign", GLSLstd450SSign, sign, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3870 MAKE_TEST_SV_I_8136("min", GLSLstd450SMin, min, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3871 MAKE_TEST_SV_U_8136("min", GLSLstd450UMin, min, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3872 MAKE_TEST_SV_I_8136("max", GLSLstd450SMax, max, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3873 MAKE_TEST_SV_U_8136("max", GLSLstd450UMax, max, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3874 MAKE_TEST_SV_I_8136("clamp", GLSLstd450SClamp, clamp, FILTER_MIN_GT_MAX, RANGE_FULL, "GLSL.std.450")
3875 MAKE_TEST_SV_U_8136("clamp", GLSLstd450UClamp, clamp, FILTER_MIN_GT_MAX, RANGE_FULL, "GLSL.std.450")
3876 MAKE_TEST_SV_I_3("find_lsb", GLSLstd450FindILsb, lsb, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3877 MAKE_TEST_SV_I_3("find_msb", GLSLstd450FindSMsb, msb, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3878 MAKE_TEST_SV_U_3("find_msb", GLSLstd450FindUMsb, msb, FILTER_NONE, RANGE_FULL, "GLSL.std.450")
3879 MAKE_TEST_SV_I_1("mul_sdiv", DE_NULL, mul_div, FILTER_ZERO, RANGE_FULL, DE_NULL)
3880 MAKE_TEST_SV_U_1("mul_udiv", DE_NULL, mul_div, FILTER_ZERO, RANGE_FULL, DE_NULL)
3881
3882 MAKE_TEST_SV_U_8136_W("shift_right_logical", SpvOpShiftRightLogical, lsr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL)
3883 MAKE_TEST_SV_I_8136_W("shift_right_logical", SpvOpShiftRightLogical, lsr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL)
3884 MAKE_TEST_SV_U_8136_W("shift_right_arithmetic", SpvOpShiftRightArithmetic, asr, FILTER_NONE, RANGE_BIT_WIDTH,
3885 DE_NULL)
3886 MAKE_TEST_SV_I_8136_W("shift_right_arithmetic", SpvOpShiftRightArithmetic, asr, FILTER_NONE, RANGE_BIT_WIDTH,
3887 DE_NULL)
3888 MAKE_TEST_SV_U_8136_W("shift_left_logical", SpvOpShiftLeftLogical, lsl, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL)
3889 MAKE_TEST_SV_I_8136_W("shift_left_logical", SpvOpShiftLeftLogical, lsl, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL)
3890
3891 MAKE_TEST_SV_U_8136("bitwise_or", SpvOpBitwiseOr, bitwise_or, FILTER_NONE, RANGE_FULL, DE_NULL)
3892 MAKE_TEST_SV_I_8136("bitwise_or", SpvOpBitwiseOr, bitwise_or, FILTER_NONE, RANGE_FULL, DE_NULL)
3893 MAKE_TEST_SV_U_8136("bitwise_xor", SpvOpBitwiseXor, bitwise_xor, FILTER_NONE, RANGE_FULL, DE_NULL)
3894 MAKE_TEST_SV_I_8136("bitwise_xor", SpvOpBitwiseXor, bitwise_xor, FILTER_NONE, RANGE_FULL, DE_NULL)
3895 MAKE_TEST_SV_U_8136("bitwise_and", SpvOpBitwiseAnd, bitwise_and, FILTER_NONE, RANGE_FULL, DE_NULL)
3896 MAKE_TEST_SV_I_8136("bitwise_and", SpvOpBitwiseAnd, bitwise_and, FILTER_NONE, RANGE_FULL, DE_NULL)
3897 MAKE_TEST_SV_U_8136("not", SpvOpNot, not, FILTER_NONE, RANGE_FULL, DE_NULL)
3898 MAKE_TEST_SV_I_8136("not", SpvOpNot, not, FILTER_NONE, RANGE_FULL, DE_NULL)
3899
3900 MAKE_TEST_SV_U_8136_N("iequal", SpvOpIEqual, iequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3901 MAKE_TEST_SV_I_8136_N("iequal", SpvOpIEqual, iequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3902 MAKE_TEST_SV_U_8136_N("inotequal", SpvOpINotEqual, inotequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3903 MAKE_TEST_SV_I_8136_N("inotequal", SpvOpINotEqual, inotequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3904 MAKE_TEST_SV_U_8136_N("ugreaterthan", SpvOpUGreaterThan, ugreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3905 MAKE_TEST_SV_I_8136_N("ugreaterthan", SpvOpUGreaterThan, ugreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3906 MAKE_TEST_SV_U_8136_N("sgreaterthan", SpvOpSGreaterThan, sgreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3907 MAKE_TEST_SV_I_8136_N("sgreaterthan", SpvOpSGreaterThan, sgreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3908 MAKE_TEST_SV_U_8136_N("ugreaterthanequal", SpvOpUGreaterThanEqual, ugreaterthanequal, FILTER_NONE, RANGE_FULL,
3909 DE_NULL)
3910 MAKE_TEST_SV_I_8136_N("ugreaterthanequal", SpvOpUGreaterThanEqual, ugreaterthanequal, FILTER_NONE, RANGE_FULL,
3911 DE_NULL)
3912 MAKE_TEST_SV_U_8136_N("sgreaterthanequal", SpvOpSGreaterThanEqual, sgreaterthanequal, FILTER_NONE, RANGE_FULL,
3913 DE_NULL)
3914 MAKE_TEST_SV_I_8136_N("sgreaterthanequal", SpvOpSGreaterThanEqual, sgreaterthanequal, FILTER_NONE, RANGE_FULL,
3915 DE_NULL)
3916 MAKE_TEST_SV_U_8136_N("ulessthan", SpvOpULessThan, ulessthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3917 MAKE_TEST_SV_I_8136_N("ulessthan", SpvOpULessThan, ulessthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3918 MAKE_TEST_SV_U_8136_N("slessthan", SpvOpSLessThan, slessthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3919 MAKE_TEST_SV_I_8136_N("slessthan", SpvOpSLessThan, slessthan, FILTER_NONE, RANGE_FULL, DE_NULL)
3920 MAKE_TEST_SV_U_8136_N("ulessthanequal", SpvOpULessThanEqual, ulessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3921 MAKE_TEST_SV_I_8136_N("ulessthanequal", SpvOpULessThanEqual, ulessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3922 MAKE_TEST_SV_U_8136_N("slessthanequal", SpvOpSLessThanEqual, slessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3923 MAKE_TEST_SV_I_8136_N("slessthanequal", SpvOpSLessThanEqual, slessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL)
3924
3925 MAKE_TEST_SV_U_3_W("bit_field_insert", SpvOpBitFieldInsert, bitFieldInsert, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3926 DE_NULL)
3927 MAKE_TEST_SV_I_3_W("bit_field_insert", SpvOpBitFieldInsert, bitFieldInsert, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3928 DE_NULL)
3929 MAKE_TEST_SV_U_3_W("bit_field_s_extract", SpvOpBitFieldSExtract, bitFieldSExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3930 DE_NULL)
3931 MAKE_TEST_SV_I_3_W("bit_field_s_extract", SpvOpBitFieldSExtract, bitFieldSExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3932 DE_NULL)
3933 MAKE_TEST_SV_U_3_W("bit_field_u_extract", SpvOpBitFieldUExtract, bitFieldUExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3934 DE_NULL)
3935 MAKE_TEST_SV_I_3_W("bit_field_u_extract", SpvOpBitFieldUExtract, bitFieldUExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM,
3936 DE_NULL)
3937 MAKE_TEST_SV_U_3("bit_reverse", SpvOpBitReverse, bitReverse, FILTER_NONE, RANGE_FULL, DE_NULL)
3938 MAKE_TEST_SV_I_3("bit_reverse", SpvOpBitReverse, bitReverse, FILTER_NONE, RANGE_FULL, DE_NULL)
3939 MAKE_TEST_SV_U_3("bit_count", SpvOpBitCount, bitCount, FILTER_NONE, RANGE_FULL, DE_NULL)
3940 MAKE_TEST_SV_I_3("bit_count", SpvOpBitCount, bitCount, FILTER_NONE, RANGE_FULL, DE_NULL)
3941
3942 MAKE_TEST_S_U_8136("constant", SpvOpConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3943 MAKE_TEST_S_I_8136("constant", SpvOpConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3944 MAKE_TEST_V_U_8136("constant_composite", SpvOpConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3945 MAKE_TEST_V_I_8136("constant_composite", SpvOpConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3946 MAKE_TEST_V_U_8136("constant_null", SpvOpConstantNull, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3947 MAKE_TEST_V_I_8136("constant_null", SpvOpConstantNull, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3948 MAKE_TEST_SV_U_8136("variable_initializer", SpvOpVariable, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3949 MAKE_TEST_SV_I_8136("variable_initializer", SpvOpVariable, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3950 MAKE_TEST_S_U_8136("spec_constant_initializer", SpvOpSpecConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3951 MAKE_TEST_S_I_8136("spec_constant_initializer", SpvOpSpecConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL)
3952 MAKE_TEST_V_U_8136("spec_constant_composite_initializer", SpvOpSpecConstantComposite, constant, FILTER_NONE,
3953 RANGE_FULL, DE_NULL)
3954 MAKE_TEST_V_I_8136("spec_constant_composite_initializer", SpvOpSpecConstantComposite, constant, FILTER_NONE,
3955 RANGE_FULL, DE_NULL)
3956
3957 int8Tests[0]->createSwitchTests();
3958 int16Tests[0]->createSwitchTests();
3959 int32Tests[0]->createSwitchTests();
3960 int64Tests[0]->createSwitchTests();
3961 uint8Tests[0]->createSwitchTests();
3962 uint16Tests[0]->createSwitchTests();
3963 uint32Tests[0]->createSwitchTests();
3964 uint64Tests[0]->createSwitchTests();
3965
3966 typeScalarTests->addChild(int8Tests[0].release());
3967 typeScalarTests->addChild(int16Tests[0].release());
3968 typeScalarTests->addChild(int32Tests[0].release());
3969 typeScalarTests->addChild(int64Tests[0].release());
3970 typeScalarTests->addChild(uint8Tests[0].release());
3971 typeScalarTests->addChild(uint16Tests[0].release());
3972 typeScalarTests->addChild(uint32Tests[0].release());
3973 typeScalarTests->addChild(uint64Tests[0].release());
3974
3975 typeTests->addChild(typeScalarTests.release());
3976
3977 for (uint32_t ndx = 0; ndx < 3; ++ndx)
3978 {
3979 typeVectorTests[ndx]->addChild(int8Tests[ndx + 1].release());
3980 typeVectorTests[ndx]->addChild(int16Tests[ndx + 1].release());
3981 typeVectorTests[ndx]->addChild(int32Tests[ndx + 1].release());
3982 typeVectorTests[ndx]->addChild(int64Tests[ndx + 1].release());
3983 typeVectorTests[ndx]->addChild(uint8Tests[ndx + 1].release());
3984 typeVectorTests[ndx]->addChild(uint16Tests[ndx + 1].release());
3985 typeVectorTests[ndx]->addChild(uint32Tests[ndx + 1].release());
3986 typeVectorTests[ndx]->addChild(uint64Tests[ndx + 1].release());
3987
3988 typeTests->addChild(typeVectorTests[ndx].release());
3989 }
3990
3991 return typeTests.release();
3992 }
3993
3994 } // namespace SpirVAssembly
3995 } // namespace vkt
3996