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 |= EXTFLOAT16INT8FEATURES_INT8;
1556 }
1557
1558 if (m_inputType == TYPE_I8 || m_inputType == TYPE_U8)
1559 {
1560 requiredFeatures.ext8BitStorage |= EXT8BITSTORAGEFEATURES_UNIFORM_STORAGE_BUFFER;
1561 spirvExtensions += "OpExtension \"SPV_KHR_8bit_storage\"\n";
1562 }
1563
1564 if (m_inputType == TYPE_I16 || m_inputType == TYPE_U16)
1565 {
1566 requiredFeatures.ext16BitStorage |= EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK;
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 computeResources.requestedVulkanFeatures = requiredFeatures;
1635
1636 createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, noExtensions, this, requiredFeatures);
1637 createComputeTest(computeResources, computeShaderTemplate, fragments, *this, testName);
1638 }
1639
1640 template <class T>
valueToStr(const T v)1641 std::string valueToStr(const T v)
1642 {
1643 std::stringstream s;
1644 s << v;
1645 return s.str();
1646 }
1647
1648 template <>
valueToStr(const deUint8 v)1649 std::string valueToStr<deUint8> (const deUint8 v)
1650 {
1651 std::stringstream s;
1652 s << (deUint16)v;
1653 return s.str();
1654 }
1655
1656 template <>
valueToStr(const deInt8 v)1657 std::string valueToStr<deInt8> ( const deInt8 v)
1658 {
1659 std::stringstream s;
1660 s << (deInt16)v;
1661 return s.str();
1662 }
1663
1664 template <class T>
verifyResult(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,deUint32 skip,tcu::TestLog & log)1665 bool SpvAsmTypeTests<T>::verifyResult (const vector<Resource>& inputs,
1666 const vector<AllocationSp>& outputAllocations,
1667 const vector<Resource>& expectedOutputs,
1668 deUint32 skip,
1669 tcu::TestLog& log)
1670 {
1671 DE_ASSERT(outputAllocations.size() == 1);
1672 DE_ASSERT(inputs.size() > 0 && inputs.size() < 5);
1673
1674 const T* input[4] = { DE_NULL };
1675 vector<deUint8> inputBytes[4];
1676 vector<deUint8> expectedBytes;
1677
1678 expectedOutputs[0].getBytes(expectedBytes);
1679 const deUint32 count = static_cast<deUint32>(expectedBytes.size() / sizeof(T));
1680 const T* obtained = static_cast<const T *>(outputAllocations[0]->getHostPtr());
1681 const T* expected = reinterpret_cast<const T*>(&expectedBytes.front());
1682
1683 for (deUint32 ndxCount = 0; ndxCount < inputs.size(); ndxCount++)
1684 {
1685 inputs[ndxCount].getBytes(inputBytes[ndxCount]);
1686 input[ndxCount] = reinterpret_cast<const T*>(&inputBytes[ndxCount].front());
1687 }
1688
1689 for (deUint32 ndxCount = 0 ; ndxCount < count; ++ndxCount)
1690 {
1691 /* Skip padding */
1692 if (((ndxCount + 1) % skip) == 0)
1693 continue;
1694
1695 if (obtained[ndxCount] != expected[ndxCount])
1696 {
1697 std::stringstream inputStream;
1698 inputStream << "(";
1699 for (deUint32 ndxIndex = 0 ; ndxIndex < inputs.size(); ++ndxIndex)
1700 {
1701 inputStream << valueToStr(input[ndxIndex][ndxCount]);
1702 if (ndxIndex < inputs.size() - 1)
1703 inputStream << ",";
1704 }
1705 inputStream << ")";
1706 log << tcu::TestLog::Message
1707 << "Error: found unexpected result for inputs " << inputStream.str()
1708 << ": expected " << valueToStr(expected[ndxCount]) << ", obtained "
1709 << valueToStr(obtained[ndxCount]) << tcu::TestLog::EndMessage;
1710 return false;
1711 }
1712 }
1713
1714 return true;
1715 }
1716
1717 template <class T>
verifyDefaultResult(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,tcu::TestLog & log)1718 bool SpvAsmTypeTests<T>::verifyDefaultResult (const vector<Resource>& inputs,
1719 const vector<AllocationSp>& outputAllocations,
1720 const vector<Resource>& expectedOutputs,
1721 tcu::TestLog& log)
1722 {
1723 return verifyResult(inputs, outputAllocations, expectedOutputs, ~0, log);
1724 }
1725
1726 template <class T>
verifyVec3Result(const vector<Resource> & inputs,const vector<AllocationSp> & outputAllocations,const vector<Resource> & expectedOutputs,tcu::TestLog & log)1727 bool SpvAsmTypeTests<T>::verifyVec3Result (const vector<Resource>& inputs,
1728 const vector<AllocationSp>& outputAllocations,
1729 const vector<Resource>& expectedOutputs,
1730 tcu::TestLog& log)
1731 {
1732 return verifyResult(inputs, outputAllocations, expectedOutputs, 4, log);
1733 }
1734
1735 template <class T>
createConstantDeclaration(vector<T> & dataset,deUint32 spirvOperation)1736 string SpvAsmTypeTests<T>::createConstantDeclaration (vector<T>& dataset, deUint32 spirvOperation)
1737 {
1738 const bool isVariableTest = (SpvOpVariable == spirvOperation);
1739 const bool isConstantNullTest = (SpvOpConstantNull == spirvOperation) || isVariableTest;
1740 const bool isConstantCompositeTest = (SpvOpConstantComposite == spirvOperation) || (isConstantNullTest && m_vectorSize > 1);
1741 const bool isConstantTest = (SpvOpConstant == spirvOperation) || isConstantCompositeTest || isConstantNullTest;
1742 const bool isSpecConstantTest = (SpvOpSpecConstant == spirvOperation);
1743 const bool isSpecConstantCompositeTest = (SpvOpSpecConstantComposite == spirvOperation);
1744
1745 const string testScalarType = (m_inputType == TYPE_I32) ? "i32"
1746 : (m_inputType == TYPE_U32) ? "u32"
1747 : "scalartype";
1748 const string constantType = (m_vectorSize > 1) ? testScalarType : m_spirvTestType;
1749 const string constantName = (m_vectorSize > 1) ? "%c_constituent_" : "%c_testtype_";
1750
1751 string str = "";
1752
1753 // Declare scalar specialization constants
1754 if (isSpecConstantTest)
1755 {
1756 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1757 str += constantName + de::toString(constantNdx) + " = OpSpecConstant %" + constantType + " " + de::toString(dataset[constantNdx]) + "\n";
1758 }
1759
1760 // Declare specialization constant composites
1761 if (isSpecConstantCompositeTest)
1762 {
1763 // Constituents are a mix of OpConstantNull, OpConstants and OpSpecializationConstants
1764 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1765 {
1766 const char* constantOp[] =
1767 {
1768 "OpConstant",
1769 "OpSpecConstant"
1770 };
1771
1772 if (constantNdx == 0u)
1773 str += constantName + de::toString(constantNdx) + " = OpConstantNull %" + constantType + "\n";
1774 else
1775 str += constantName + de::toString(constantNdx) + " = " + constantOp[constantNdx % 2] + " %" + constantType + " " + de::toString(dataset[constantNdx]) + "\n";
1776 }
1777
1778 for (deUint32 compositeNdx = 0u; compositeNdx < (deUint32)dataset.size(); compositeNdx++)
1779 {
1780 str += "%c_testtype_" + de::toString(compositeNdx) + " = OpSpecConstantComposite %" + m_spirvTestType;
1781
1782 for (deUint32 componentNdx = 0u; componentNdx < m_vectorSize; componentNdx++)
1783 str += " %c_constituent_" + de::toString(getConstituentIndex(compositeNdx * m_vectorSize + componentNdx, m_vectorSize));
1784
1785 str += "\n";
1786 }
1787 }
1788
1789 // Declare scalar constants
1790 if (isConstantTest || isVariableTest)
1791 {
1792 for (size_t constantNdx = 0u; constantNdx < dataset.size(); constantNdx++)
1793 {
1794 if (isConstantNullTest && constantNdx == 0u)
1795 str += constantName + de::toString(constantNdx) + " = OpConstantNull %" + constantType + "\n";
1796 else
1797 str += constantName + de::toString(constantNdx) + " = OpConstant %" + constantType + " " + de::toString(dataset[constantNdx]) + "\n";
1798 }
1799 }
1800
1801 // Declare constant composites
1802 if (isConstantCompositeTest)
1803 {
1804 for (deUint32 compositeNdx = 0u; compositeNdx < (deUint32)dataset.size(); compositeNdx++)
1805 {
1806 str += "%c_testtype_" + de::toString(compositeNdx) + " = OpConstantComposite %" + m_spirvTestType;
1807
1808 for (deUint32 componentNdx = 0u; componentNdx < m_vectorSize; componentNdx++)
1809 str += " %c_constituent_" + de::toString(getConstituentIndex(compositeNdx * m_vectorSize + componentNdx, m_vectorSize));
1810
1811 str += "\n";
1812 }
1813 }
1814
1815 return str;
1816 }
1817
1818 template <class T>
getVariableStr(vector<T> & dataset,const char * spirvType,deUint32 spirvOperation)1819 string getVariableStr (vector<T>& dataset, const char* spirvType, deUint32 spirvOperation)
1820 {
1821 const bool isVariableTest = (SpvOpVariable == spirvOperation);
1822 string str = "";
1823
1824 // Declare variables with initializers
1825 if (isVariableTest)
1826 for (size_t i = 0u; i < dataset.size(); i++)
1827 str += "%testvariable_" + de::toString(i) + " = OpVariable %fp_" + spirvType + " Function %c_testtype_" + de::toString(i) + "\n";
1828
1829 return str;
1830 }
1831
1832 template <class T>
createTests(const char * testName,deUint32 spirvOperation,OpUnaryFuncType operation,UnaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)1833 void SpvAsmTypeTests<T>::createTests (const char* testName,
1834 deUint32 spirvOperation,
1835 OpUnaryFuncType operation,
1836 UnaryFilterFuncType filter,
1837 InputRange inputRange,
1838 InputWidth inputWidth,
1839 const char* spirvExtension,
1840 const bool returnHighPart)
1841 {
1842 DE_ASSERT(!isBooleanResultTest(spirvOperation));
1843
1844 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
1845 OpUnaryFuncType zeroFunc = &zero;
1846 vector<T> dataset;
1847 vector<string> decorations;
1848 vector<string> pre_mains;
1849 vector<string> testfuns;
1850 GraphicsResources resources;
1851 ComputeShaderSpec computeResources;
1852 map<string, string> fragments;
1853 map<string, string> specs;
1854
1855 if (isConstantOrVariableTest(spirvOperation))
1856 {
1857 DE_ASSERT(!spirvExtension);
1858
1859 const deUint32 inputSize = TEST_DATASET_SIZE;
1860 const deUint32 outputSize = TEST_DATASET_SIZE * m_vectorSize;
1861 vector<T> inputDataset;
1862
1863 inputDataset.reserve(inputSize);
1864 dataset.reserve(outputSize);
1865
1866 getDataset(inputDataset, inputSize);
1867 getConstantDataset(inputDataset, dataset, spirvOperation);
1868
1869 const deUint32 totalElements = combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1870
1871 pre_mains.reserve(1);
1872 pre_mains.push_back(createConstantDeclaration(inputDataset, spirvOperation));
1873
1874 string fullOperation = "OpBranch %switchStart\n"
1875 "%switchStart = OpLabel\n"
1876 "OpSelectionMerge %switchEnd None\n"
1877 "OpSwitch %counter_val %caseDefault";
1878
1879 for (deUint32 caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1880 fullOperation += " " + de::toString(caseNdx) + " " + "%case" + de::toString(caseNdx);
1881
1882 fullOperation += "\n";
1883
1884 const string funVariables = getVariableStr(inputDataset, m_spirvTestType.c_str(), spirvOperation);
1885
1886 if (SpvOpVariable == spirvOperation)
1887 {
1888 for (deUint32 caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1889 fullOperation += "%case" + de::toString(caseNdx) + " = OpLabel\n"
1890 "%temp_" + de::toString(caseNdx) + " = OpLoad %" + m_spirvTestType + " %testvariable_" + de::toString(caseNdx) + "\n"
1891 "OpStore %op_constant %temp_" + de::toString(caseNdx) + "\n"
1892 "OpBranch %switchEnd\n";
1893 }
1894 else
1895 {
1896 for (deUint32 caseNdx = 0u; caseNdx < inputSize; caseNdx++)
1897 fullOperation += "%case" + de::toString(caseNdx) + " = OpLabel\n"
1898 "OpStore %op_constant %c_testtype_" + de::toString(caseNdx) + "\n"
1899 "OpBranch %switchEnd\n";
1900 }
1901
1902 fullOperation += "%caseDefault = OpLabel\n"
1903 "OpBranch %switchEnd\n"
1904 "%switchEnd = OpLabel\n"
1905 + resultName + " = OpLoad %" + m_spirvTestType + " %op_constant\n";
1906
1907
1908 finalizeFullOperation(fullOperation, resultName, returnHighPart, false);
1909
1910 createStageTests(testName, resources, computeResources, totalElements, decorations,
1911 pre_mains, testfuns, fullOperation, inputWidth, funVariables.c_str(), spirvExtension);
1912 }
1913 else
1914 {
1915 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
1916 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
1917 const deUint32 totalElements = combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1918
1919 decorations.reserve(1);
1920 pre_mains.reserve(1);
1921 testfuns.reserve(1);
1922
1923 decorations.push_back(createInputDecoration(0));
1924 pre_mains.push_back(createInputPreMain(0, spirvOperation));
1925 testfuns.push_back(createInputTestfun(0, spirvOperation));
1926
1927 string full_operation (spirvExtension ? resultName + " = OpExtInst %" + m_spirvTestType + " %ext1 " + getGLSLstd450OperationStr(spirvOperation) + " %input0_val\n"
1928 : resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + m_spirvTestType + " %input0_val\n");
1929
1930 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
1931
1932 createStageTests(testName, resources, computeResources, totalElements, decorations,
1933 pre_mains, testfuns, full_operation, inputWidth, "", spirvExtension);
1934 }
1935 }
1936
1937 template <class T>
createTests(const char * testName,deUint32 spirvOperation,OpBinaryFuncType operation,BinaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)1938 void SpvAsmTypeTests<T>::createTests (const char* testName,
1939 deUint32 spirvOperation,
1940 OpBinaryFuncType operation,
1941 BinaryFilterFuncType filter,
1942 InputRange inputRange,
1943 InputWidth inputWidth,
1944 const char* spirvExtension,
1945 const bool returnHighPart)
1946 {
1947 const bool isBoolean = isBooleanResultTest(spirvOperation);
1948 const string resultName = (returnHighPart || isBoolean) ? "%op_result_pre" : "%op_result";
1949 const string resultType = isBoolean ? getBooleanResultType(m_vectorSize) : m_spirvTestType;
1950 OpBinaryFuncType zeroFunc = &zero;
1951 vector<T> dataset;
1952 vector<string> decorations;
1953 vector<string> pre_mains;
1954 vector<string> testfuns;
1955 GraphicsResources resources;
1956 ComputeShaderSpec computeResources;
1957 map<string, string> fragments;
1958 map<string, string> specs;
1959 string full_operation;
1960
1961 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
1962 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
1963 const deUint32 totalElements = combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
1964
1965 decorations.reserve(2);
1966 pre_mains.reserve(2);
1967 testfuns.reserve(2);
1968
1969 for (deUint32 elemNdx = 0; elemNdx < 2; ++elemNdx)
1970 {
1971 decorations.push_back(createInputDecoration(elemNdx));
1972 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
1973 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
1974 }
1975
1976 if (spirvOperation != DE_NULL)
1977 {
1978 if (inputWidth == WIDTH_DEFAULT)
1979 full_operation = spirvExtension ? resultName + " = OpExtInst %" + resultType + " %ext1 " + getGLSLstd450OperationStr(spirvOperation) + " %input0_val %input1_val\n"
1980 : resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + resultType + " %input0_val %input1_val\n";
1981 else
1982 full_operation = getBinaryFullOperationWithInputWidthStr(resultName, getSpvOperationStr(spirvOperation), m_inputType, m_spirvTestType, m_vectorSize, inputWidth);
1983 }
1984 else
1985 {
1986 if (deStringBeginsWith(testName, "mul_sdiv"))
1987 {
1988 DE_ASSERT(spirvExtension == DE_NULL);
1989 full_operation = "%op_result2 = OpIMul %" + m_spirvTestType + " %input0_val %input1_val\n";
1990 full_operation += resultName + " = OpSDiv %" + m_spirvTestType + " %op_result2 %input1_val\n";
1991 }
1992 if (deStringBeginsWith(testName, "mul_udiv"))
1993 {
1994 DE_ASSERT(spirvExtension == DE_NULL);
1995 full_operation = "%op_result2 = OpIMul %" + m_spirvTestType + " %input0_val %input1_val\n";
1996 full_operation += resultName + " = OpUDiv %" + m_spirvTestType + " %op_result2 %input1_val\n";
1997 }
1998 }
1999
2000 finalizeFullOperation(full_operation, resultName, returnHighPart, isBoolean);
2001
2002 createStageTests(testName, resources, computeResources, totalElements, decorations,
2003 pre_mains, testfuns, full_operation, inputWidth, "", spirvExtension);
2004 }
2005
2006 template <class T>
createTests(const char * testName,deUint32 spirvOperation,OpTernaryFuncType operation,TernaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)2007 void SpvAsmTypeTests<T>::createTests (const char* testName,
2008 deUint32 spirvOperation,
2009 OpTernaryFuncType operation,
2010 TernaryFilterFuncType filter,
2011 InputRange inputRange,
2012 InputWidth inputWidth,
2013 const char* spirvExtension,
2014 const bool returnHighPart)
2015 {
2016 DE_ASSERT(!isBooleanResultTest(spirvOperation));
2017
2018 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
2019 OpTernaryFuncType zeroFunc = &zero;
2020 vector<T> dataset;
2021 vector<string> decorations;
2022 vector<string> pre_mains;
2023 vector<string> testfuns;
2024 GraphicsResources resources;
2025 ComputeShaderSpec computeResources;
2026 map<string, string> fragments;
2027 map<string, string> specs;
2028
2029 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
2030 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
2031 const deUint32 totalElements = combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
2032
2033 decorations.reserve(3);
2034 pre_mains.reserve(3);
2035 testfuns.reserve(3);
2036
2037 for (deUint32 elemNdx = 0; elemNdx < 3; ++elemNdx)
2038 {
2039 decorations.push_back(createInputDecoration(elemNdx));
2040 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
2041 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
2042 }
2043
2044 string full_operation = "";
2045
2046 if (inputWidth == WIDTH_DEFAULT)
2047 full_operation = (spirvExtension ? resultName + " = OpExtInst %" + m_spirvTestType + " %ext1 " + getGLSLstd450OperationStr(spirvOperation) + " %input0_val %input1_val %input2_val\n"
2048 : resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + m_spirvTestType + " %input0_val %input1_val %input2_val\n");
2049 else
2050 full_operation = getFullOperationWithDifferentInputWidthStr(resultName, getSpvOperationStr(spirvOperation), m_inputType, m_spirvTestType, inputWidth, false);
2051
2052 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
2053
2054 createStageTests(testName, resources, computeResources, totalElements, decorations,
2055 pre_mains, testfuns, full_operation, inputWidth, "", spirvExtension);
2056 }
2057
2058 template <class T>
createTests(const char * testName,deUint32 spirvOperation,OpQuaternaryFuncType operation,QuaternaryFilterFuncType filter,InputRange inputRange,InputWidth inputWidth,const char * spirvExtension,const bool returnHighPart)2059 void SpvAsmTypeTests<T>::createTests (const char* testName,
2060 deUint32 spirvOperation,
2061 OpQuaternaryFuncType operation,
2062 QuaternaryFilterFuncType filter,
2063 InputRange inputRange,
2064 InputWidth inputWidth,
2065 const char* spirvExtension,
2066 const bool returnHighPart)
2067 {
2068 DE_ASSERT(!spirvExtension);
2069 DE_ASSERT(!isBooleanResultTest(spirvOperation));
2070
2071 const string resultName = returnHighPart ? "%op_result_pre" : "%op_result";
2072 OpQuaternaryFuncType zeroFunc = &zero;
2073 vector<T> dataset;
2074 vector<string> decorations;
2075 vector<string> pre_mains;
2076 vector<string> testfuns;
2077 GraphicsResources resources;
2078 ComputeShaderSpec computeResources;
2079 map<string, string> fragments;
2080 map<string, string> specs;
2081 string full_operation;
2082
2083 dataset.reserve(TEST_DATASET_SIZE * m_vectorSize);
2084 getDataset(dataset, TEST_DATASET_SIZE * m_vectorSize);
2085 const deUint32 totalElements = combine(resources, computeResources, dataset, (returnHighPart ? zeroFunc : operation), filter, inputRange);
2086
2087 decorations.reserve(4);
2088 pre_mains.reserve(4);
2089 testfuns.reserve(4);
2090
2091 for (deUint32 elemNdx = 0; elemNdx < 4; ++elemNdx)
2092 {
2093 decorations.push_back(createInputDecoration(elemNdx));
2094 pre_mains.push_back(createInputPreMain(elemNdx, spirvOperation));
2095 testfuns.push_back(createInputTestfun(elemNdx, spirvOperation));
2096 }
2097
2098 if (inputWidth == WIDTH_DEFAULT)
2099 full_operation = resultName + " = " + getSpvOperationStr(spirvOperation) + " %" + m_spirvTestType + " %input0_val %input1_val %input2_val %input3_val\n";
2100 else
2101 full_operation = getFullOperationWithDifferentInputWidthStr(resultName, getSpvOperationStr(spirvOperation), m_inputType, m_spirvTestType, inputWidth, true);
2102
2103 finalizeFullOperation(full_operation, resultName, returnHighPart, false);
2104
2105 createStageTests(testName, resources, computeResources, totalElements, decorations,
2106 pre_mains, testfuns, full_operation, inputWidth, "", spirvExtension);
2107 }
2108
2109 template <class T>
createSwitchTests(void)2110 void SpvAsmTypeTests<T>::createSwitchTests (void)
2111 {
2112 // The switch case test function is a bit different from the normal one. It uses two input buffers for input data and expected
2113 // results. The shader itself will calculate results based on input data and compare them to the expected results in the second
2114 // buffer, instead of verifying results on the CPU.
2115 //
2116 // The test function will return the color passed to it if the obtained results match the expected results, and will return (0.5,
2117 // 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
2118 // image as usual with the graphics shader test utils. For compute shaders, this does not work.
2119 //
2120 // 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
2121 // single integer in an output storage buffer as a boolean value indicating if the returned color matches the input color, to be
2122 // checked after the shader runs. Roughly equivalent to the following GLSL code:
2123 //
2124 // layout(binding = 2) buffer BlockType { int values[]; } block;
2125 //
2126 // vec4 testfun(in vec4 param);
2127 //
2128 // void main()
2129 // {
2130 // vec4 in_color = vec4(0.0, 0.0, 0.0, 1.0);
2131 // vec4 out_color = testfun(in_color);
2132 // block.values[0] = int(all(equal(in_color, out_color)));
2133 // }
2134 const tcu::StringTemplate computeShaderSwitchTemplate(R"(
2135 OpCapability Shader
2136 ${capability:opt}
2137 ${extension:opt}
2138 OpMemoryModel Logical GLSL450
2139 OpEntryPoint GLCompute %BP_main "main"
2140 OpExecutionMode %BP_main LocalSize 1 1 1
2141 ${execution_mode:opt}
2142 ${debug:opt}
2143 ${moduleprocessed:opt}
2144 ${IF_decoration:opt}
2145 ${decoration:opt}
2146 OpDecorate %rta_i32 ArrayStride 4
2147 OpMemberDecorate %BlockType 0 Offset 0
2148 OpDecorate %BlockType BufferBlock
2149 OpDecorate %block DescriptorSet 0
2150 OpDecorate %block Binding 2
2151 )"
2152 SPIRV_ASSEMBLY_TYPES
2153 SPIRV_ASSEMBLY_CONSTANTS
2154 SPIRV_ASSEMBLY_ARRAYS
2155 R"(
2156 %rta_i32 = OpTypeRuntimeArray %i32
2157 %BlockType = OpTypeStruct %rta_i32
2158 %up_BlockType = OpTypePointer Uniform %BlockType
2159 %block = OpVariable %up_BlockType Uniform
2160 %BP_color = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1
2161 ${pre_main:opt}
2162 ${IF_variable:opt}
2163 %up_i32 = OpTypePointer Uniform %i32
2164 %BP_main = OpFunction %void None %voidf
2165 %BP_label_main = OpLabel
2166 ${IF_carryforward:opt}
2167 ${post_interface_op_comp:opt}
2168 %BP_in_color = OpVariable %fp_v4f32 Function
2169 %BP_out_color = OpVariable %fp_v4f32 Function
2170 OpStore %BP_in_color %BP_color
2171 %BP_tmp1 = OpLoad %v4f32 %BP_in_color
2172 %BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1
2173 OpStore %BP_out_color %BP_tmp2
2174
2175 %BP_tmp3 = OpLoad %v4f32 %BP_in_color
2176 %BP_tmp4 = OpLoad %v4f32 %BP_out_color
2177 %BP_tmp5 = OpFOrdEqual %v4bool %BP_tmp3 %BP_tmp4
2178 %BP_tmp6 = OpAll %bool %BP_tmp5
2179 %BP_tmp7 = OpSelect %i32 %BP_tmp6 %c_i32_1 %c_i32_0
2180 %BP_tmp8 = OpAccessChain %up_i32 %block %c_i32_0 %c_i32_0
2181 OpStore %BP_tmp8 %BP_tmp7
2182
2183 OpReturn
2184 OpFunctionEnd
2185
2186 ${testfun}
2187 )");
2188
2189 const StringTemplate decoration ("OpDecorate %input DescriptorSet 0\n"
2190 "OpDecorate %input Binding 0\n"
2191 "OpDecorate %input NonWritable\n"
2192 "OpDecorate %expectedOutput DescriptorSet 0\n"
2193 "OpDecorate %expectedOutput Binding 1\n"
2194 "OpDecorate %expectedOutput NonWritable\n"
2195 "OpDecorate %a${num_elements}testtype ArrayStride ${typesize}\n"
2196 "OpDecorate %buf BufferBlock\n"
2197 "OpMemberDecorate %buf 0 Offset 0\n");
2198
2199 const StringTemplate pre_pre_main ("%fp_bool = OpTypePointer Function %bool\n"
2200 "%c_u32_${num_elements} = OpConstant %u32 ${num_elements}\n"
2201 "%c_i32_${num_elements} = OpConstant %i32 ${num_elements}\n");
2202
2203 const StringTemplate scalar_pre_main ("%testtype = ${scalartype}\n");
2204
2205 const StringTemplate post_pre_main ("%c_casedefault = OpConstant %${testtype} 10\n"
2206 "%c_case0 = OpConstant %${testtype} 100\n"
2207 "%c_case1 = OpConstant %${testtype} 110\n"
2208 "%c_case2 = OpConstant %${testtype} 120\n"
2209 "%fail_color = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_1\n"
2210 "%a${num_elements}testtype = OpTypeArray %${testtype} %c_u32_${num_elements}\n"
2211 "%up_testtype = OpTypePointer Uniform %${testtype}\n"
2212 "%buf = OpTypeStruct %a${num_elements}testtype\n"
2213 "%bufptr = OpTypePointer Uniform %buf\n"
2214 "%input = OpVariable %bufptr Uniform\n"
2215 "%expectedOutput = OpVariable %bufptr Uniform\n");
2216
2217 const StringTemplate testfun ("%test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
2218 "%param = OpFunctionParameter %v4f32\n"
2219
2220 "%entry = OpLabel\n"
2221 "%counter = OpVariable %fp_i32 Function\n"
2222 "%return = OpVariable %fp_v4f32 Function\n"
2223 "%works = OpVariable %fp_bool Function\n"
2224 "OpStore %counter %c_i32_0\n"
2225 "OpStore %return %param\n"
2226 "OpBranch %loop\n"
2227
2228 "%loop = OpLabel\n"
2229 "%counter_val = OpLoad %i32 %counter\n"
2230 "%lt = OpSLessThan %bool %counter_val %c_i32_${num_elements}\n"
2231 "OpLoopMerge %loop_exit %inc None\n"
2232 "OpBranchConditional %lt %load %loop_exit\n"
2233
2234 "%load = OpLabel\n"
2235 "%input_loc = OpAccessChain %up_testtype %input %c_i32_0 %counter_val\n"
2236 "%input_val = OpLoad %${testtype} %input_loc\n"
2237 "%expectedOutput_loc = OpAccessChain %up_testtype %expectedOutput %c_i32_0 %counter_val\n"
2238 "%expectedOutput_val = OpLoad %${testtype} %expectedOutput_loc\n"
2239
2240 "OpSelectionMerge %switch_exit None\n"
2241 "OpSwitch %input_val %default ${case0} %case0 ${case1} %case1 ${case2} %case2\n"
2242
2243 "%default = OpLabel\n"
2244 "%is_default = OpIEqual %bool %expectedOutput_val %c_casedefault\n"
2245 "OpBranch %switch_exit\n"
2246
2247 "%case0 = OpLabel\n"
2248 "%is_case0 = OpIEqual %bool %expectedOutput_val %c_case0\n"
2249 "OpBranch %switch_exit\n"
2250
2251 "%case1 = OpLabel\n"
2252 "%is_case1 = OpIEqual %bool %expectedOutput_val %c_case1\n"
2253 "OpBranch %switch_exit\n"
2254
2255 "%case2 = OpLabel\n"
2256 "%is_case2 = OpIEqual %bool %expectedOutput_val %c_case2\n"
2257 "OpBranch %switch_exit\n"
2258
2259 "%switch_exit = OpLabel\n"
2260 "%case_result = OpPhi %bool %is_default %default %is_case0 %case0 %is_case1 %case1 %is_case2 %case2\n"
2261 "OpSelectionMerge %result_end None\n"
2262 "OpBranchConditional %case_result %result_correct %result_incorrect\n"
2263
2264 "%result_correct = OpLabel\n"
2265 "OpBranch %result_end\n"
2266
2267 "%result_incorrect = OpLabel\n"
2268 "%counter_val_end = OpIAdd %i32 %counter_val %c_i32_${num_elements}\n"
2269 "OpStore %counter %counter_val_end\n"
2270 "OpStore %return %fail_color\n"
2271 "OpBranch %result_end\n"
2272
2273 "%result_end = OpLabel\n"
2274 "OpBranch %inc\n"
2275
2276 "%inc = OpLabel\n"
2277 "%counter_val_next = OpIAdd %i32 %counter_val %c_i32_1\n"
2278 "OpStore %counter %counter_val_next\n"
2279 "OpBranch %loop\n"
2280
2281 "%loop_exit = OpLabel\n"
2282 "%return_val = OpLoad %v4f32 %return\n"
2283 "OpReturnValue %return_val\n"
2284
2285 "OpFunctionEnd\n");
2286
2287 const bool uses8bit (m_inputType == TYPE_I8 || m_inputType == TYPE_U8);
2288
2289 GraphicsResources resources;
2290 ComputeShaderSpec computeResources;
2291 RGBA defaultColors[4];
2292 map<string, string> fragments;
2293 map<string, string> specs;
2294 std::vector<string> noExtensions;
2295 std::vector<string> features;
2296 VulkanFeatures requiredFeatures;
2297 vector<T> dataset;
2298 deUint32 numElements;
2299 std::string spirvExtensions;
2300 std::string spirvCapabilities;
2301
2302 getDefaultColors(defaultColors);
2303
2304 dataset.reserve(TEST_DATASET_SIZE);
2305 getDataset(dataset, TEST_DATASET_SIZE);
2306 numElements = fillResources(resources, computeResources, dataset);
2307
2308 if (m_deviceFeature)
2309 features.insert(features.begin(), m_deviceFeature);
2310
2311 if (uses8bit)
2312 {
2313 requiredFeatures.extFloat16Int8 |= EXTFLOAT16INT8FEATURES_INT8;
2314 }
2315
2316 if (m_inputType == TYPE_I8 || m_inputType == TYPE_U8)
2317 {
2318 requiredFeatures.ext8BitStorage |= EXT8BITSTORAGEFEATURES_UNIFORM_STORAGE_BUFFER;
2319 spirvExtensions += "OpExtension \"SPV_KHR_8bit_storage\"\n";
2320 }
2321
2322 if (m_inputType == TYPE_I16 || m_inputType == TYPE_U16)
2323 {
2324 requiredFeatures.ext16BitStorage |= EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK;
2325 spirvExtensions += "OpExtension \"SPV_KHR_16bit_storage\"\n";
2326 }
2327
2328 specs["testtype"] = m_spirvTestType;
2329 specs["scalartype"] = m_spirvType;
2330 specs["typesize"] = de::toString(m_typeSize / 8);
2331 specs["num_elements"] = de::toString(numElements);
2332 specs["case0"] = de::toString(m_cases[0]);
2333 specs["case1"] = de::toString(m_cases[1]);
2334 specs["case2"] = de::toString(m_cases[2]);
2335
2336 fragments["decoration"] = decoration.specialize(specs);
2337
2338 fragments["pre_main"] = pre_pre_main.specialize(specs);
2339 if (specs["testtype"].compare(UNDEFINED_SPIRV_TEST_TYPE) == 0)
2340 fragments["pre_main"] += scalar_pre_main.specialize(specs);
2341 fragments["pre_main"] += post_pre_main.specialize(specs);
2342
2343 fragments["testfun"] = testfun.specialize(specs);
2344
2345 spirvCapabilities += getSpirvCapabilityStr(m_spirvCapability, WIDTH_DEFAULT);
2346
2347 fragments["extension"] = spirvExtensions;
2348 fragments["capability"] = spirvCapabilities;
2349
2350 requiredFeaturesFromStrings(features, requiredFeatures);
2351 computeResources.requestedVulkanFeatures = requiredFeatures;
2352
2353 const string testName = "switch";
2354
2355 createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, noExtensions, this, requiredFeatures);
2356 createComputeTest(computeResources, computeShaderSwitchTemplate, fragments, *this, testName);
2357 }
2358
2359 template <class T>
getConstantDataset(vector<T> inputDataset,vector<T> & outputDataset,deUint32 spirvOperation)2360 void SpvAsmTypeTests<T>::getConstantDataset (vector<T> inputDataset, vector<T>& outputDataset, deUint32 spirvOperation)
2361 {
2362 const deUint32 numElements = (deUint32)inputDataset.size();
2363
2364 if ((SpvOpConstant == spirvOperation) || (SpvOpSpecConstant == spirvOperation))
2365 {
2366 for (deUint32 elementNdx = 0u; elementNdx < numElements; elementNdx++)
2367 outputDataset.push_back(inputDataset[elementNdx]);
2368 }
2369 else
2370 {
2371 for (deUint32 elementNdx = 0; elementNdx < numElements * m_vectorSize; elementNdx++)
2372 outputDataset.push_back(inputDataset[getConstituentIndex(elementNdx, m_vectorSize)]);
2373 }
2374 }
2375
2376 template <class T>
finalizeFullOperation(string & fullOperation,const string & resultName,const bool returnHighPart,const bool isBooleanResult)2377 void SpvAsmTypeTests<T>::finalizeFullOperation (string& fullOperation,
2378 const string& resultName,
2379 const bool returnHighPart,
2380 const bool isBooleanResult)
2381 {
2382 DE_ASSERT(!fullOperation.empty());
2383
2384 if (returnHighPart)
2385 {
2386 DE_ASSERT(sizeof(T) == sizeof(deInt16));
2387 DE_ASSERT((m_inputType == TYPE_I16) || (m_inputType == TYPE_U16));
2388
2389 const bool signedness = (m_inputType == TYPE_I16);
2390 const string convertOp = signedness ? "OpSConvert" : "OpUConvert";
2391 const string convertPrefix = (m_vectorSize == 1) ? "" : "v" + de::toString(m_vectorSize);
2392 const string convertType = convertPrefix + "u32";
2393
2394 // Zero extend value to double-width value, then return high part
2395 fullOperation += "%op_result_a = OpUConvert %" + convertType + " " + resultName + "\n";
2396 fullOperation += "%op_result_b = OpShiftRightLogical %" + convertType + " %op_result_a %c_shift\n";
2397 fullOperation += "%op_result = " + convertOp + " %" + m_spirvTestType + " %op_result_b\n";
2398 }
2399 else if (isBooleanResult)
2400 {
2401 const string selectType = (m_vectorSize == 1) ? ("u32") : ("v" + de::toString(m_vectorSize) + "u32");
2402
2403 // Convert boolean values to result format
2404 if (m_inputType == TYPE_U32)
2405 {
2406 fullOperation += "%op_result = OpSelect %" + selectType + " %op_result_pre %c_one %c_zero\n";
2407 }
2408 else
2409 {
2410 fullOperation += "%op_result_u32 = OpSelect %" + selectType + " %op_result_pre %c_one %c_zero\n";
2411
2412 if (m_typeSize == 32)
2413 fullOperation += "%op_result = OpBitcast %" + m_spirvTestType + " %op_result_u32\n";
2414 else
2415 fullOperation += "%op_result = OpSConvert %" + m_spirvTestType + " %op_result_u32\n";
2416 }
2417 }
2418 else
2419 {
2420 DE_ASSERT(resultName == "%op_result");
2421 }
2422 }
2423
2424 template <class T>
filterNone(T)2425 bool SpvAsmTypeTests<T>::filterNone (T)
2426 {
2427 return true;
2428 }
2429
2430 template <class T>
filterNone(T,T)2431 bool SpvAsmTypeTests<T>::filterNone (T, T)
2432 {
2433 return true;
2434 }
2435
2436 template <class T>
filterNone(T,T,T)2437 bool SpvAsmTypeTests<T>::filterNone (T, T, T)
2438 {
2439 return true;
2440 }
2441
2442 template <class T>
filterNone(T,T,T,T)2443 bool SpvAsmTypeTests<T>::filterNone (T, T, T, T)
2444 {
2445 return true;
2446 }
2447
2448 template <class T>
filterZero(T,T b)2449 bool SpvAsmTypeTests<T>::filterZero (T, T b)
2450 {
2451 if (b == static_cast<T>(0))
2452 return false;
2453 else
2454 return true;
2455 }
2456
2457 template <class T>
filterNegativesAndZero(T a,T b)2458 bool SpvAsmTypeTests<T>::filterNegativesAndZero (T a, T b)
2459 {
2460 if (a < static_cast<T>(0) || b <= static_cast<T>(0))
2461 return false;
2462 else
2463 return true;
2464 }
2465
2466 template <class T>
filterMinGtMax(T,T a,T b)2467 bool SpvAsmTypeTests<T>::filterMinGtMax (T, T a, T b)
2468 {
2469 if (a > b)
2470 return false;
2471 else
2472 return true;
2473 }
2474
2475 template <class T>
zero(T)2476 T SpvAsmTypeTests<T>::zero (T)
2477 {
2478 return static_cast<T>(0.0);
2479 }
2480
2481 template <class T>
zero(T,T)2482 T SpvAsmTypeTests<T>::zero (T, T)
2483 {
2484 return static_cast<T>(0.0);
2485 }
2486
2487 template <class T>
zero(T,T,T)2488 T SpvAsmTypeTests<T>::zero (T, T, T)
2489 {
2490 return static_cast<T>(0.0);
2491 }
2492
2493 template <class T>
zero(T,T,T,T)2494 T SpvAsmTypeTests<T>::zero (T, T, T, T)
2495 {
2496 return static_cast<T>(0.0);
2497 }
2498
2499 template <class T>
replicate(const std::string & replicant,const deUint32 count)2500 std::string SpvAsmTypeTests<T>::replicate (const std::string& replicant,
2501 const deUint32 count)
2502 {
2503 std::string result;
2504
2505 for (deUint32 i = 0; i < count; ++i)
2506 result += replicant;
2507
2508 return result;
2509 }
2510
2511 class SpvAsmTypeInt8Tests : public SpvAsmTypeTests<deInt8>
2512 {
2513 public:
2514 SpvAsmTypeInt8Tests (tcu::TestContext& testCtx,
2515 deUint32 vectorSize);
2516 ~SpvAsmTypeInt8Tests (void);
2517 void getDataset (vector<deInt8>& input,
2518 deUint32 numElements);
2519 void pushResource (vector<Resource>& resource,
2520 const vector<deInt8>& data);
2521 };
2522
SpvAsmTypeInt8Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2523 SpvAsmTypeInt8Tests::SpvAsmTypeInt8Tests (tcu::TestContext& testCtx,
2524 deUint32 vectorSize)
2525 : SpvAsmTypeTests (testCtx, "i8", "int8 tests", DE_NULL, "Int8", "OpTypeInt 8 1", TYPE_I8, 8, vectorSize)
2526 {
2527 m_cases[0] = -42;
2528 m_cases[1] = 73;
2529 m_cases[2] = 121;
2530 }
2531
~SpvAsmTypeInt8Tests(void)2532 SpvAsmTypeInt8Tests::~SpvAsmTypeInt8Tests (void)
2533 {
2534 }
2535
getDataset(vector<deInt8> & input,deUint32 numElements)2536 void SpvAsmTypeInt8Tests::getDataset (vector<deInt8>& input,
2537 deUint32 numElements)
2538 {
2539 // Push first special cases
2540 input.push_back(0);
2541 input.push_back(static_cast<deInt8>(deIntMinValue32(8)));// A 8-bit negative number
2542 input.push_back(static_cast<deInt8>(deIntMaxValue32(8)));// A 8-bit positive number
2543
2544 // Push switch cases
2545 input.push_back(m_cases[0]);
2546 input.push_back(m_cases[1]);
2547 input.push_back(m_cases[2]);
2548
2549 numElements -= static_cast<deUint32>(input.size());
2550
2551 // Random values
2552 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2553 input.push_back(static_cast<deInt8>(m_rnd.getUint8()));
2554 }
2555
pushResource(vector<Resource> & resource,const vector<deInt8> & data)2556 void SpvAsmTypeInt8Tests::pushResource (vector<Resource>& resource,
2557 const vector<deInt8>& data)
2558 {
2559 resource.push_back(Resource(BufferSp(new Int8Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2560 }
2561
2562 class SpvAsmTypeInt16Tests : public SpvAsmTypeTests<deInt16>
2563 {
2564 public:
2565 SpvAsmTypeInt16Tests (tcu::TestContext& testCtx,
2566 deUint32 vectorSize);
2567 ~SpvAsmTypeInt16Tests (void);
2568 void getDataset (vector<deInt16>& input,
2569 deUint32 numElements);
2570 void pushResource (vector<Resource>& resource,
2571 const vector<deInt16>& data);
2572 };
2573
SpvAsmTypeInt16Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2574 SpvAsmTypeInt16Tests::SpvAsmTypeInt16Tests (tcu::TestContext& testCtx,
2575 deUint32 vectorSize)
2576 : SpvAsmTypeTests (testCtx, "i16", "int16 tests", "shaderInt16", "Int16", "OpTypeInt 16 1", TYPE_I16, 16, vectorSize)
2577 {
2578 m_cases[0] = -3221;
2579 m_cases[1] = 3210;
2580 m_cases[2] = 19597;
2581 }
2582
~SpvAsmTypeInt16Tests(void)2583 SpvAsmTypeInt16Tests::~SpvAsmTypeInt16Tests (void)
2584 {
2585 }
2586
getDataset(vector<deInt16> & input,deUint32 numElements)2587 void SpvAsmTypeInt16Tests::getDataset (vector<deInt16>& input,
2588 deUint32 numElements)
2589 {
2590 // Push first special cases
2591 input.push_back(0);
2592 input.push_back(static_cast<deInt16>(deIntMinValue32(16)));// A 16-bit negative number
2593 input.push_back(static_cast<deInt16>(deIntMaxValue32(16)));// A 16-bit positive number
2594
2595 // Push switch cases
2596 input.push_back(m_cases[0]);
2597 input.push_back(m_cases[1]);
2598 input.push_back(m_cases[2]);
2599
2600 numElements -= static_cast<deUint32>(input.size());
2601
2602 // Random values
2603 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2604 input.push_back(static_cast<deInt16>(m_rnd.getUint16()));
2605 }
2606
pushResource(vector<Resource> & resource,const vector<deInt16> & data)2607 void SpvAsmTypeInt16Tests::pushResource (vector<Resource>& resource,
2608 const vector<deInt16>& data)
2609 {
2610 resource.push_back(Resource(BufferSp(new Int16Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2611 }
2612
2613 class SpvAsmTypeInt32Tests : public SpvAsmTypeTests<deInt32>
2614 {
2615 public:
2616 SpvAsmTypeInt32Tests (tcu::TestContext& testCtx,
2617 deUint32 vectorSize);
2618 ~SpvAsmTypeInt32Tests (void);
2619 void getDataset (vector<deInt32>& input,
2620 deUint32 numElements);
2621 void pushResource (vector<Resource>& resource,
2622 const vector<deInt32>& data);
2623 };
2624
SpvAsmTypeInt32Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2625 SpvAsmTypeInt32Tests::SpvAsmTypeInt32Tests (tcu::TestContext& testCtx,
2626 deUint32 vectorSize)
2627 : SpvAsmTypeTests (testCtx, "i32", "int32 tests", DE_NULL, DE_NULL, "OpTypeInt 32 1", TYPE_I32, 32, vectorSize)
2628 {
2629 m_cases[0] = -3221;
2630 m_cases[1] = 3210;
2631 m_cases[2] = 268438669;
2632 }
2633
~SpvAsmTypeInt32Tests(void)2634 SpvAsmTypeInt32Tests::~SpvAsmTypeInt32Tests (void)
2635 {
2636 }
2637
getDataset(vector<deInt32> & input,deUint32 numElements)2638 void SpvAsmTypeInt32Tests::getDataset (vector<deInt32>& input,
2639 deUint32 numElements)
2640 {
2641 // Push first special cases
2642 input.push_back(0);
2643 input.push_back(deIntMinValue32(32) + 1); // So MIN = -MAX
2644 input.push_back(deIntMaxValue32(32));
2645
2646 // Push switch cases
2647 input.push_back(m_cases[0]);
2648 input.push_back(m_cases[1]);
2649 input.push_back(m_cases[2]);
2650
2651 numElements -= static_cast<deUint32>(input.size());
2652
2653 // Random values
2654 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2655 input.push_back(static_cast<deInt32>(m_rnd.getUint32()));
2656 }
2657
pushResource(vector<Resource> & resource,const vector<deInt32> & data)2658 void SpvAsmTypeInt32Tests::pushResource (vector<Resource>& resource,
2659 const vector<deInt32>& data)
2660 {
2661 resource.push_back(Resource(BufferSp(new Int32Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2662 }
2663
2664 class SpvAsmTypeInt64Tests : public SpvAsmTypeTests<deInt64>
2665 {
2666 public:
2667 SpvAsmTypeInt64Tests (tcu::TestContext& testCtx,
2668 deUint32 vectorSize);
2669 ~SpvAsmTypeInt64Tests (void);
2670 void getDataset (vector<deInt64>& input,
2671 deUint32 numElements);
2672 void pushResource (vector<Resource>& resource,
2673 const vector<deInt64>& data);
2674 };
2675
SpvAsmTypeInt64Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2676 SpvAsmTypeInt64Tests::SpvAsmTypeInt64Tests (tcu::TestContext& testCtx,
2677 deUint32 vectorSize)
2678 : SpvAsmTypeTests (testCtx, "i64", "int64 tests", "shaderInt64", "Int64", "OpTypeInt 64 1", TYPE_I64, 64, vectorSize)
2679 {
2680 m_cases[0] = 3210;
2681 m_cases[1] = -268438669;
2682 m_cases[2] = 26843866939192872;
2683 }
2684
~SpvAsmTypeInt64Tests(void)2685 SpvAsmTypeInt64Tests::~SpvAsmTypeInt64Tests (void)
2686 {
2687 }
2688
getDataset(vector<deInt64> & input,deUint32 numElements)2689 void SpvAsmTypeInt64Tests::getDataset (vector<deInt64>& input,
2690 deUint32 numElements)
2691 {
2692 // Push first special cases
2693 input.push_back(0);
2694 input.push_back(0xFFFF859A3BF78592);// A 64-bit negative number
2695 input.push_back(0x7FFF859A3BF78592);// A 64-bit positive number
2696
2697 // Push switch cases
2698 input.push_back(m_cases[0]);
2699 input.push_back(m_cases[1]);
2700 input.push_back(m_cases[2]);
2701
2702 numElements -= static_cast<deUint32>(input.size());
2703
2704 // Random values
2705 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2706 input.push_back(static_cast<deInt64>(m_rnd.getUint64()));
2707 }
2708
pushResource(vector<Resource> & resource,const vector<deInt64> & data)2709 void SpvAsmTypeInt64Tests::pushResource (vector<Resource>& resource,
2710 const vector<deInt64>& data)
2711 {
2712 resource.push_back(Resource(BufferSp(new Int64Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2713 }
2714
2715 class SpvAsmTypeUint8Tests : public SpvAsmTypeTests<deUint8>
2716 {
2717 public:
2718 SpvAsmTypeUint8Tests (tcu::TestContext& testCtx,
2719 deUint32 vectorSize);
2720 ~SpvAsmTypeUint8Tests (void);
2721 void getDataset (vector<deUint8>& input,
2722 deUint32 numElements);
2723 void pushResource (vector<Resource>& resource,
2724 const vector<deUint8>& data);
2725 };
2726
SpvAsmTypeUint8Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2727 SpvAsmTypeUint8Tests::SpvAsmTypeUint8Tests (tcu::TestContext& testCtx,
2728 deUint32 vectorSize)
2729 : SpvAsmTypeTests (testCtx, "u8", "uint8 tests", DE_NULL, "Int8", "OpTypeInt 8 0", TYPE_U8, 8, vectorSize)
2730 {
2731 m_cases[0] = 0;
2732 m_cases[1] = 73;
2733 m_cases[2] = 193;
2734 }
2735
~SpvAsmTypeUint8Tests(void)2736 SpvAsmTypeUint8Tests::~SpvAsmTypeUint8Tests (void)
2737 {
2738 }
2739
getDataset(vector<deUint8> & input,deUint32 numElements)2740 void SpvAsmTypeUint8Tests::getDataset (vector<deUint8>& input,
2741 deUint32 numElements)
2742 {
2743 // Push first special cases
2744 input.push_back(0); // Min value
2745 input.push_back(~0); // Max value
2746
2747 //Push switch cases
2748 input.push_back(m_cases[0]);
2749 input.push_back(m_cases[1]);
2750 input.push_back(m_cases[2]);
2751
2752 numElements -= static_cast<deUint32>(input.size());
2753
2754 // Random values
2755 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2756 input.push_back(m_rnd.getUint8());
2757 }
2758
pushResource(vector<Resource> & resource,const vector<deUint8> & data)2759 void SpvAsmTypeUint8Tests::pushResource (vector<Resource>& resource,
2760 const vector<deUint8>& data)
2761 {
2762 resource.push_back(Resource(BufferSp(new Uint8Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2763 }
2764
2765 class SpvAsmTypeUint16Tests : public SpvAsmTypeTests<deUint16>
2766 {
2767 public:
2768 SpvAsmTypeUint16Tests (tcu::TestContext& testCtx,
2769 deUint32 vectorSize);
2770 ~SpvAsmTypeUint16Tests (void);
2771 void getDataset (vector<deUint16>& input,
2772 deUint32 numElements);
2773 void pushResource (vector<Resource>& resource,
2774 const vector<deUint16>& data);
2775 };
2776
SpvAsmTypeUint16Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2777 SpvAsmTypeUint16Tests::SpvAsmTypeUint16Tests (tcu::TestContext& testCtx,
2778 deUint32 vectorSize)
2779 : SpvAsmTypeTests (testCtx, "u16", "uint16 tests", "shaderInt16", "Int16", "OpTypeInt 16 0", TYPE_U16, 16, vectorSize)
2780 {
2781 m_cases[0] = 0;
2782 m_cases[1] = 3210;
2783 m_cases[2] = 19597;
2784 }
2785
~SpvAsmTypeUint16Tests(void)2786 SpvAsmTypeUint16Tests::~SpvAsmTypeUint16Tests (void)
2787 {
2788 }
2789
getDataset(vector<deUint16> & input,deUint32 numElements)2790 void SpvAsmTypeUint16Tests::getDataset (vector<deUint16>& input,
2791 deUint32 numElements)
2792 {
2793 // Push first special cases
2794 input.push_back(0); // Min value
2795 input.push_back(~0); // Max value
2796
2797 //Push switch cases
2798 input.push_back(m_cases[0]);
2799 input.push_back(m_cases[1]);
2800 input.push_back(m_cases[2]);
2801
2802 numElements -= static_cast<deUint32>(input.size());
2803
2804 // Random values
2805 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2806 input.push_back(m_rnd.getUint16());
2807 }
2808
pushResource(vector<Resource> & resource,const vector<deUint16> & data)2809 void SpvAsmTypeUint16Tests::pushResource (vector<Resource>& resource,
2810 const vector<deUint16>& data)
2811 {
2812 resource.push_back(Resource(BufferSp(new Uint16Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2813 }
2814
2815 class SpvAsmTypeUint32Tests : public SpvAsmTypeTests<deUint32>
2816 {
2817 public:
2818 SpvAsmTypeUint32Tests (tcu::TestContext& testCtx,
2819 deUint32 vectorSize);
2820 ~SpvAsmTypeUint32Tests (void);
2821 void getDataset (vector<deUint32>& input,
2822 deUint32 numElements);
2823 void pushResource (vector<Resource>& resource,
2824 const vector<deUint32>& data);
2825 };
2826
SpvAsmTypeUint32Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2827 SpvAsmTypeUint32Tests::SpvAsmTypeUint32Tests (tcu::TestContext& testCtx,
2828 deUint32 vectorSize)
2829 : SpvAsmTypeTests (testCtx, "u32", "uint32 tests", DE_NULL, DE_NULL, "OpTypeInt 32 0", TYPE_U32, 32, vectorSize)
2830 {
2831 m_cases[0] = 0;
2832 m_cases[1] = 3210;
2833 m_cases[2] = 268438669;
2834 }
2835
~SpvAsmTypeUint32Tests(void)2836 SpvAsmTypeUint32Tests::~SpvAsmTypeUint32Tests (void)
2837 {
2838 }
2839
getDataset(vector<deUint32> & input,deUint32 numElements)2840 void SpvAsmTypeUint32Tests::getDataset (vector<deUint32>& input,
2841 deUint32 numElements)
2842 {
2843 // Push first special cases
2844 input.push_back(0); // Min value
2845 input.push_back(~0); // Max value
2846
2847 // Push switch cases
2848 input.push_back(m_cases[0]);
2849 input.push_back(m_cases[1]);
2850 input.push_back(m_cases[2]);
2851
2852 numElements -= static_cast<deUint32>(input.size());
2853
2854 // Random values
2855 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2856 input.push_back(m_rnd.getUint32());
2857 }
2858
pushResource(vector<Resource> & resource,const vector<deUint32> & data)2859 void SpvAsmTypeUint32Tests::pushResource (vector<Resource>& resource,
2860 const vector<deUint32>& data)
2861 {
2862 resource.push_back(Resource(BufferSp(new Uint32Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2863 }
2864
2865 class SpvAsmTypeUint64Tests : public SpvAsmTypeTests<deUint64>
2866 {
2867 public:
2868 SpvAsmTypeUint64Tests (tcu::TestContext& testCtx,
2869 deUint32 vectorSize);
2870 ~SpvAsmTypeUint64Tests (void);
2871 void getDataset (vector<deUint64>& input,
2872 deUint32 numElements);
2873 void pushResource (vector<Resource>& resource,
2874 const vector<deUint64>& data);
2875 };
2876
SpvAsmTypeUint64Tests(tcu::TestContext & testCtx,deUint32 vectorSize)2877 SpvAsmTypeUint64Tests::SpvAsmTypeUint64Tests (tcu::TestContext& testCtx,
2878 deUint32 vectorSize)
2879 : SpvAsmTypeTests (testCtx, "u64", "uint64 tests", "shaderInt64", "Int64", "OpTypeInt 64 0", TYPE_U64, 64, vectorSize)
2880 {
2881 m_cases[0] = 3210;
2882 m_cases[1] = 268438669;
2883 m_cases[2] = 26843866939192872;
2884 }
2885
~SpvAsmTypeUint64Tests(void)2886 SpvAsmTypeUint64Tests::~SpvAsmTypeUint64Tests (void)
2887 {
2888 }
2889
getDataset(vector<deUint64> & input,deUint32 numElements)2890 void SpvAsmTypeUint64Tests::getDataset (vector<deUint64>& input,
2891 deUint32 numElements)
2892 {
2893 // Push first special cases
2894 input.push_back(0); // Min value
2895 input.push_back(~0); // Max value
2896
2897 // Push switch cases
2898 input.push_back(m_cases[0]);
2899 input.push_back(m_cases[1]);
2900 input.push_back(m_cases[2]);
2901
2902 numElements -= static_cast<deUint32>(input.size());
2903
2904 // Random values
2905 for (deUint32 elemNdx = 0; elemNdx < numElements; ++elemNdx)
2906 input.push_back(m_rnd.getUint64());
2907 }
2908
pushResource(vector<Resource> & resource,const vector<deUint64> & data)2909 void SpvAsmTypeUint64Tests::pushResource (vector<Resource>& resource,
2910 const vector<deUint64>& data)
2911 {
2912 resource.push_back(Resource(BufferSp(new Uint64Buffer(data)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
2913 }
2914
2915 template <class T>
2916 class TestMath
2917 {
2918 public:
test_abs(T x)2919 static inline T test_abs (T x)
2920 {
2921 T t0 = static_cast<T>(0.0);
2922
2923 if (x >= t0)
2924 return x;
2925 else
2926 return test_negate(x);
2927 }
2928
test_add(T x,T y)2929 static inline T test_add (T x, T y)
2930 {
2931 return static_cast<T>(x + y);
2932 }
2933
test_clamp(T x,T minVal,T maxVal)2934 static inline T test_clamp (T x, T minVal, T maxVal)
2935 {
2936 return test_min(test_max(x, minVal), maxVal);
2937 }
2938
test_div(T x,T y)2939 static inline T test_div (T x, T y)
2940 {
2941 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
2942 // let's return 0
2943 if (y == static_cast<T>(0))
2944 return 0;
2945 else
2946 return static_cast<T>(x / y);
2947 }
2948
test_lsb(T x)2949 static inline T test_lsb (T x)
2950 {
2951 for (deUint32 i = 0; i < 8 * sizeof(T); i++)
2952 {
2953 if (x & (1u << i))
2954 return static_cast<T>(i);
2955 }
2956
2957 return static_cast<T>(-1.0);
2958 }
2959
test_max(T x,T y)2960 static inline T test_max (T x, T y)
2961 {
2962 if (x < y)
2963 return y;
2964 else
2965 return x;
2966 }
2967
test_min(T x,T y)2968 static inline T test_min (T x, T y)
2969 {
2970 if (y < x)
2971 return y;
2972 else
2973 return x;
2974 }
2975
test_mod(T x,T y)2976 static inline T test_mod (T x, T y)
2977 {
2978 T sign_x, sign_y;
2979
2980 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
2981 // let's return 0
2982 if (y == static_cast<T>(0))
2983 return 0;
2984
2985 if (x >= static_cast<T>(0))
2986 sign_x = 1;
2987 else
2988 sign_x = -1;
2989
2990 if (y >= static_cast<T>(0))
2991 sign_y = 1;
2992 else
2993 sign_y = -1;
2994
2995 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));
2996 }
2997
test_mul(T x,T y)2998 static inline T test_mul (T x, T y)
2999 {
3000 return static_cast<T>(x * y);
3001 }
3002
test_negate(T x)3003 static inline T test_negate (T x)
3004 {
3005 return static_cast<T>(static_cast<T>(0.0) - static_cast<T>(x));
3006 }
3007
test_rem(T x,T y)3008 static inline T test_rem (T x, T y)
3009 {
3010 // In SPIR-V, if "y" is 0, then the result is undefined. In our case,
3011 // let's return 0
3012 if (y == static_cast<T>(0))
3013 return 0;
3014
3015 return static_cast<T>(x % y);
3016 }
3017
test_sign(T x)3018 static inline T test_sign (T x)
3019 {
3020 T t0 = static_cast<T>(0.0);
3021
3022 if (x > t0)
3023 return static_cast<T>(1.0);
3024 else if (x < t0)
3025 return static_cast<T>(-1.0);
3026 else
3027 return t0;
3028 }
3029
test_sub(T x,T y)3030 static inline T test_sub (T x, T y)
3031 {
3032 return static_cast<T>(x - y);
3033 }
3034
test_msb(T)3035 static inline T test_msb (T)
3036 {
3037 TCU_THROW(InternalError, "Not implemented");
3038 }
3039
test_lsr(T x,T y)3040 static inline T test_lsr (T x, T y)
3041 {
3042 if (x >= static_cast<T>(0) || y == static_cast<T>(0))
3043 {
3044 return static_cast<T>(x >> y);
3045 }
3046 else
3047 {
3048 const T mask = de::leftZeroMask(y);
3049 return static_cast<T>((x >> y) & mask);
3050 }
3051 }
3052
test_asr(T x,T y)3053 static inline T test_asr (T x, T y)
3054 {
3055 const T bitmask = static_cast<T>(deUint64(1) << (sizeof(T) * 8u - 1u));
3056
3057 if ((x & bitmask) && y > 0)
3058 {
3059 const T mask = de::leftSetMask(y);
3060 const T result = static_cast<T>((x >> y) | mask);
3061 return result;
3062 }
3063 else
3064 {
3065 return static_cast<T>(x >> y);
3066 }
3067 }
3068
test_lsl(T x,T y)3069 static inline T test_lsl (T x, T y)
3070 {
3071 return static_cast<T>(x << y);
3072 }
3073
test_bitwise_or(T x,T y)3074 static inline T test_bitwise_or (T x, T y)
3075 {
3076 return static_cast<T>(x | y);
3077 }
3078
test_bitwise_xor(T x,T y)3079 static inline T test_bitwise_xor (T x, T y)
3080 {
3081 return static_cast<T>(x ^ y);
3082 }
3083
test_bitwise_and(T x,T y)3084 static inline T test_bitwise_and (T x, T y)
3085 {
3086 return static_cast<T>(x & y);
3087 }
3088
test_not(T x)3089 static inline T test_not (T x)
3090 {
3091 return static_cast<T>(~x);
3092 }
3093
test_iequal(T x,T y)3094 static inline T test_iequal (T x, T y)
3095 {
3096 if (x == y)
3097 return static_cast<T>(1);
3098 else
3099 return static_cast<T>(0);
3100 }
3101
test_inotequal(T x,T y)3102 static inline T test_inotequal (T x, T y)
3103 {
3104 if (x != y)
3105 return static_cast<T>(1);
3106 else
3107 return static_cast<T>(0);
3108 }
3109
test_ugreaterthan(T x,T y)3110 static inline T test_ugreaterthan (T x, T y)
3111 {
3112 if (x > y)
3113 return static_cast<T>(1);
3114 else
3115 return static_cast<T>(0);
3116 }
3117
test_ulessthan(T x,T y)3118 static inline T test_ulessthan (T x, T y)
3119 {
3120 return test_ugreaterthan(y, x);
3121 }
3122
test_sgreaterthan(T x,T y)3123 static inline T test_sgreaterthan (T x, T y)
3124 {
3125 if (x > y)
3126 return static_cast<T>(1);
3127 else
3128 return static_cast<T>(0);
3129 }
3130
test_slessthan(T x,T y)3131 static inline T test_slessthan (T x, T y)
3132 {
3133 return test_sgreaterthan(y, x);
3134 }
3135
test_ugreaterthanequal(T x,T y)3136 static inline T test_ugreaterthanequal (T x, T y)
3137 {
3138 if (x >= y)
3139 return static_cast<T>(1);
3140 else
3141 return static_cast<T>(0);
3142 }
3143
test_ulessthanequal(T x,T y)3144 static inline T test_ulessthanequal (T x, T y)
3145 {
3146 return test_ugreaterthanequal(y, x);
3147 }
3148
test_sgreaterthanequal(T x,T y)3149 static inline T test_sgreaterthanequal (T x, T y)
3150 {
3151 if (x >= y)
3152 return static_cast<T>(1);
3153 else
3154 return static_cast<T>(0);
3155 }
3156
test_slessthanequal(T x,T y)3157 static inline T test_slessthanequal (T x, T y)
3158 {
3159 return test_sgreaterthanequal(y, x);
3160 }
3161
test_bitFieldInsert(T base,T insert,T offset,T count)3162 static inline T test_bitFieldInsert (T base, T insert, T offset, T count)
3163 {
3164 const T insertMask = de::rightSetMask(count);
3165
3166 return static_cast<T>((base & ~(insertMask << offset)) | ((insert & insertMask) << offset));
3167 }
3168
test_bitFieldSExtract(T x,T y,T z)3169 static inline T test_bitFieldSExtract (T x, T y, T z)
3170 {
3171 const T allZeros = static_cast<T>(0);
3172
3173 // Count can be 0, in which case the result will be 0
3174 if (z == allZeros)
3175 return allZeros;
3176
3177 const T extractMask = de::rightSetMask(z);
3178 const T signBit = static_cast<T>(x & (1 << (y + z - 1)));
3179 const T signMask = static_cast<T>(signBit ? ~extractMask : allZeros);
3180
3181 return static_cast<T>((signMask & ~extractMask) | ((x >> y) & extractMask));
3182 }
3183
test_bitFieldUExtract(T x,T y,T z)3184 static inline T test_bitFieldUExtract (T x, T y, T z)
3185 {
3186 const T allZeros = (static_cast<T>(0));
3187
3188 // Count can be 0, in which case the result will be 0
3189 if (z == allZeros)
3190 return allZeros;
3191
3192 const T extractMask = de::rightSetMask(z);
3193
3194 return static_cast<T>((x >> y) & extractMask);
3195 }
3196
test_bitReverse(T x)3197 static inline T test_bitReverse (T x)
3198 {
3199 T base = x;
3200 T result = static_cast<T>(0);
3201
3202 for (size_t bitNdx = 0u; bitNdx < sizeof(T) * 8u; bitNdx++)
3203 {
3204 result = static_cast<T>(result << 1) | (base & 1);
3205 base >>= 1;
3206 }
3207
3208 return result;
3209 }
3210
test_bitCount(T x)3211 static inline T test_bitCount (T x)
3212 {
3213 T count = static_cast<T>(0);
3214
3215 for (deUint32 bitNdx = 0u; bitNdx < (deUint32)sizeof(T) * 8u; bitNdx++)
3216 if (x & (static_cast<T>(1) << bitNdx))
3217 count++;
3218
3219 return count;
3220 }
3221
test_constant(T a)3222 static inline T test_constant (T a)
3223 {
3224 return a;
3225 }
3226 };
3227
3228 class TestMathInt8 : public TestMath<deInt8>
3229 {
3230 public:
test_msb(deInt8 x)3231 static inline deInt8 test_msb (deInt8 x)
3232 {
3233 if (x > 0)
3234 return static_cast<deInt8>(7 - deClz32((deUint32)x));
3235 else if (x < 0)
3236 return static_cast<deInt8>(7 - deClz32(~(deUint32)x));
3237 else
3238 return -1;
3239 }
3240
test_mul_div(deInt8 x,deInt8 y)3241 static inline deInt8 test_mul_div (deInt8 x, deInt8 y)
3242 {
3243 deInt32 x32 = static_cast<deInt32>(x);
3244 deInt32 y32 = static_cast<deInt32>(y);
3245
3246 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3247 if (y == static_cast<deInt8>(0))
3248 return 0;
3249 else
3250 return static_cast<deInt8>(static_cast<deInt8>(x32 * y32) / y32);
3251 }
3252
test_ugreaterthan(deInt8 x,deInt8 y)3253 static inline deInt8 test_ugreaterthan (deInt8 x, deInt8 y)
3254 {
3255 // Consume signed integers as unsigned integers
3256 if ((x & 0x80) ^ (y & 0x80))
3257 std::swap(x,y);
3258
3259 if (x > y)
3260 return static_cast<deInt8>(1);
3261 else
3262 return static_cast<deInt8>(0);
3263 }
3264
test_ulessthan(deInt8 x,deInt8 y)3265 static inline deInt8 test_ulessthan (deInt8 x, deInt8 y)
3266 {
3267 return test_ugreaterthan(y, x);
3268 }
3269
test_ugreaterthanequal(deInt8 x,deInt8 y)3270 static inline deInt8 test_ugreaterthanequal (deInt8 x, deInt8 y)
3271 {
3272 // Consume signed integers as unsigned integers
3273 if ((x & 0x80) ^ (y & 0x80))
3274 std::swap(x,y);
3275
3276 if (x >= y)
3277 return static_cast<deInt8>(1);
3278 else
3279 return static_cast<deInt8>(0);
3280 }
3281
test_ulessthanequal(deInt8 x,deInt8 y)3282 static inline deInt8 test_ulessthanequal (deInt8 x, deInt8 y)
3283 {
3284 return test_ugreaterthanequal(y, x);
3285 }
3286 };
3287
3288 class TestMathInt16 : public TestMath<deInt16>
3289 {
3290 public:
test_msb(deInt16 x)3291 static inline deInt16 test_msb (deInt16 x)
3292 {
3293 if (x > 0)
3294 return static_cast<deInt16>(15 - deClz32((deUint32)x));
3295 else if (x < 0)
3296 return static_cast<deInt16>(15 - deClz32(~(deUint32)x));
3297 else
3298 return -1;
3299 }
3300
test_mul_div(deInt16 x,deInt16 y)3301 static inline deInt16 test_mul_div (deInt16 x, deInt16 y)
3302 {
3303 deInt32 x32 = static_cast<deInt32>(x);
3304 deInt32 y32 = static_cast<deInt32>(y);
3305
3306 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3307 if (y == static_cast<deInt16>(0))
3308 return 0;
3309 else
3310 return static_cast<deInt16>(static_cast<deInt16>(x32 * y32) / y32);
3311 }
3312
test_ugreaterthan(deInt16 x,deInt16 y)3313 static inline deInt16 test_ugreaterthan (deInt16 x, deInt16 y)
3314 {
3315 // Consume signed integers as unsigned integers
3316 if ((x & 0x8000) ^ (y & 0x8000))
3317 std::swap(x,y);
3318
3319 if (x > y)
3320 return static_cast<deInt16>(1);
3321 else
3322 return static_cast<deInt16>(0);
3323 }
3324
test_ulessthan(deInt16 x,deInt16 y)3325 static inline deInt16 test_ulessthan (deInt16 x, deInt16 y)
3326 {
3327 return test_ugreaterthan(y, x);
3328 }
3329
test_ugreaterthanequal(deInt16 x,deInt16 y)3330 static inline deInt16 test_ugreaterthanequal (deInt16 x, deInt16 y)
3331 {
3332 // Consume signed integers as unsigned integers
3333 if ((x & 0x8000) ^ (y & 0x8000))
3334 std::swap(x,y);
3335
3336 if (x >= y)
3337 return static_cast<deInt16>(1);
3338 else
3339 return static_cast<deInt16>(0);
3340 }
3341
test_ulessthanequal(deInt16 x,deInt16 y)3342 static inline deInt16 test_ulessthanequal (deInt16 x, deInt16 y)
3343 {
3344 return test_ugreaterthanequal(y, x);
3345 }
3346 };
3347
3348 class TestMathInt32 : public TestMath<deInt32>
3349 {
3350 public:
test_msb(deInt32 x)3351 static inline deInt32 test_msb (deInt32 x)
3352 {
3353 if (x > 0)
3354 return 31 - deClz32((deUint32)x);
3355 else if (x < 0)
3356 return 31 - deClz32(~(deUint32)x);
3357 else
3358 return -1;
3359 }
3360
test_ugreaterthan(deInt32 x,deInt32 y)3361 static inline deInt32 test_ugreaterthan (deInt32 x, deInt32 y)
3362 {
3363 // Consume signed integers as unsigned integers
3364 if ((x & 0x80000000) ^ (y & 0x80000000))
3365 std::swap(x,y);
3366
3367 if (x > y)
3368 return static_cast<deInt32>(1);
3369 else
3370 return static_cast<deInt32>(0);
3371 }
3372
test_ulessthan(deInt32 x,deInt32 y)3373 static inline deInt32 test_ulessthan (deInt32 x, deInt32 y)
3374 {
3375 return test_ugreaterthan(y, x);
3376 }
3377
test_ugreaterthanequal(deInt32 x,deInt32 y)3378 static inline deInt32 test_ugreaterthanequal (deInt32 x, deInt32 y)
3379 {
3380 // Consume signed integers as unsigned integers
3381 if ((x & 0x80000000) ^ (y & 0x80000000))
3382 std::swap(x,y);
3383
3384 if (x >= y)
3385 return static_cast<deInt32>(1);
3386 else
3387 return static_cast<deInt32>(0);
3388 }
3389
test_ulessthanequal(deInt32 x,deInt32 y)3390 static inline deInt32 test_ulessthanequal (deInt32 x, deInt32 y)
3391 {
3392 return test_ugreaterthanequal(y, x);
3393 }
3394 };
3395
3396 class TestMathInt64 : public TestMath<deInt64>
3397 {
3398 public:
test_ugreaterthan(deInt64 x,deInt64 y)3399 static inline deInt64 test_ugreaterthan (deInt64 x, deInt64 y)
3400 {
3401 // Consume signed integers as unsigned integers
3402 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3403 std::swap(x,y);
3404
3405 if (x > y)
3406 return static_cast<deInt64>(1);
3407 else
3408 return static_cast<deInt64>(0);
3409 }
3410
test_ulessthan(deInt64 x,deInt64 y)3411 static inline deInt64 test_ulessthan (deInt64 x, deInt64 y)
3412 {
3413 return test_ugreaterthan(y, x);
3414 }
3415
test_ugreaterthanequal(deInt64 x,deInt64 y)3416 static inline deInt64 test_ugreaterthanequal (deInt64 x, deInt64 y)
3417 {
3418 // Consume signed integers as unsigned integers
3419 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3420 std::swap(x,y);
3421
3422 if (x >= y)
3423 return static_cast<deInt64>(1);
3424 else
3425 return static_cast<deInt64>(0);
3426 }
3427
test_ulessthanequal(deInt64 x,deInt64 y)3428 static inline deInt64 test_ulessthanequal (deInt64 x, deInt64 y)
3429 {
3430 return test_ugreaterthanequal(y, x);
3431 }
3432 };
3433
3434 class TestMathUint8 : public TestMath<deUint8>
3435 {
3436 public:
test_msb(deUint8 x)3437 static inline deUint32 test_msb (deUint8 x)
3438 {
3439 if (x > 0)
3440 return 7 - deClz32((deUint32)x);
3441 else
3442 return -1;
3443 }
3444
test_mul_div(deUint8 x,deUint8 y)3445 static inline deUint8 test_mul_div (deUint8 x, deUint8 y)
3446 {
3447 const deUint32 x32 = static_cast<deUint32>(x);
3448 const deUint32 y32 = static_cast<deUint32>(y);
3449
3450 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3451 if (y == static_cast<deUint8>(0))
3452 return 0;
3453 else
3454 return static_cast<deUint8>(static_cast<deUint8>(x32 * y32) / y32);
3455 }
3456
test_sgreaterthan(deUint8 x,deUint8 y)3457 static inline deUint8 test_sgreaterthan (deUint8 x, deUint8 y)
3458 {
3459 // Consume unsigned integers as signed integers
3460 if ((x & 0x80) ^ (y & 0x80))
3461 std::swap(x,y);
3462
3463 if (x > y)
3464 return static_cast<deUint8>(1);
3465 else
3466 return static_cast<deUint8>(0);
3467 }
3468
test_slessthan(deUint8 x,deUint8 y)3469 static inline deUint8 test_slessthan (deUint8 x, deUint8 y)
3470 {
3471 return test_sgreaterthan(y, x);
3472 }
3473
test_sgreaterthanequal(deUint8 x,deUint8 y)3474 static inline deUint8 test_sgreaterthanequal (deUint8 x, deUint8 y)
3475 {
3476 // Consume unsigned integers as signed integers
3477 if ((x & 0x80) ^ (y & 0x80))
3478 std::swap(x,y);
3479
3480 if (x >= y)
3481 return static_cast<deUint8>(1);
3482 else
3483 return static_cast<deUint8>(0);
3484 }
3485
test_slessthanequal(deUint8 x,deUint8 y)3486 static inline deUint8 test_slessthanequal (deUint8 x, deUint8 y)
3487 {
3488 return test_sgreaterthanequal(y, x);
3489 }
3490 };
3491
3492 class TestMathUint16 : public TestMath<deUint16>
3493 {
3494 public:
test_msb(deUint16 x)3495 static inline deUint32 test_msb (deUint16 x)
3496 {
3497 if (x > 0)
3498 return 15 - deClz32((deUint32)x);
3499 else
3500 return -1;
3501 }
3502
test_mul_div(deUint16 x,deUint16 y)3503 static inline deUint16 test_mul_div (deUint16 x, deUint16 y)
3504 {
3505 const deUint32 x32 = static_cast<deUint32>(x);
3506 const deUint32 y32 = static_cast<deUint32>(y);
3507
3508 // In SPIR-V, if "y" is 0, then the result is undefined. In our case, let's return 0
3509 if (y == static_cast<deUint16>(0))
3510 return 0;
3511 else
3512 return static_cast<deUint16>(static_cast<deUint16>(x32 * y32) / y32);
3513 }
3514
test_sgreaterthan(deUint16 x,deUint16 y)3515 static inline deUint16 test_sgreaterthan (deUint16 x, deUint16 y)
3516 {
3517 // Consume unsigned integers as signed integers
3518 if ((x & 0x8000) ^ (y & 0x8000))
3519 std::swap(x,y);
3520
3521 if (x > y)
3522 return static_cast<deUint16>(1);
3523 else
3524 return static_cast<deUint16>(0);
3525 }
3526
test_slessthan(deUint16 x,deUint16 y)3527 static inline deUint16 test_slessthan (deUint16 x, deUint16 y)
3528 {
3529 return test_sgreaterthan(y, x);
3530 }
3531
test_sgreaterthanequal(deUint16 x,deUint16 y)3532 static inline deUint16 test_sgreaterthanequal (deUint16 x, deUint16 y)
3533 {
3534 // Consume unsigned integers as signed integers
3535 if ((x & 0x8000) ^ (y & 0x8000))
3536 std::swap(x,y);
3537
3538 if (x >= y)
3539 return static_cast<deUint16>(1);
3540 else
3541 return static_cast<deUint16>(0);
3542 }
3543
test_slessthanequal(deUint16 x,deUint16 y)3544 static inline deUint16 test_slessthanequal (deUint16 x, deUint16 y)
3545 {
3546 return test_sgreaterthanequal(y, x);
3547 }
3548 };
3549
3550 class TestMathUint32 : public TestMath<deUint32>
3551 {
3552 public:
test_msb(deUint32 x)3553 static inline deUint32 test_msb (deUint32 x)
3554 {
3555 if (x > 0)
3556 return 31 - deClz32(x);
3557 else
3558 return -1;
3559 }
3560
test_sgreaterthan(deUint32 x,deUint32 y)3561 static inline deUint32 test_sgreaterthan (deUint32 x, deUint32 y)
3562 {
3563 // Consume unsigned integers as signed integers
3564 if ((x & 0x80000000) ^ (y & 0x80000000))
3565 std::swap(x,y);
3566
3567 if (x > y)
3568 return static_cast<deUint32>(1);
3569 else
3570 return static_cast<deUint32>(0);
3571 }
3572
test_slessthan(deUint32 x,deUint32 y)3573 static inline deUint32 test_slessthan (deUint32 x, deUint32 y)
3574 {
3575 return test_sgreaterthan(y, x);
3576 }
3577
test_sgreaterthanequal(deUint32 x,deUint32 y)3578 static inline deUint32 test_sgreaterthanequal (deUint32 x, deUint32 y)
3579 {
3580 // Consume unsigned integers as signed integers
3581 if ((x & 0x80000000) ^ (y & 0x80000000))
3582 std::swap(x,y);
3583
3584 if (x >= y)
3585 return static_cast<deUint32>(1);
3586 else
3587 return static_cast<deUint32>(0);
3588 }
3589
test_slessthanequal(deUint32 x,deUint32 y)3590 static inline deUint32 test_slessthanequal (deUint32 x, deUint32 y)
3591 {
3592 return test_sgreaterthanequal(y, x);
3593 }
3594
3595 };
3596
3597 class TestMathUint64 : public TestMath<deUint64>
3598 {
3599 public:
test_sgreaterthan(deUint64 x,deUint64 y)3600 static inline deUint64 test_sgreaterthan (deUint64 x, deUint64 y)
3601 {
3602 // Consume unsigned integers as signed integers
3603 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3604 std::swap(x,y);
3605
3606 if (x > y)
3607 return static_cast<deUint64>(1);
3608 else
3609 return static_cast<deUint64>(0);
3610 }
3611
test_slessthan(deUint64 x,deUint64 y)3612 static inline deUint64 test_slessthan (deUint64 x, deUint64 y)
3613 {
3614 return test_sgreaterthan(y, x);
3615 }
3616
test_sgreaterthanequal(deUint64 x,deUint64 y)3617 static inline deUint64 test_sgreaterthanequal (deUint64 x, deUint64 y)
3618 {
3619 // Consume unsigned integers as signed integers
3620 if ((x & 0x8000000000000000) ^ (y & 0x8000000000000000))
3621 std::swap(x,y);
3622
3623 if (x >= y)
3624 return static_cast<deUint64>(1);
3625 else
3626 return static_cast<deUint64>(0);
3627 }
3628
test_slessthanequal(deUint64 x,deUint64 y)3629 static inline deUint64 test_slessthanequal (deUint64 x, deUint64 y)
3630 {
3631 return test_sgreaterthanequal(y, x);
3632 }
3633 };
3634
3635 #define I8_FILTER_NONE SpvAsmTypeInt8Tests::filterNone
3636 #define I16_FILTER_NONE SpvAsmTypeInt16Tests::filterNone
3637 #define I32_FILTER_NONE SpvAsmTypeInt32Tests::filterNone
3638 #define I64_FILTER_NONE SpvAsmTypeInt64Tests::filterNone
3639 #define U8_FILTER_NONE SpvAsmTypeUint8Tests::filterNone
3640 #define U16_FILTER_NONE SpvAsmTypeUint16Tests::filterNone
3641 #define U32_FILTER_NONE SpvAsmTypeUint32Tests::filterNone
3642 #define U64_FILTER_NONE SpvAsmTypeUint64Tests::filterNone
3643
3644 #define I8_FILTER_ZERO SpvAsmTypeInt8Tests::filterZero
3645 #define I16_FILTER_ZERO SpvAsmTypeInt16Tests::filterZero
3646 #define I32_FILTER_ZERO SpvAsmTypeInt32Tests::filterZero
3647 #define I64_FILTER_ZERO SpvAsmTypeInt64Tests::filterZero
3648 #define U8_FILTER_ZERO SpvAsmTypeUint8Tests::filterZero
3649 #define U16_FILTER_ZERO SpvAsmTypeUint16Tests::filterZero
3650 #define U32_FILTER_ZERO SpvAsmTypeUint32Tests::filterZero
3651 #define U64_FILTER_ZERO SpvAsmTypeUint64Tests::filterZero
3652
3653 #define I8_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt8Tests::filterNegativesAndZero
3654 #define I16_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt16Tests::filterNegativesAndZero
3655 #define I32_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt32Tests::filterNegativesAndZero
3656 #define I64_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeInt64Tests::filterNegativesAndZero
3657 #define U8_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint8Tests::filterNegativesAndZero
3658 #define U16_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint16Tests::filterNegativesAndZero
3659 #define U32_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint32Tests::filterNegativesAndZero
3660 #define U64_FILTER_NEGATIVES_AND_ZERO SpvAsmTypeUint64Tests::filterNegativesAndZero
3661
3662 #define I8_FILTER_MIN_GT_MAX SpvAsmTypeInt8Tests::filterMinGtMax
3663 #define I16_FILTER_MIN_GT_MAX SpvAsmTypeInt16Tests::filterMinGtMax
3664 #define I32_FILTER_MIN_GT_MAX SpvAsmTypeInt32Tests::filterMinGtMax
3665 #define I64_FILTER_MIN_GT_MAX SpvAsmTypeInt64Tests::filterMinGtMax
3666 #define U8_FILTER_MIN_GT_MAX SpvAsmTypeUint8Tests::filterMinGtMax
3667 #define U16_FILTER_MIN_GT_MAX SpvAsmTypeUint16Tests::filterMinGtMax
3668 #define U32_FILTER_MIN_GT_MAX SpvAsmTypeUint32Tests::filterMinGtMax
3669 #define U64_FILTER_MIN_GT_MAX SpvAsmTypeUint64Tests::filterMinGtMax
3670
3671 const string bitShiftTestPostfix[] =
3672 {
3673 "_shift8",
3674 "_shift16",
3675 "_shift32",
3676 "_shift64"
3677 };
3678
3679 const string bitFieldTestPostfix[] =
3680 {
3681 "_offset8_count8",
3682 "_offset8_count16",
3683 "_offset8_count32",
3684 "_offset8_count64",
3685 "_offset16_count8",
3686 "_offset16_count16",
3687 "_offset16_count32",
3688 "_offset16_count64",
3689 "_offset32_count8",
3690 "_offset32_count16",
3691 "_offset32_count32",
3692 "_offset32_count64",
3693 "_offset64_count8",
3694 "_offset64_count16",
3695 "_offset64_count32",
3696 "_offset64_count64",
3697 };
3698
3699 // Macro to create tests.
3700 // Syntax: MAKE_TEST_{S,V}_{I,U}_{8,1,3,6}
3701 //
3702 // 'S': create scalar test
3703 // 'V': create vector test
3704 //
3705 // 'I': create integer test
3706 // 'U': create unsigned integer test
3707 //
3708 // '8': create 8-bit test
3709 // '1': create 16-bit test
3710 // '3': create 32-bit test
3711 // '6': create 64-bit test
3712 //
3713 // 'W': bit width of some parameters in bit field and shift operations can be different from Result and Base
3714 // 'N': create 16-bit tests without 'test_high_part_zero' variants
3715
3716 #define MAKE_TEST_S_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3717 for (deUint32 ndx = 0; ndx < 1; ++ndx) \
3718 { \
3719 int8Tests[ndx]->createTests((name), (spirvOp), \
3720 TestMathInt8::test_##op, I8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3721 int16Tests[ndx]->createTests((name), (spirvOp), \
3722 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3723 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3724 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3725 int32Tests[ndx]->createTests((name), (spirvOp), \
3726 TestMathInt32::test_##op, I32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3727 int64Tests[ndx]->createTests((name), (spirvOp), \
3728 TestMathInt64::test_##op, I64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3729 } \
3730
3731 #define MAKE_TEST_V_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3732 for (deUint32 ndx = 1; ndx < 4; ++ndx) \
3733 { \
3734 int8Tests[ndx]->createTests((name), (spirvOp), \
3735 TestMathInt8::test_##op, I8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3736 int16Tests[ndx]->createTests((name), (spirvOp), \
3737 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3738 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3739 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3740 int32Tests[ndx]->createTests((name), (spirvOp), \
3741 TestMathInt32::test_##op, I32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3742 int64Tests[ndx]->createTests((name), (spirvOp), \
3743 TestMathInt64::test_##op, I64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3744 } \
3745
3746 #define MAKE_TEST_SV_I_8136(name, spirvOp, op, filter, inputRange, extension) \
3747 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3748 { \
3749 int8Tests[ndx]->createTests((name), (spirvOp), \
3750 TestMathInt8::test_##op, I8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3751 int16Tests[ndx]->createTests((name), (spirvOp), \
3752 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3753 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3754 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3755 int32Tests[ndx]->createTests((name), (spirvOp), \
3756 TestMathInt32::test_##op, I32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3757 int64Tests[ndx]->createTests((name), (spirvOp), \
3758 TestMathInt64::test_##op, I64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3759 } \
3760
3761 #define MAKE_TEST_SV_I_8136_N(name, spirvOp, op, filter, inputRange, extension) \
3762 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3763 { \
3764 int8Tests[ndx]->createTests((name), (spirvOp), \
3765 TestMathInt8::test_##op, I8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3766 int16Tests[ndx]->createTests((name), (spirvOp), \
3767 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3768 int32Tests[ndx]->createTests((name), (spirvOp), \
3769 TestMathInt32::test_##op, I32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3770 int64Tests[ndx]->createTests((name), (spirvOp), \
3771 TestMathInt64::test_##op, I64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3772 } \
3773
3774 #define MAKE_TEST_SV_I_8136_W(name, spirvOp, op, filter, inputRange, extension) \
3775 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3776 for (deUint32 widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(bitShiftTestPostfix); ++widthNdx) \
3777 { \
3778 const InputWidth inputWidth = static_cast<InputWidth>(WIDTH_8 + widthNdx); \
3779 \
3780 int8Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3781 TestMathInt8::test_##op, I8_##filter, inputRange, inputWidth, (extension)); \
3782 int16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3783 TestMathInt16::test_##op, I16_##filter, inputRange, inputWidth, (extension)); \
3784 int16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx] + "_test_high_part_zero").c_str(), (spirvOp), \
3785 TestMathInt16::test_##op, I16_##filter, inputRange, inputWidth, (extension), true); \
3786 int32Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3787 TestMathInt32::test_##op, I32_##filter, inputRange, inputWidth, (extension)); \
3788 int64Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3789 TestMathInt64::test_##op, I64_##filter, inputRange, inputWidth, (extension)); \
3790 } \
3791
3792 #define MAKE_TEST_SV_I_1(name, spirvOp, op, filter, inputRange, extension) \
3793 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3794 { \
3795 int16Tests[ndx]->createTests((name), (spirvOp), \
3796 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3797 int16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3798 TestMathInt16::test_##op, I16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3799 } \
3800
3801 #define MAKE_TEST_SV_I_3(name, spirvOp, op, filter, inputRange, extension) \
3802 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3803 int32Tests[ndx]->createTests((name), (spirvOp), \
3804 TestMathInt32::test_##op, I32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3805
3806 #define MAKE_TEST_SV_I_3_W(name, spirvOp, op, filter, inputRange, extension) \
3807 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3808 for (deUint32 width = 0; width < DE_LENGTH_OF_ARRAY(bitFieldTestPostfix); ++width) \
3809 { \
3810 int32Tests[ndx]->createTests(string(name + bitFieldTestPostfix[width]).c_str(), (spirvOp), \
3811 TestMathInt32::test_##op, I32_##filter, inputRange, InputWidth(WIDTH_8_8 + width), (extension)); \
3812 } \
3813
3814 #define MAKE_TEST_S_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3815 for (deUint32 ndx = 0; ndx < 1; ++ndx) \
3816 { \
3817 uint8Tests[ndx]->createTests((name), (spirvOp), \
3818 TestMathUint8::test_##op, U8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3819 uint16Tests[ndx]->createTests((name), (spirvOp), \
3820 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3821 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3822 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3823 uint32Tests[ndx]->createTests((name), (spirvOp), \
3824 TestMathUint32::test_##op, U32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3825 uint64Tests[ndx]->createTests((name), (spirvOp), \
3826 TestMathUint64::test_##op, U64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3827 } \
3828
3829 #define MAKE_TEST_V_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3830 for (deUint32 ndx = 1; ndx < 4; ++ndx) \
3831 { \
3832 uint16Tests[ndx]->createTests((name), (spirvOp), \
3833 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3834 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3835 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3836 uint32Tests[ndx]->createTests((name), (spirvOp), \
3837 TestMathUint32::test_##op, U32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3838 uint64Tests[ndx]->createTests((name), (spirvOp), \
3839 TestMathUint64::test_##op, U64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3840 } \
3841
3842 #define MAKE_TEST_SV_U_8136(name, spirvOp, op, filter, inputRange, extension) \
3843 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3844 { \
3845 uint8Tests[ndx]->createTests((name), (spirvOp), \
3846 TestMathUint8::test_##op, U8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3847 uint16Tests[ndx]->createTests((name), (spirvOp), \
3848 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3849 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3850 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3851 uint32Tests[ndx]->createTests((name), (spirvOp), \
3852 TestMathUint32::test_##op, U32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3853 uint64Tests[ndx]->createTests((name), (spirvOp), \
3854 TestMathUint64::test_##op, U64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3855 } \
3856
3857 #define MAKE_TEST_SV_U_8136_N(name, spirvOp, op, filter, inputRange, extension) \
3858 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3859 { \
3860 uint8Tests[ndx]->createTests((name), (spirvOp), \
3861 TestMathUint8::test_##op, U8_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3862 uint16Tests[ndx]->createTests((name), (spirvOp), \
3863 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3864 uint32Tests[ndx]->createTests((name), (spirvOp), \
3865 TestMathUint32::test_##op, U32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3866 uint64Tests[ndx]->createTests((name), (spirvOp), \
3867 TestMathUint64::test_##op, U64_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3868 } \
3869
3870 #define MAKE_TEST_SV_U_8136_W(name, spirvOp, op, filter, inputRange, extension) \
3871 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3872 for (deUint32 widthNdx = 0; widthNdx < DE_LENGTH_OF_ARRAY(bitShiftTestPostfix); ++widthNdx) \
3873 { \
3874 const InputWidth inputWidth = static_cast<InputWidth>(WIDTH_8 + widthNdx); \
3875 \
3876 uint8Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3877 TestMathUint8::test_##op, U8_##filter, inputRange, inputWidth, (extension)); \
3878 uint16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3879 TestMathUint16::test_##op, U16_##filter, inputRange, inputWidth, (extension)); \
3880 uint16Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx] + "_test_high_part_zero").c_str(), (spirvOp), \
3881 TestMathUint16::test_##op, U16_##filter, inputRange, inputWidth, (extension), true); \
3882 uint32Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3883 TestMathUint32::test_##op, U32_##filter, inputRange, inputWidth, (extension)); \
3884 uint64Tests[ndx]->createTests(string(name + bitShiftTestPostfix[widthNdx]).c_str(), (spirvOp), \
3885 TestMathUint64::test_##op, U64_##filter, inputRange, inputWidth, (extension)); \
3886 } \
3887
3888 #define MAKE_TEST_SV_U_1(name, spirvOp, op, filter, inputRange, extension) \
3889 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3890 { \
3891 uint16Tests[ndx]->createTests((name), (spirvOp), \
3892 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3893 uint16Tests[ndx]->createTests((name "_test_high_part_zero"), (spirvOp), \
3894 TestMathUint16::test_##op, U16_##filter, inputRange, WIDTH_DEFAULT, (extension), true); \
3895 } \
3896
3897 #define MAKE_TEST_SV_U_3(name, spirvOp, op, filter, inputRange, extension) \
3898 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3899 uint32Tests[ndx]->createTests((name), (spirvOp), \
3900 TestMathUint32::test_##op, U32_##filter, inputRange, WIDTH_DEFAULT, (extension)); \
3901
3902 #define MAKE_TEST_SV_U_3_W(name, spirvOp, op, filter, inputRange, extension) \
3903 for (deUint32 ndx = 0; ndx < 4; ++ndx) \
3904 for (deUint32 width = 0; width < DE_LENGTH_OF_ARRAY(bitFieldTestPostfix); ++width) \
3905 { \
3906 uint32Tests[ndx]->createTests(string(name + bitFieldTestPostfix[width]).c_str(), (spirvOp), \
3907 TestMathUint32::test_##op, U32_##filter, inputRange, InputWidth(WIDTH_8_8 + width), (extension)); \
3908 } \
3909
createTypeTests(tcu::TestContext & testCtx)3910 tcu::TestCaseGroup* createTypeTests (tcu::TestContext& testCtx)
3911 {
3912 de::MovePtr<tcu::TestCaseGroup> typeTests (new tcu::TestCaseGroup(testCtx, "type", "Test types"));
3913 de::MovePtr<tcu::TestCaseGroup> typeScalarTests (new tcu::TestCaseGroup(testCtx, "scalar", "scalar tests"));
3914 de::MovePtr<tcu::TestCaseGroup> typeVectorTests[3];
3915
3916 de::MovePtr<SpvAsmTypeInt8Tests> int8Tests[4];
3917 de::MovePtr<SpvAsmTypeInt16Tests> int16Tests[4];
3918 de::MovePtr<SpvAsmTypeInt32Tests> int32Tests[4];
3919 de::MovePtr<SpvAsmTypeInt64Tests> int64Tests[4];
3920 de::MovePtr<SpvAsmTypeUint8Tests> uint8Tests[4];
3921 de::MovePtr<SpvAsmTypeUint16Tests> uint16Tests[4];
3922 de::MovePtr<SpvAsmTypeUint32Tests> uint32Tests[4];
3923 de::MovePtr<SpvAsmTypeUint64Tests> uint64Tests[4];
3924
3925 for (deUint32 ndx = 0; ndx < 3; ++ndx)
3926 {
3927 std::string testName = "vec" + de::toString(ndx + 2);
3928 typeVectorTests[ndx] = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, testName.c_str(), "vector tests"));
3929 }
3930
3931 for (deUint32 ndx = 0; ndx < 4; ++ndx)
3932 {
3933 int8Tests[ndx] = de::MovePtr<SpvAsmTypeInt8Tests>(new SpvAsmTypeInt8Tests(testCtx, ndx + 1));
3934 int16Tests[ndx] = de::MovePtr<SpvAsmTypeInt16Tests>(new SpvAsmTypeInt16Tests(testCtx, ndx + 1));
3935 int32Tests[ndx] = de::MovePtr<SpvAsmTypeInt32Tests>(new SpvAsmTypeInt32Tests(testCtx, ndx + 1));
3936 int64Tests[ndx] = de::MovePtr<SpvAsmTypeInt64Tests>(new SpvAsmTypeInt64Tests(testCtx, ndx + 1));
3937 uint8Tests[ndx] = de::MovePtr<SpvAsmTypeUint8Tests>(new SpvAsmTypeUint8Tests(testCtx, ndx + 1));
3938 uint16Tests[ndx] = de::MovePtr<SpvAsmTypeUint16Tests>(new SpvAsmTypeUint16Tests(testCtx, ndx + 1));
3939 uint32Tests[ndx] = de::MovePtr<SpvAsmTypeUint32Tests>(new SpvAsmTypeUint32Tests(testCtx, ndx + 1));
3940 uint64Tests[ndx] = de::MovePtr<SpvAsmTypeUint64Tests>(new SpvAsmTypeUint64Tests(testCtx, ndx + 1));
3941 }
3942
3943 MAKE_TEST_SV_I_8136("negate", SpvOpSNegate, negate, FILTER_NONE, RANGE_FULL, DE_NULL);
3944 MAKE_TEST_SV_I_8136("add", SpvOpIAdd, add, FILTER_NONE, RANGE_FULL, DE_NULL);
3945 MAKE_TEST_SV_I_8136("sub", SpvOpISub, sub, FILTER_NONE, RANGE_FULL, DE_NULL);
3946 MAKE_TEST_SV_I_8136("mul", SpvOpIMul, mul, FILTER_NONE, RANGE_FULL, DE_NULL);
3947 MAKE_TEST_SV_I_8136("div", SpvOpSDiv, div, FILTER_ZERO, RANGE_FULL, DE_NULL);
3948 MAKE_TEST_SV_U_8136("div", SpvOpUDiv, div, FILTER_ZERO, RANGE_FULL, DE_NULL);
3949 MAKE_TEST_SV_I_8136("rem", SpvOpSRem, rem, FILTER_NEGATIVES_AND_ZERO, RANGE_FULL, DE_NULL);
3950 MAKE_TEST_SV_I_8136("mod", SpvOpSMod, mod, FILTER_NEGATIVES_AND_ZERO, RANGE_FULL, DE_NULL);
3951 MAKE_TEST_SV_U_8136("mod", SpvOpUMod, mod, FILTER_ZERO, RANGE_FULL, DE_NULL);
3952 MAKE_TEST_SV_I_8136("abs", GLSLstd450SAbs, abs, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3953 MAKE_TEST_SV_I_8136("sign", GLSLstd450SSign, sign, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3954 MAKE_TEST_SV_I_8136("min", GLSLstd450SMin, min, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3955 MAKE_TEST_SV_U_8136("min", GLSLstd450UMin, min, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3956 MAKE_TEST_SV_I_8136("max", GLSLstd450SMax, max, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3957 MAKE_TEST_SV_U_8136("max", GLSLstd450UMax, max, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3958 MAKE_TEST_SV_I_8136("clamp", GLSLstd450SClamp, clamp, FILTER_MIN_GT_MAX, RANGE_FULL, "GLSL.std.450");
3959 MAKE_TEST_SV_U_8136("clamp", GLSLstd450UClamp, clamp, FILTER_MIN_GT_MAX, RANGE_FULL, "GLSL.std.450");
3960 MAKE_TEST_SV_I_3("find_lsb", GLSLstd450FindILsb, lsb, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3961 MAKE_TEST_SV_I_3("find_msb", GLSLstd450FindSMsb, msb, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3962 MAKE_TEST_SV_U_3("find_msb", GLSLstd450FindUMsb, msb, FILTER_NONE, RANGE_FULL, "GLSL.std.450");
3963 MAKE_TEST_SV_I_1("mul_sdiv", DE_NULL, mul_div, FILTER_ZERO, RANGE_FULL, DE_NULL);
3964 MAKE_TEST_SV_U_1("mul_udiv", DE_NULL, mul_div, FILTER_ZERO, RANGE_FULL, DE_NULL);
3965
3966 MAKE_TEST_SV_U_8136_W("shift_right_logical", SpvOpShiftRightLogical, lsr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3967 MAKE_TEST_SV_I_8136_W("shift_right_logical", SpvOpShiftRightLogical, lsr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3968 MAKE_TEST_SV_U_8136_W("shift_right_arithmetic", SpvOpShiftRightArithmetic, asr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3969 MAKE_TEST_SV_I_8136_W("shift_right_arithmetic", SpvOpShiftRightArithmetic, asr, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3970 MAKE_TEST_SV_U_8136_W("shift_left_logical", SpvOpShiftLeftLogical, lsl, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3971 MAKE_TEST_SV_I_8136_W("shift_left_logical", SpvOpShiftLeftLogical, lsl, FILTER_NONE, RANGE_BIT_WIDTH, DE_NULL);
3972
3973 MAKE_TEST_SV_U_8136("bitwise_or", SpvOpBitwiseOr, bitwise_or, FILTER_NONE, RANGE_FULL, DE_NULL);
3974 MAKE_TEST_SV_I_8136("bitwise_or", SpvOpBitwiseOr, bitwise_or , FILTER_NONE, RANGE_FULL, DE_NULL);
3975 MAKE_TEST_SV_U_8136("bitwise_xor", SpvOpBitwiseXor, bitwise_xor, FILTER_NONE, RANGE_FULL, DE_NULL);
3976 MAKE_TEST_SV_I_8136("bitwise_xor", SpvOpBitwiseXor, bitwise_xor, FILTER_NONE, RANGE_FULL, DE_NULL);
3977 MAKE_TEST_SV_U_8136("bitwise_and", SpvOpBitwiseAnd, bitwise_and, FILTER_NONE, RANGE_FULL, DE_NULL);
3978 MAKE_TEST_SV_I_8136("bitwise_and", SpvOpBitwiseAnd, bitwise_and, FILTER_NONE, RANGE_FULL, DE_NULL);
3979 MAKE_TEST_SV_U_8136("not", SpvOpNot, not, FILTER_NONE, RANGE_FULL, DE_NULL);
3980 MAKE_TEST_SV_I_8136("not", SpvOpNot, not, FILTER_NONE, RANGE_FULL, DE_NULL);
3981
3982 MAKE_TEST_SV_U_8136_N("iequal", SpvOpIEqual, iequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3983 MAKE_TEST_SV_I_8136_N("iequal", SpvOpIEqual, iequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3984 MAKE_TEST_SV_U_8136_N("inotequal", SpvOpINotEqual, inotequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3985 MAKE_TEST_SV_I_8136_N("inotequal", SpvOpINotEqual, inotequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3986 MAKE_TEST_SV_U_8136_N("ugreaterthan", SpvOpUGreaterThan, ugreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3987 MAKE_TEST_SV_I_8136_N("ugreaterthan", SpvOpUGreaterThan, ugreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3988 MAKE_TEST_SV_U_8136_N("sgreaterthan", SpvOpSGreaterThan, sgreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3989 MAKE_TEST_SV_I_8136_N("sgreaterthan", SpvOpSGreaterThan, sgreaterthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3990 MAKE_TEST_SV_U_8136_N("ugreaterthanequal", SpvOpUGreaterThanEqual, ugreaterthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3991 MAKE_TEST_SV_I_8136_N("ugreaterthanequal", SpvOpUGreaterThanEqual, ugreaterthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3992 MAKE_TEST_SV_U_8136_N("sgreaterthanequal", SpvOpSGreaterThanEqual, sgreaterthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3993 MAKE_TEST_SV_I_8136_N("sgreaterthanequal", SpvOpSGreaterThanEqual, sgreaterthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3994 MAKE_TEST_SV_U_8136_N("ulessthan", SpvOpULessThan, ulessthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3995 MAKE_TEST_SV_I_8136_N("ulessthan", SpvOpULessThan, ulessthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3996 MAKE_TEST_SV_U_8136_N("slessthan", SpvOpSLessThan, slessthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3997 MAKE_TEST_SV_I_8136_N("slessthan", SpvOpSLessThan, slessthan, FILTER_NONE, RANGE_FULL, DE_NULL);
3998 MAKE_TEST_SV_U_8136_N("ulessthanequal", SpvOpULessThanEqual, ulessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
3999 MAKE_TEST_SV_I_8136_N("ulessthanequal", SpvOpULessThanEqual, ulessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
4000 MAKE_TEST_SV_U_8136_N("slessthanequal", SpvOpSLessThanEqual, slessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
4001 MAKE_TEST_SV_I_8136_N("slessthanequal", SpvOpSLessThanEqual, slessthanequal, FILTER_NONE, RANGE_FULL, DE_NULL);
4002
4003 MAKE_TEST_SV_U_3_W("bit_field_insert", SpvOpBitFieldInsert, bitFieldInsert, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4004 MAKE_TEST_SV_I_3_W("bit_field_insert", SpvOpBitFieldInsert, bitFieldInsert, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4005 MAKE_TEST_SV_U_3_W("bit_field_s_extract", SpvOpBitFieldSExtract, bitFieldSExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4006 MAKE_TEST_SV_I_3_W("bit_field_s_extract", SpvOpBitFieldSExtract, bitFieldSExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4007 MAKE_TEST_SV_U_3_W("bit_field_u_extract", SpvOpBitFieldUExtract, bitFieldUExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4008 MAKE_TEST_SV_I_3_W("bit_field_u_extract", SpvOpBitFieldUExtract, bitFieldUExtract, FILTER_NONE, RANGE_BIT_WIDTH_SUM, DE_NULL);
4009 MAKE_TEST_SV_U_3("bit_reverse", SpvOpBitReverse, bitReverse, FILTER_NONE, RANGE_FULL, DE_NULL);
4010 MAKE_TEST_SV_I_3("bit_reverse", SpvOpBitReverse, bitReverse, FILTER_NONE, RANGE_FULL, DE_NULL);
4011 MAKE_TEST_SV_U_3("bit_count", SpvOpBitCount, bitCount, FILTER_NONE, RANGE_FULL, DE_NULL);
4012 MAKE_TEST_SV_I_3("bit_count", SpvOpBitCount, bitCount, FILTER_NONE, RANGE_FULL, DE_NULL);
4013
4014 MAKE_TEST_S_U_8136("constant", SpvOpConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4015 MAKE_TEST_S_I_8136("constant", SpvOpConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4016 MAKE_TEST_V_U_8136("constant_composite", SpvOpConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4017 MAKE_TEST_V_I_8136("constant_composite", SpvOpConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4018 MAKE_TEST_V_U_8136("constant_null", SpvOpConstantNull, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4019 MAKE_TEST_V_I_8136("constant_null", SpvOpConstantNull, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4020 MAKE_TEST_SV_U_8136("variable_initializer", SpvOpVariable, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4021 MAKE_TEST_SV_I_8136("variable_initializer", SpvOpVariable, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4022 MAKE_TEST_S_U_8136("spec_constant_initializer", SpvOpSpecConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4023 MAKE_TEST_S_I_8136("spec_constant_initializer", SpvOpSpecConstant, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4024 MAKE_TEST_V_U_8136("spec_constant_composite_initializer", SpvOpSpecConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4025 MAKE_TEST_V_I_8136("spec_constant_composite_initializer", SpvOpSpecConstantComposite, constant, FILTER_NONE, RANGE_FULL, DE_NULL);
4026
4027 int8Tests[0]->createSwitchTests();
4028 int16Tests[0]->createSwitchTests();
4029 int32Tests[0]->createSwitchTests();
4030 int64Tests[0]->createSwitchTests();
4031 uint8Tests[0]->createSwitchTests();
4032 uint16Tests[0]->createSwitchTests();
4033 uint32Tests[0]->createSwitchTests();
4034 uint64Tests[0]->createSwitchTests();
4035
4036 typeScalarTests->addChild(int8Tests[0].release());
4037 typeScalarTests->addChild(int16Tests[0].release());
4038 typeScalarTests->addChild(int32Tests[0].release());
4039 typeScalarTests->addChild(int64Tests[0].release());
4040 typeScalarTests->addChild(uint8Tests[0].release());
4041 typeScalarTests->addChild(uint16Tests[0].release());
4042 typeScalarTests->addChild(uint32Tests[0].release());
4043 typeScalarTests->addChild(uint64Tests[0].release());
4044
4045 typeTests->addChild(typeScalarTests.release());
4046
4047 for (deUint32 ndx = 0; ndx < 3; ++ndx)
4048 {
4049 typeVectorTests[ndx]->addChild(int8Tests[ndx + 1].release());
4050 typeVectorTests[ndx]->addChild(int16Tests[ndx + 1].release());
4051 typeVectorTests[ndx]->addChild(int32Tests[ndx + 1].release());
4052 typeVectorTests[ndx]->addChild(int64Tests[ndx + 1].release());
4053 typeVectorTests[ndx]->addChild(uint8Tests[ndx + 1].release());
4054 typeVectorTests[ndx]->addChild(uint16Tests[ndx + 1].release());
4055 typeVectorTests[ndx]->addChild(uint32Tests[ndx + 1].release());
4056 typeVectorTests[ndx]->addChild(uint64Tests[ndx + 1].release());
4057
4058 typeTests->addChild(typeVectorTests[ndx].release());
4059 }
4060
4061 return typeTests.release();
4062 }
4063
4064 } // SpirVAssembly
4065 } // vkt
4066