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