xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTypeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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