• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Validation tests for SSA
16 
17 #include <sstream>
18 #include <string>
19 #include <utility>
20 
21 #include "gmock/gmock.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24 
25 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::HasSubstr;
30 using ::testing::MatchesRegex;
31 
32 using ValidateSSA = spvtest::ValidateBase<std::pair<std::string, bool>>;
33 
TEST_F(ValidateSSA,Default)34 TEST_F(ValidateSSA, Default) {
35   char str[] = R"(
36      OpCapability Shader
37      OpCapability Linkage
38      OpMemoryModel Logical GLSL450
39      OpEntryPoint GLCompute %3 ""
40      OpExecutionMode %3 LocalSize 1 1 1
41 %1 = OpTypeVoid
42 %2 = OpTypeFunction %1
43 %3 = OpFunction %1 None %2
44 %4 = OpLabel
45      OpReturn
46      OpFunctionEnd
47 )";
48   CompileSuccessfully(str);
49   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
50 }
51 
TEST_F(ValidateSSA,IdUndefinedBad)52 TEST_F(ValidateSSA, IdUndefinedBad) {
53   char str[] = R"(
54           OpCapability Shader
55           OpCapability Linkage
56           OpMemoryModel Logical GLSL450
57           OpName %missing "missing"
58 %voidt  = OpTypeVoid
59 %vfunct = OpTypeFunction %voidt
60 %func   = OpFunction %vfunct None %missing
61 %flabel = OpLabel
62           OpReturn
63           OpFunctionEnd
64     )";
65   CompileSuccessfully(str);
66   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
67   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
68 }
69 
TEST_F(ValidateSSA,IdRedefinedBad)70 TEST_F(ValidateSSA, IdRedefinedBad) {
71   char str[] = R"(
72      OpCapability Shader
73      OpCapability Linkage
74      OpMemoryModel Logical GLSL450
75      OpName %2 "redefined"
76 %1 = OpTypeVoid
77 %2 = OpTypeFunction %1
78 %2 = OpFunction %1 None %2
79 %4 = OpLabel
80      OpReturn
81      OpFunctionEnd
82 )";
83   CompileSuccessfully(str);
84   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
85 }
86 
TEST_F(ValidateSSA,DominateUsageBad)87 TEST_F(ValidateSSA, DominateUsageBad) {
88   char str[] = R"(
89      OpCapability Shader
90      OpCapability Linkage
91      OpMemoryModel Logical GLSL450
92      OpName %1 "not_dominant"
93 %2 = OpTypeFunction %1              ; uses %1 before it's definition
94 %1 = OpTypeVoid
95 )";
96   CompileSuccessfully(str);
97   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
98   EXPECT_THAT(getDiagnosticString(), HasSubstr("not_dominant"));
99 }
100 
TEST_F(ValidateSSA,DominateUsageWithinBlockBad)101 TEST_F(ValidateSSA, DominateUsageWithinBlockBad) {
102   char str[] = R"(
103      OpCapability Shader
104      OpCapability Linkage
105      OpMemoryModel Logical GLSL450
106      OpName %bad "bad"
107 %voidt = OpTypeVoid
108 %funct = OpTypeFunction %voidt
109 %uintt = OpTypeInt 32 0
110 %one   = OpConstant %uintt 1
111 %func  = OpFunction %voidt None %funct
112 %entry = OpLabel
113 %sum   = OpIAdd %uintt %one %bad
114 %bad   = OpCopyObject %uintt %sum
115          OpReturn
116          OpFunctionEnd
117 )";
118   CompileSuccessfully(str);
119   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
120   EXPECT_THAT(getDiagnosticString(),
121               MatchesRegex("ID .\\[%bad\\] has not been defined\n"
122                            "  %8 = OpIAdd %uint %uint_1 %bad\n"));
123 }
124 
TEST_F(ValidateSSA,DominateUsageSameInstructionBad)125 TEST_F(ValidateSSA, DominateUsageSameInstructionBad) {
126   char str[] = R"(
127      OpCapability Shader
128      OpCapability Linkage
129      OpMemoryModel Logical GLSL450
130      OpName %sum "sum"
131 %voidt = OpTypeVoid
132 %funct = OpTypeFunction %voidt
133 %uintt = OpTypeInt 32 0
134 %one   = OpConstant %uintt 1
135 %func  = OpFunction %voidt None %funct
136 %entry = OpLabel
137 %sum   = OpIAdd %uintt %one %sum
138          OpReturn
139          OpFunctionEnd
140 )";
141   CompileSuccessfully(str);
142   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
143   EXPECT_THAT(getDiagnosticString(),
144               MatchesRegex("ID .\\[%sum\\] has not been defined\n"
145                            "  %sum = OpIAdd %uint %uint_1 %sum\n"));
146 }
147 
TEST_F(ValidateSSA,ForwardNameGood)148 TEST_F(ValidateSSA, ForwardNameGood) {
149   char str[] = R"(
150      OpCapability Shader
151      OpCapability Linkage
152      OpMemoryModel Logical GLSL450
153      OpName %3 "main"
154 %1 = OpTypeVoid
155 %2 = OpTypeFunction %1
156 %3 = OpFunction %1 None %2
157 %4 = OpLabel
158      OpReturn
159      OpFunctionEnd
160 )";
161   CompileSuccessfully(str);
162   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
163 }
164 
TEST_F(ValidateSSA,ForwardNameMissingTargetBad)165 TEST_F(ValidateSSA, ForwardNameMissingTargetBad) {
166   char str[] = R"(
167       OpCapability Shader
168       OpCapability Linkage
169       OpMemoryModel Logical GLSL450
170       OpName %5 "main"              ; Target never defined
171 )";
172   CompileSuccessfully(str);
173   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
174   EXPECT_THAT(getDiagnosticString(), HasSubstr("main"));
175 }
176 
TEST_F(ValidateSSA,ForwardMemberNameGood)177 TEST_F(ValidateSSA, ForwardMemberNameGood) {
178   char str[] = R"(
179            OpCapability Shader
180            OpCapability Linkage
181            OpMemoryModel Logical GLSL450
182            OpMemberName %struct 0 "value"
183            OpMemberName %struct 1 "size"
184 %intt   =  OpTypeInt 32 1
185 %uintt  =  OpTypeInt 32 0
186 %struct =  OpTypeStruct %intt %uintt
187 )";
188   CompileSuccessfully(str);
189   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
190 }
191 
TEST_F(ValidateSSA,ForwardMemberNameMissingTargetBad)192 TEST_F(ValidateSSA, ForwardMemberNameMissingTargetBad) {
193   char str[] = R"(
194            OpCapability Shader
195            OpCapability Linkage
196            OpMemoryModel Logical GLSL450
197            OpMemberName %struct 0 "value"
198            OpMemberName %bad 1 "size"     ; Target is not defined
199 %intt   =  OpTypeInt 32 1
200 %uintt  =  OpTypeInt 32 0
201 %struct =  OpTypeStruct %intt %uintt
202 )";
203   CompileSuccessfully(str);
204   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
205   EXPECT_THAT(getDiagnosticString(),
206               HasSubstr("The following forward referenced IDs have not been "
207                         "defined:\n2[%2]"));
208 }
209 
TEST_F(ValidateSSA,ForwardDecorateGood)210 TEST_F(ValidateSSA, ForwardDecorateGood) {
211   char str[] = R"(
212            OpCapability Shader
213            OpCapability Linkage
214            OpMemoryModel Logical GLSL450
215            OpDecorate %var Restrict
216 %intt   =  OpTypeInt 32 1
217 %ptrt   =  OpTypePointer UniformConstant %intt
218 %var    =  OpVariable %ptrt UniformConstant
219 )";
220   CompileSuccessfully(str);
221   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
222 }
223 
TEST_F(ValidateSSA,ForwardDecorateInvalidIDBad)224 TEST_F(ValidateSSA, ForwardDecorateInvalidIDBad) {
225   char str[] = R"(
226            OpCapability Shader
227            OpCapability Linkage
228            OpMemoryModel Logical GLSL450
229            OpName %missing "missing"
230            OpDecorate %missing Restrict        ;Missing ID
231 %voidt  =  OpTypeVoid
232 %intt   =  OpTypeInt 32 1
233 %ptrt   =  OpTypePointer UniformConstant %intt
234 %var    =  OpVariable %ptrt UniformConstant
235 %2      =  OpTypeFunction %voidt
236 %3      =  OpFunction %voidt None %2
237 %4      =  OpLabel
238            OpReturn
239            OpFunctionEnd
240 )";
241   CompileSuccessfully(str);
242   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
243   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
244 }
245 
TEST_F(ValidateSSA,ForwardMemberDecorateGood)246 TEST_F(ValidateSSA, ForwardMemberDecorateGood) {
247   char str[] = R"(
248            OpCapability Shader
249            OpCapability Linkage
250            OpMemoryModel Logical GLSL450
251            OpMemberDecorate %struct 1 RowMajor
252 %intt   =  OpTypeInt 32 1
253 %f32    =  OpTypeFloat 32
254 %vec3   =  OpTypeVector %f32 3
255 %mat33  =  OpTypeMatrix %vec3 3
256 %struct =  OpTypeStruct %intt %mat33
257 )";
258   CompileSuccessfully(str);
259   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
260 }
261 
TEST_F(ValidateSSA,ForwardMemberDecorateInvalidIdBad)262 TEST_F(ValidateSSA, ForwardMemberDecorateInvalidIdBad) {
263   char str[] = R"(
264            OpCapability Shader
265            OpCapability Linkage
266            OpMemoryModel Logical GLSL450
267            OpName %missing "missing"
268            OpMemberDecorate %missing 1 RowMajor ; Target not defined
269 %intt   =  OpTypeInt 32 1
270 %f32    =  OpTypeFloat 32
271 %vec3   =  OpTypeVector %f32 3
272 %mat33  =  OpTypeMatrix %vec3 3
273 %struct =  OpTypeStruct %intt %mat33
274 )";
275   CompileSuccessfully(str);
276   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
277   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
278 }
279 
TEST_F(ValidateSSA,ForwardGroupDecorateGood)280 TEST_F(ValidateSSA, ForwardGroupDecorateGood) {
281   char str[] = R"(
282           OpCapability Shader
283           OpCapability Linkage
284           OpMemoryModel Logical GLSL450
285           OpDecorate %dgrp RowMajor
286 %dgrp   = OpDecorationGroup
287           OpGroupDecorate %dgrp %mat33 %mat44
288 %f32    =  OpTypeFloat 32
289 %vec3   = OpTypeVector %f32 3
290 %vec4   = OpTypeVector %f32 4
291 %mat33  = OpTypeMatrix %vec3 3
292 %mat44  = OpTypeMatrix %vec4 4
293 )";
294   CompileSuccessfully(str);
295   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
296 }
297 
TEST_F(ValidateSSA,ForwardGroupDecorateMissingGroupBad)298 TEST_F(ValidateSSA, ForwardGroupDecorateMissingGroupBad) {
299   char str[] = R"(
300            OpCapability Shader
301            OpCapability Linkage
302            OpMemoryModel Logical GLSL450
303            OpName %missing "missing"
304            OpDecorate %dgrp RowMajor
305 %dgrp   =  OpDecorationGroup
306            OpGroupDecorate %missing %mat33 %mat44 ; Target not defined
307 %intt   =  OpTypeInt 32 1
308 %vec3   =  OpTypeVector %intt 3
309 %vec4   =  OpTypeVector %intt 4
310 %mat33  =  OpTypeMatrix %vec3 3
311 %mat44  =  OpTypeMatrix %vec4 4
312 )";
313   CompileSuccessfully(str);
314   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
315   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
316 }
317 
TEST_F(ValidateSSA,ForwardGroupDecorateMissingTargetBad)318 TEST_F(ValidateSSA, ForwardGroupDecorateMissingTargetBad) {
319   char str[] = R"(
320            OpCapability Shader
321            OpCapability Linkage
322            OpMemoryModel Logical GLSL450
323            OpName %missing "missing"
324            OpDecorate %dgrp RowMajor
325 %dgrp   =  OpDecorationGroup
326            OpGroupDecorate %dgrp %missing %mat44 ; Target not defined
327 %f32    =  OpTypeFloat 32
328 %vec3   =  OpTypeVector %f32 3
329 %vec4   =  OpTypeVector %f32 4
330 %mat33  =  OpTypeMatrix %vec3 3
331 %mat44  =  OpTypeMatrix %vec4 4
332 )";
333   CompileSuccessfully(str);
334   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
335   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
336 }
337 
TEST_F(ValidateSSA,ForwardGroupDecorateDecorationGroupDominateBad)338 TEST_F(ValidateSSA, ForwardGroupDecorateDecorationGroupDominateBad) {
339   char str[] = R"(
340            OpCapability Shader
341            OpCapability Linkage
342            OpMemoryModel Logical GLSL450
343            OpName %dgrp "group"
344            OpDecorate %dgrp RowMajor
345            OpGroupDecorate %dgrp %mat33 %mat44 ; Decoration group does not dominate usage
346 %dgrp   =  OpDecorationGroup
347 %intt   =  OpTypeInt 32 1
348 %vec3   =  OpTypeVector %intt 3
349 %vec4   =  OpTypeVector %intt 4
350 %mat33  =  OpTypeMatrix %vec3 3
351 %mat44  =  OpTypeMatrix %vec4 4
352 )";
353   CompileSuccessfully(str);
354   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
355   EXPECT_THAT(getDiagnosticString(), HasSubstr("group"));
356 }
357 
TEST_F(ValidateSSA,ForwardDecorateInvalidIdBad)358 TEST_F(ValidateSSA, ForwardDecorateInvalidIdBad) {
359   char str[] = R"(
360            OpCapability Shader
361            OpCapability Linkage
362            OpMemoryModel Logical GLSL450
363            OpName %missing "missing"
364            OpDecorate %missing Restrict        ; Missing target
365 %voidt  =  OpTypeVoid
366 %intt   =  OpTypeInt 32 1
367 %ptrt   =  OpTypePointer UniformConstant %intt
368 %var    =  OpVariable %ptrt UniformConstant
369 %2      =  OpTypeFunction %voidt
370 %3      =  OpFunction %voidt None %2
371 %4      =  OpLabel
372            OpReturn
373            OpFunctionEnd
374 )";
375   CompileSuccessfully(str);
376   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
377   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
378 }
379 
TEST_F(ValidateSSA,FunctionCallGood)380 TEST_F(ValidateSSA, FunctionCallGood) {
381   char str[] = R"(
382          OpCapability Shader
383          OpCapability Linkage
384          OpMemoryModel Logical GLSL450
385 %1    =  OpTypeVoid
386 %2    =  OpTypeInt 32 1
387 %3    =  OpTypeInt 32 0
388 %4    =  OpTypeFunction %1
389 %8    =  OpTypeFunction %1 %2 %3
390 %four =  OpConstant %2 4
391 %five =  OpConstant %3 5
392 %9    =  OpFunction %1 None %8
393 %10   =  OpFunctionParameter %2
394 %11   =  OpFunctionParameter %3
395 %12   =  OpLabel
396          OpReturn
397          OpFunctionEnd
398 %5    =  OpFunction %1 None %4
399 %6    =  OpLabel
400 %7    =  OpFunctionCall %1 %9 %four %five
401          OpReturn
402          OpFunctionEnd
403 )";
404   CompileSuccessfully(str);
405   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
406 }
407 
TEST_F(ValidateSSA,ForwardFunctionCallGood)408 TEST_F(ValidateSSA, ForwardFunctionCallGood) {
409   char str[] = R"(
410          OpCapability Shader
411          OpCapability Linkage
412          OpMemoryModel Logical GLSL450
413 %1    =  OpTypeVoid
414 %2    =  OpTypeInt 32 1
415 %3    =  OpTypeInt 32 0
416 %four =  OpConstant %2 4
417 %five =  OpConstant %3 5
418 %8    =  OpTypeFunction %1 %2 %3
419 %4    =  OpTypeFunction %1
420 %5    =  OpFunction %1 None %4
421 %6    =  OpLabel
422 %7    =  OpFunctionCall %1 %9 %four %five
423          OpReturn
424          OpFunctionEnd
425 %9    =  OpFunction %1 None %8
426 %10   =  OpFunctionParameter %2
427 %11   =  OpFunctionParameter %3
428 %12   =  OpLabel
429          OpReturn
430          OpFunctionEnd
431 )";
432   CompileSuccessfully(str);
433   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
434 }
435 
TEST_F(ValidateSSA,ForwardBranchConditionalGood)436 TEST_F(ValidateSSA, ForwardBranchConditionalGood) {
437   char str[] = R"(
438             OpCapability Shader
439             OpCapability Linkage
440             OpMemoryModel Logical GLSL450
441 %voidt  =   OpTypeVoid
442 %boolt  =   OpTypeBool
443 %vfunct =   OpTypeFunction %voidt
444 %true   =   OpConstantTrue %boolt
445 %main   =   OpFunction %voidt None %vfunct
446 %mainl  =   OpLabel
447             OpSelectionMerge %endl None
448             OpBranchConditional %true %truel %falsel
449 %truel  =   OpLabel
450             OpNop
451             OpBranch %endl
452 %falsel =   OpLabel
453             OpNop
454             OpBranch %endl
455 %endl    =  OpLabel
456             OpReturn
457             OpFunctionEnd
458 )";
459   CompileSuccessfully(str);
460   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
461 }
462 
TEST_F(ValidateSSA,ForwardBranchConditionalWithWeightsGood)463 TEST_F(ValidateSSA, ForwardBranchConditionalWithWeightsGood) {
464   char str[] = R"(
465            OpCapability Shader
466            OpCapability Linkage
467            OpMemoryModel Logical GLSL450
468 %voidt  =  OpTypeVoid
469 %boolt  =  OpTypeBool
470 %vfunct =  OpTypeFunction %voidt
471 %true   =  OpConstantTrue %boolt
472 %main   =  OpFunction %voidt None %vfunct
473 %mainl  =  OpLabel
474            OpSelectionMerge %endl None
475            OpBranchConditional %true %truel %falsel 1 9
476 %truel  =  OpLabel
477            OpNop
478            OpBranch %endl
479 %falsel =  OpLabel
480            OpNop
481            OpBranch %endl
482 %endl   =  OpLabel
483            OpReturn
484            OpFunctionEnd
485 )";
486   CompileSuccessfully(str);
487   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
488 }
489 
TEST_F(ValidateSSA,ForwardBranchConditionalNonDominantConditionBad)490 TEST_F(ValidateSSA, ForwardBranchConditionalNonDominantConditionBad) {
491   char str[] = R"(
492            OpCapability Shader
493            OpCapability Linkage
494            OpMemoryModel Logical GLSL450
495            OpName %tcpy "conditional"
496 %voidt  =  OpTypeVoid
497 %boolt  =  OpTypeBool
498 %vfunct =  OpTypeFunction %voidt
499 %true   =  OpConstantTrue %boolt
500 %main   =  OpFunction %voidt None %vfunct
501 %mainl  =  OpLabel
502            OpSelectionMerge %endl None
503            OpBranchConditional %tcpy %truel %falsel ;
504 %truel  =  OpLabel
505            OpNop
506            OpBranch %endl
507 %falsel =  OpLabel
508            OpNop
509            OpBranch %endl
510 %endl   =  OpLabel
511 %tcpy   =  OpCopyObject %boolt %true
512            OpReturn
513            OpFunctionEnd
514 )";
515   CompileSuccessfully(str);
516   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
517   EXPECT_THAT(getDiagnosticString(), HasSubstr("conditional"));
518 }
519 
TEST_F(ValidateSSA,ForwardBranchConditionalMissingTargetBad)520 TEST_F(ValidateSSA, ForwardBranchConditionalMissingTargetBad) {
521   char str[] = R"(
522            OpCapability Shader
523            OpCapability Linkage
524            OpMemoryModel Logical GLSL450
525            OpName %missing "missing"
526 %voidt  =  OpTypeVoid
527 %boolt  =  OpTypeBool
528 %vfunct =  OpTypeFunction %voidt
529 %true   =  OpConstantTrue %boolt
530 %main   =  OpFunction %voidt None %vfunct
531 %mainl  =  OpLabel
532            OpSelectionMerge %endl None
533            OpBranchConditional %true %missing %falsel
534 %truel  =  OpLabel
535            OpNop
536            OpBranch %endl
537 %falsel =  OpLabel
538            OpNop
539            OpBranch %endl
540 %endl   =  OpLabel
541            OpReturn
542            OpFunctionEnd
543 )";
544   CompileSuccessfully(str);
545   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
546   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
547 }
548 
549 // Since Int8 requires the Kernel capability, the signedness of int types may
550 // not be "1".
551 const std::string kHeader = R"(
552 OpCapability Int8
553 OpCapability DeviceEnqueue
554 OpCapability Linkage
555 OpMemoryModel Logical OpenCL
556 )";
557 
558 const std::string kBasicTypes = R"(
559 %voidt  =  OpTypeVoid
560 %boolt  =  OpTypeBool
561 %int8t  =  OpTypeInt 8 0
562 %uintt  =  OpTypeInt 32 0
563 %vfunct =  OpTypeFunction %voidt
564 %intptrt = OpTypePointer UniformConstant %uintt
565 %zero      = OpConstant %uintt 0
566 %one       = OpConstant %uintt 1
567 %ten       = OpConstant %uintt 10
568 %false     = OpConstantFalse %boolt
569 )";
570 
571 const std::string kKernelTypesAndConstants = R"(
572 %queuet  = OpTypeQueue
573 
574 %three   = OpConstant %uintt 3
575 %arr3t   = OpTypeArray %uintt %three
576 %ndt     = OpTypeStruct %uintt %arr3t %arr3t %arr3t
577 
578 %eventt  = OpTypeEvent
579 
580 %offset = OpConstant %uintt 0
581 %local  = OpConstant %uintt 1
582 %gl     = OpConstant %uintt 1
583 
584 %nevent = OpConstant %uintt 0
585 %event  = OpConstantNull %eventt
586 
587 %firstp = OpConstant %int8t 0
588 %psize  = OpConstant %uintt 0
589 %palign = OpConstant %uintt 32
590 %lsize  = OpConstant %uintt 1
591 %flags  = OpConstant %uintt 0 ; NoWait
592 
593 %kfunct = OpTypeFunction %voidt %intptrt
594 )";
595 
596 const std::string kKernelSetup = R"(
597 %dqueue = OpGetDefaultQueue %queuet
598 %ndval  = OpBuildNDRange %ndt %gl %local %offset
599 %revent = OpUndef %eventt
600 
601 )";
602 
603 const std::string kKernelDefinition = R"(
604 %kfunc  = OpFunction %voidt None %kfunct
605 %iparam = OpFunctionParameter %intptrt
606 %kfuncl = OpLabel
607           OpNop
608           OpReturn
609           OpFunctionEnd
610 )";
611 
TEST_F(ValidateSSA,EnqueueKernelGood)612 TEST_F(ValidateSSA, EnqueueKernelGood) {
613   std::string str = kHeader + kBasicTypes + kKernelTypesAndConstants +
614                     kKernelDefinition + R"(
615                 %main   = OpFunction %voidt None %vfunct
616                 %mainl  = OpLabel
617                 )" + kKernelSetup + R"(
618                 %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
619                                         %event %revent %kfunc %firstp %psize
620                                         %palign %lsize
621                           OpReturn
622                           OpFunctionEnd
623                  )";
624   CompileSuccessfully(str);
625   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
626 }
627 
TEST_F(ValidateSSA,ForwardEnqueueKernelGood)628 TEST_F(ValidateSSA, ForwardEnqueueKernelGood) {
629   std::string str = kHeader + kBasicTypes + kKernelTypesAndConstants + R"(
630                 %main   = OpFunction %voidt None %vfunct
631                 %mainl  = OpLabel
632                 )" +
633                     kKernelSetup + R"(
634                 %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
635                                         %event %revent %kfunc %firstp %psize
636                                         %palign %lsize
637                          OpReturn
638                          OpFunctionEnd
639                  )" + kKernelDefinition;
640   CompileSuccessfully(str);
641   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
642 }
643 
TEST_F(ValidateSSA,EnqueueMissingFunctionBad)644 TEST_F(ValidateSSA, EnqueueMissingFunctionBad) {
645   std::string str = kHeader + "OpName %kfunc \"kfunc\"" + kBasicTypes +
646                     kKernelTypesAndConstants + R"(
647                 %main   = OpFunction %voidt None %vfunct
648                 %mainl  = OpLabel
649                 )" + kKernelSetup + R"(
650                 %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
651                                         %event %revent %kfunc %firstp %psize
652                                         %palign %lsize
653                          OpReturn
654                          OpFunctionEnd
655                  )";
656   CompileSuccessfully(str);
657   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
658   EXPECT_THAT(getDiagnosticString(), HasSubstr("kfunc"));
659 }
660 
forwardKernelNonDominantParameterBaseCode(std::string name=std::string ())661 std::string forwardKernelNonDominantParameterBaseCode(
662     std::string name = std::string()) {
663   std::string op_name;
664   if (name.empty()) {
665     op_name = "";
666   } else {
667     op_name = "\nOpName %" + name + " \"" + name + "\"\n";
668   }
669   std::string out = kHeader + op_name + kBasicTypes + kKernelTypesAndConstants +
670                     kKernelDefinition +
671                     R"(
672                 %main   = OpFunction %voidt None %vfunct
673                 %mainl  = OpLabel
674                 )" + kKernelSetup;
675   return out;
676 }
677 
TEST_F(ValidateSSA,ForwardEnqueueKernelMissingParameter1Bad)678 TEST_F(ValidateSSA, ForwardEnqueueKernelMissingParameter1Bad) {
679   std::string str = forwardKernelNonDominantParameterBaseCode("missing") + R"(
680                 %err    = OpEnqueueKernel %missing %dqueue %flags %ndval
681                                         %nevent %event %revent %kfunc %firstp
682                                         %psize %palign %lsize
683                           OpReturn
684                           OpFunctionEnd
685                 )";
686   CompileSuccessfully(str);
687   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
688   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
689 }
690 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter2Bad)691 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter2Bad) {
692   std::string str = forwardKernelNonDominantParameterBaseCode("dqueue2") + R"(
693                 %err     = OpEnqueueKernel %uintt %dqueue2 %flags %ndval
694                                             %nevent %event %revent %kfunc
695                                             %firstp %psize %palign %lsize
696                 %dqueue2 = OpGetDefaultQueue %queuet
697                            OpReturn
698                            OpFunctionEnd
699                 )";
700   CompileSuccessfully(str);
701   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
702   EXPECT_THAT(getDiagnosticString(), HasSubstr("dqueue2"));
703 }
704 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter3Bad)705 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter3Bad) {
706   std::string str = forwardKernelNonDominantParameterBaseCode("ndval2") + R"(
707                 %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval2
708                                         %nevent %event %revent %kfunc %firstp
709                                         %psize %palign %lsize
710                 %ndval2  = OpBuildNDRange %ndt %gl %local %offset
711                           OpReturn
712                           OpFunctionEnd
713                 )";
714   CompileSuccessfully(str);
715   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
716   EXPECT_THAT(getDiagnosticString(), HasSubstr("ndval2"));
717 }
718 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter4Bad)719 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter4Bad) {
720   std::string str = forwardKernelNonDominantParameterBaseCode("nevent2") + R"(
721               %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent2
722                                         %event %revent %kfunc %firstp %psize
723                                         %palign %lsize
724               %nevent2 = OpCopyObject %uintt %nevent
725                         OpReturn
726                         OpFunctionEnd
727               )";
728   CompileSuccessfully(str);
729   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
730   EXPECT_THAT(getDiagnosticString(), HasSubstr("nevent2"));
731 }
732 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter5Bad)733 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter5Bad) {
734   std::string str = forwardKernelNonDominantParameterBaseCode("event2") + R"(
735               %err     = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
736                                         %event2 %revent %kfunc %firstp %psize
737                                         %palign %lsize
738               %event2  = OpCopyObject %eventt %event
739                          OpReturn
740                          OpFunctionEnd
741               )";
742   CompileSuccessfully(str);
743   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
744   EXPECT_THAT(getDiagnosticString(), HasSubstr("event2"));
745 }
746 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter6Bad)747 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter6Bad) {
748   std::string str = forwardKernelNonDominantParameterBaseCode("revent2") + R"(
749               %err     = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
750                                         %event %revent2 %kfunc %firstp %psize
751                                         %palign %lsize
752               %revent2 = OpCopyObject %eventt %revent
753                          OpReturn
754                          OpFunctionEnd
755               )";
756   CompileSuccessfully(str);
757   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
758   EXPECT_THAT(getDiagnosticString(), HasSubstr("revent2"));
759 }
760 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter8Bad)761 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter8Bad) {
762   std::string str = forwardKernelNonDominantParameterBaseCode("firstp2") + R"(
763               %err     = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
764                                         %event %revent %kfunc %firstp2 %psize
765                                         %palign %lsize
766               %firstp2 = OpCopyObject %int8t %firstp
767                          OpReturn
768                          OpFunctionEnd
769               )";
770   CompileSuccessfully(str);
771   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
772   EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2"));
773 }
774 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter9Bad)775 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter9Bad) {
776   std::string str = forwardKernelNonDominantParameterBaseCode("psize2") + R"(
777               %err    = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
778                                         %event %revent %kfunc %firstp %psize2
779                                         %palign %lsize
780               %psize2 = OpCopyObject %uintt %psize
781                         OpReturn
782                         OpFunctionEnd
783               )";
784   CompileSuccessfully(str);
785   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
786   EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2"));
787 }
788 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter10Bad)789 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter10Bad) {
790   std::string str = forwardKernelNonDominantParameterBaseCode("palign2") + R"(
791               %err     = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
792                                         %event %revent %kfunc %firstp %psize
793                                         %palign2 %lsize
794               %palign2 = OpCopyObject %uintt %palign
795                         OpReturn
796                         OpFunctionEnd
797               )";
798   CompileSuccessfully(str);
799   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
800   EXPECT_THAT(getDiagnosticString(), HasSubstr("palign2"));
801 }
802 
TEST_F(ValidateSSA,ForwardEnqueueKernelNonDominantParameter11Bad)803 TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter11Bad) {
804   std::string str = forwardKernelNonDominantParameterBaseCode("lsize2") + R"(
805               %err     = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
806                                         %event %revent %kfunc %firstp %psize
807                                         %palign %lsize2
808               %lsize2  = OpCopyObject %uintt %lsize
809                          OpReturn
810                          OpFunctionEnd
811               )";
812 
813   CompileSuccessfully(str);
814   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
815   EXPECT_THAT(getDiagnosticString(), HasSubstr("lsize2"));
816 }
817 
818 static const bool kWithNDrange = true;
819 static const bool kNoNDrange = false;
820 std::pair<std::string, bool> cases[] = {
821     {"OpGetKernelNDrangeSubGroupCount", kWithNDrange},
822     {"OpGetKernelNDrangeMaxSubGroupSize", kWithNDrange},
823     {"OpGetKernelWorkGroupSize", kNoNDrange},
824     {"OpGetKernelPreferredWorkGroupSizeMultiple", kNoNDrange}};
825 
826 INSTANTIATE_TEST_CASE_P(KernelArgs, ValidateSSA, ::testing::ValuesIn(cases), );
827 
828 static const std::string return_instructions = R"(
829   OpReturn
830   OpFunctionEnd
831 )";
832 
TEST_P(ValidateSSA,GetKernelGood)833 TEST_P(ValidateSSA, GetKernelGood) {
834   std::string instruction = GetParam().first;
835   bool with_ndrange = GetParam().second;
836   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
837 
838   std::stringstream ss;
839   // clang-format off
840   ss << forwardKernelNonDominantParameterBaseCode() + " %numsg = "
841      << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign"
842      << return_instructions;
843   // clang-format on
844 
845   CompileSuccessfully(ss.str());
846   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
847 }
848 
TEST_P(ValidateSSA,ForwardGetKernelGood)849 TEST_P(ValidateSSA, ForwardGetKernelGood) {
850   std::string instruction = GetParam().first;
851   bool with_ndrange = GetParam().second;
852   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
853 
854   // clang-format off
855   std::string str = kHeader + kBasicTypes + kKernelTypesAndConstants +
856                R"(
857             %main    = OpFunction %voidt None %vfunct
858             %mainl   = OpLabel
859                 )"
860             + kKernelSetup + " %numsg = "
861             + instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign"
862             + return_instructions + kKernelDefinition;
863   // clang-format on
864 
865   CompileSuccessfully(str);
866   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
867 }
868 
TEST_P(ValidateSSA,ForwardGetKernelMissingDefinitionBad)869 TEST_P(ValidateSSA, ForwardGetKernelMissingDefinitionBad) {
870   std::string instruction = GetParam().first;
871   bool with_ndrange = GetParam().second;
872   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
873 
874   std::stringstream ss;
875   // clang-format off
876   ss << forwardKernelNonDominantParameterBaseCode("missing") + " %numsg = "
877      << instruction + " %uintt" + ndrange_param + "%missing %firstp %psize %palign"
878      << return_instructions;
879   // clang-format on
880 
881   CompileSuccessfully(ss.str());
882   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
883   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
884 }
885 
TEST_P(ValidateSSA,ForwardGetKernelNDrangeSubGroupCountMissingParameter1Bad)886 TEST_P(ValidateSSA, ForwardGetKernelNDrangeSubGroupCountMissingParameter1Bad) {
887   std::string instruction = GetParam().first;
888   bool with_ndrange = GetParam().second;
889   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
890 
891   std::stringstream ss;
892   // clang-format off
893   ss << forwardKernelNonDominantParameterBaseCode("missing") + " %numsg = "
894      << instruction + " %missing" + ndrange_param + "%kfunc %firstp %psize %palign"
895      << return_instructions;
896   // clang-format on
897 
898   CompileSuccessfully(ss.str());
899   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
900   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
901 }
902 
TEST_P(ValidateSSA,ForwardGetKernelNDrangeSubGroupCountNonDominantParameter2Bad)903 TEST_P(ValidateSSA,
904        ForwardGetKernelNDrangeSubGroupCountNonDominantParameter2Bad) {
905   std::string instruction = GetParam().first;
906   bool with_ndrange = GetParam().second;
907   std::string ndrange_param = with_ndrange ? " %ndval2 " : " ";
908 
909   std::stringstream ss;
910   // clang-format off
911   ss << forwardKernelNonDominantParameterBaseCode("ndval2") + " %numsg = "
912      << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign"
913      << "\n %ndval2  = OpBuildNDRange %ndt %gl %local %offset"
914      << return_instructions;
915   // clang-format on
916 
917   if (GetParam().second) {
918     CompileSuccessfully(ss.str());
919     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
920     EXPECT_THAT(getDiagnosticString(), HasSubstr("ndval2"));
921   }
922 }
923 
TEST_P(ValidateSSA,ForwardGetKernelNDrangeSubGroupCountNonDominantParameter4Bad)924 TEST_P(ValidateSSA,
925        ForwardGetKernelNDrangeSubGroupCountNonDominantParameter4Bad) {
926   std::string instruction = GetParam().first;
927   bool with_ndrange = GetParam().second;
928   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
929 
930   std::stringstream ss;
931   // clang-format off
932   ss << forwardKernelNonDominantParameterBaseCode("firstp2") + " %numsg = "
933      << instruction + " %uintt" + ndrange_param + "%kfunc %firstp2 %psize %palign"
934      << "\n %firstp2 = OpCopyObject %int8t %firstp"
935      << return_instructions;
936   // clang-format on
937 
938   CompileSuccessfully(ss.str());
939   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
940   EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2"));
941 }
942 
TEST_P(ValidateSSA,ForwardGetKernelNDrangeSubGroupCountNonDominantParameter5Bad)943 TEST_P(ValidateSSA,
944        ForwardGetKernelNDrangeSubGroupCountNonDominantParameter5Bad) {
945   std::string instruction = GetParam().first;
946   bool with_ndrange = GetParam().second;
947   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
948 
949   std::stringstream ss;
950   // clang-format off
951   ss << forwardKernelNonDominantParameterBaseCode("psize2") + " %numsg = "
952      << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize2 %palign"
953      << "\n %psize2  = OpCopyObject %uintt %psize"
954      << return_instructions;
955   // clang-format on
956 
957   CompileSuccessfully(ss.str());
958   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
959   EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2"));
960 }
961 
TEST_P(ValidateSSA,ForwardGetKernelNDrangeSubGroupCountNonDominantParameter6Bad)962 TEST_P(ValidateSSA,
963        ForwardGetKernelNDrangeSubGroupCountNonDominantParameter6Bad) {
964   std::string instruction = GetParam().first;
965   bool with_ndrange = GetParam().second;
966   std::string ndrange_param = with_ndrange ? " %ndval " : " ";
967 
968   std::stringstream ss;
969   // clang-format off
970   ss << forwardKernelNonDominantParameterBaseCode("palign2") + " %numsg = "
971      << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign2"
972      << "\n %palign2 = OpCopyObject %uintt %palign"
973      << return_instructions;
974   // clang-format on
975 
976   if (GetParam().second) {
977     CompileSuccessfully(ss.str());
978     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
979     EXPECT_THAT(getDiagnosticString(), HasSubstr("palign2"));
980   }
981 }
982 
TEST_F(ValidateSSA,PhiGood)983 TEST_F(ValidateSSA, PhiGood) {
984   std::string str = kHeader + kBasicTypes +
985                     R"(
986 %func      = OpFunction %voidt None %vfunct
987 %preheader = OpLabel
988 %init      = OpCopyObject %uintt %zero
989              OpBranch %loop
990 %loop      = OpLabel
991 %i         = OpPhi %uintt %init %preheader %loopi %loop
992 %loopi     = OpIAdd %uintt %i %one
993              OpNop
994 %cond      = OpSLessThan %boolt %i %ten
995              OpLoopMerge %endl %loop None
996              OpBranchConditional %cond %loop %endl
997 %endl      = OpLabel
998              OpReturn
999              OpFunctionEnd
1000 )";
1001 
1002   CompileSuccessfully(str);
1003   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1004 }
1005 
TEST_F(ValidateSSA,PhiMissingTypeBad)1006 TEST_F(ValidateSSA, PhiMissingTypeBad) {
1007   std::string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
1008                     R"(
1009 %func      = OpFunction %voidt None %vfunct
1010 %preheader = OpLabel
1011 %init      = OpCopyObject %uintt %zero
1012              OpBranch %loop
1013 %loop      = OpLabel
1014 %i         = OpPhi %missing %init %preheader %loopi %loop
1015 %loopi     = OpIAdd %uintt %i %one
1016              OpNop
1017 %cond      = OpSLessThan %boolt %i %ten
1018              OpLoopMerge %endl %loop None
1019              OpBranchConditional %cond %loop %endl
1020 %endl      = OpLabel
1021              OpReturn
1022              OpFunctionEnd
1023 )";
1024 
1025   CompileSuccessfully(str);
1026   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1027   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
1028 }
1029 
TEST_F(ValidateSSA,PhiMissingIdBad)1030 TEST_F(ValidateSSA, PhiMissingIdBad) {
1031   std::string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
1032                     R"(
1033 %func      = OpFunction %voidt None %vfunct
1034 %preheader = OpLabel
1035 %init      = OpCopyObject %uintt %zero
1036              OpBranch %loop
1037 %loop      = OpLabel
1038 %i         = OpPhi %uintt %missing %preheader %loopi %loop
1039 %loopi     = OpIAdd %uintt %i %one
1040              OpNop
1041 %cond      = OpSLessThan %boolt %i %ten
1042              OpLoopMerge %endl %loop None
1043              OpBranchConditional %cond %loop %endl
1044 %endl      = OpLabel
1045              OpReturn
1046              OpFunctionEnd
1047 )";
1048 
1049   CompileSuccessfully(str);
1050   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1051   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
1052 }
1053 
TEST_F(ValidateSSA,PhiMissingLabelBad)1054 TEST_F(ValidateSSA, PhiMissingLabelBad) {
1055   std::string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
1056                     R"(
1057 %func      = OpFunction %voidt None %vfunct
1058 %preheader = OpLabel
1059 %init      = OpCopyObject %uintt %zero
1060              OpBranch %loop
1061 %loop      = OpLabel
1062 %i         = OpPhi %uintt %init %missing %loopi %loop
1063 %loopi     = OpIAdd %uintt %i %one
1064              OpNop
1065 %cond      = OpSLessThan %boolt %i %ten
1066              OpLoopMerge %endl %loop None
1067              OpBranchConditional %cond %loop %endl
1068 %endl      = OpLabel
1069              OpReturn
1070              OpFunctionEnd
1071 )";
1072 
1073   CompileSuccessfully(str);
1074   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1075   EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
1076 }
1077 
TEST_F(ValidateSSA,IdDominatesItsUseGood)1078 TEST_F(ValidateSSA, IdDominatesItsUseGood) {
1079   std::string str = kHeader + kBasicTypes +
1080                     R"(
1081 %func      = OpFunction %voidt None %vfunct
1082 %entry     = OpLabel
1083 %cond      = OpSLessThan %boolt %one %ten
1084 %eleven    = OpIAdd %uintt %one %ten
1085              OpSelectionMerge %merge None
1086              OpBranchConditional %cond %t %f
1087 %t         = OpLabel
1088 %twelve    = OpIAdd %uintt %eleven %one
1089              OpBranch %merge
1090 %f         = OpLabel
1091 %twentytwo = OpIAdd %uintt %eleven %ten
1092              OpBranch %merge
1093 %merge     = OpLabel
1094              OpReturn
1095              OpFunctionEnd
1096 )";
1097 
1098   CompileSuccessfully(str);
1099   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1100 }
1101 
TEST_F(ValidateSSA,IdDoesNotDominateItsUseBad)1102 TEST_F(ValidateSSA, IdDoesNotDominateItsUseBad) {
1103   std::string str = kHeader +
1104                     "OpName %eleven \"eleven\"\n"
1105                     "OpName %true_block \"true_block\"\n"
1106                     "OpName %false_block \"false_block\"" +
1107                     kBasicTypes +
1108                     R"(
1109 %func        = OpFunction %voidt None %vfunct
1110 %entry       = OpLabel
1111 %cond        = OpSLessThan %boolt %one %ten
1112                OpSelectionMerge %merge None
1113                OpBranchConditional %cond %true_block %false_block
1114 %true_block  = OpLabel
1115 %eleven      = OpIAdd %uintt %one %ten
1116 %twelve      = OpIAdd %uintt %eleven %one
1117                OpBranch %merge
1118 %false_block = OpLabel
1119 %twentytwo   = OpIAdd %uintt %eleven %ten
1120                OpBranch %merge
1121 %merge       = OpLabel
1122                OpReturn
1123                OpFunctionEnd
1124 )";
1125   CompileSuccessfully(str);
1126   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1127   EXPECT_THAT(
1128       getDiagnosticString(),
1129       MatchesRegex("ID .\\[%eleven\\] defined in block .\\[%true_block\\] "
1130                    "does not dominate its use in block .\\[%false_block\\]\n"
1131                    "  %false_block = OpLabel\n"));
1132 }
1133 
TEST_F(ValidateSSA,PhiUseDoesntDominateDefinitionGood)1134 TEST_F(ValidateSSA, PhiUseDoesntDominateDefinitionGood) {
1135   std::string str = kHeader + kBasicTypes +
1136                     R"(
1137 %funcintptrt = OpTypePointer Function %uintt
1138 %func        = OpFunction %voidt None %vfunct
1139 %entry       = OpLabel
1140 %var_one     = OpVariable %funcintptrt Function %one
1141 %one_val     = OpLoad %uintt %var_one
1142                OpBranch %loop
1143 %loop        = OpLabel
1144 %i           = OpPhi %uintt %one_val %entry %inew %cont
1145 %cond        = OpSLessThan %boolt %one %ten
1146                OpLoopMerge %merge %cont None
1147                OpBranchConditional %cond %body %merge
1148 %body        = OpLabel
1149                OpBranch %cont
1150 %cont        = OpLabel
1151 %inew        = OpIAdd %uintt %i %one
1152                OpBranch %loop
1153 %merge       = OpLabel
1154                OpReturn
1155                OpFunctionEnd
1156 )";
1157 
1158   CompileSuccessfully(str);
1159   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1160 }
1161 
TEST_F(ValidateSSA,PhiUseDoesntDominateUseOfPhiOperandUsedBeforeDefinitionBad)1162 TEST_F(ValidateSSA,
1163        PhiUseDoesntDominateUseOfPhiOperandUsedBeforeDefinitionBad) {
1164   std::string str = kHeader + "OpName %inew \"inew\"" + kBasicTypes +
1165                     R"(
1166 %func        = OpFunction %voidt None %vfunct
1167 %entry       = OpLabel
1168 %var_one     = OpVariable %intptrt Function %one
1169 %one_val     = OpLoad %uintt %var_one
1170                OpBranch %loop
1171 %loop        = OpLabel
1172 %i           = OpPhi %uintt %one_val %entry %inew %cont
1173 %bad         = OpIAdd %uintt %inew %one
1174 %cond        = OpSLessThan %boolt %one %ten
1175                OpLoopMerge %merge %cont None
1176                OpBranchConditional %cond %body %merge
1177 %body        = OpLabel
1178                OpBranch %cont
1179 %cont        = OpLabel
1180 %inew        = OpIAdd %uintt %i %one
1181                OpBranch %loop
1182 %merge       = OpLabel
1183                OpReturn
1184                OpFunctionEnd
1185 )";
1186 
1187   CompileSuccessfully(str);
1188   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1189   EXPECT_THAT(getDiagnosticString(),
1190               MatchesRegex("ID .\\[%inew\\] has not been defined\n"
1191                            "  %19 = OpIAdd %uint %inew %uint_1\n"));
1192 }
1193 
TEST_F(ValidateSSA,PhiUseMayComeFromNonDominatingBlockGood)1194 TEST_F(ValidateSSA, PhiUseMayComeFromNonDominatingBlockGood) {
1195   std::string str = kHeader + "OpName %if_true \"if_true\"\n" +
1196                     "OpName %exit \"exit\"\n" + "OpName %copy \"copy\"\n" +
1197                     kBasicTypes +
1198                     R"(
1199 %func        = OpFunction %voidt None %vfunct
1200 %entry       = OpLabel
1201                OpBranchConditional %false %if_true %exit
1202 
1203 %if_true     = OpLabel
1204 %copy        = OpCopyObject %boolt %false
1205                OpBranch %exit
1206 
1207 ; The use of %copy here is ok, even though it was defined
1208 ; in a block that does not dominate %exit.  That's the point
1209 ; of an OpPhi.
1210 %exit        = OpLabel
1211 %value       = OpPhi %boolt %false %entry %copy %if_true
1212                OpReturn
1213                OpFunctionEnd
1214 )";
1215 
1216   CompileSuccessfully(str);
1217   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
1218 }
1219 
TEST_F(ValidateSSA,PhiUsesItsOwnDefinitionGood)1220 TEST_F(ValidateSSA, PhiUsesItsOwnDefinitionGood) {
1221   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/415
1222   //
1223   // Non-phi instructions can't use their own definitions, as
1224   // already checked in test DominateUsageSameInstructionBad.
1225   std::string str = kHeader + "OpName %loop \"loop\"\n" +
1226                     "OpName %value \"value\"\n" + kBasicTypes +
1227                     R"(
1228 %func        = OpFunction %voidt None %vfunct
1229 %entry       = OpLabel
1230                OpBranch %loop
1231 
1232 %loop        = OpLabel
1233 %value       = OpPhi %boolt %false %entry %value %loop
1234                OpBranch %loop
1235 
1236                OpFunctionEnd
1237 )";
1238 
1239   CompileSuccessfully(str);
1240   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
1241 }
1242 
TEST_F(ValidateSSA,PhiVariableDefNotDominatedByParentBlockBad)1243 TEST_F(ValidateSSA, PhiVariableDefNotDominatedByParentBlockBad) {
1244   std::string str = kHeader + "OpName %if_true \"if_true\"\n" +
1245                     "OpName %if_false \"if_false\"\n" +
1246                     "OpName %exit \"exit\"\n" + "OpName %value \"phi\"\n" +
1247                     "OpName %true_copy \"true_copy\"\n" +
1248                     "OpName %false_copy \"false_copy\"\n" + kBasicTypes +
1249                     R"(
1250 %func        = OpFunction %voidt None %vfunct
1251 %entry       = OpLabel
1252                OpBranchConditional %false %if_true %if_false
1253 
1254 %if_true     = OpLabel
1255 %true_copy   = OpCopyObject %boolt %false
1256                OpBranch %exit
1257 
1258 %if_false    = OpLabel
1259 %false_copy  = OpCopyObject %boolt %false
1260                OpBranch %exit
1261 
1262 ; The (variable,Id) pairs are swapped.
1263 %exit        = OpLabel
1264 %value       = OpPhi %boolt %true_copy %if_false %false_copy %if_true
1265                OpReturn
1266                OpFunctionEnd
1267 )";
1268 
1269   CompileSuccessfully(str);
1270   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1271   EXPECT_THAT(
1272       getDiagnosticString(),
1273       MatchesRegex("In OpPhi instruction .\\[%phi\\], ID .\\[%true_copy\\] "
1274                    "definition does not dominate its parent .\\[%if_false\\]\n"
1275                    "  %phi = OpPhi %bool %true_copy %if_false %false_copy "
1276                    "%if_true\n"));
1277 }
1278 
TEST_F(ValidateSSA,PhiVariableDefDominatesButNotDefinedInParentBlock)1279 TEST_F(ValidateSSA, PhiVariableDefDominatesButNotDefinedInParentBlock) {
1280   std::string str = kHeader + "OpName %if_true \"if_true\"\n" + kBasicTypes +
1281                     R"(
1282 %func        = OpFunction %voidt None %vfunct
1283 %entry       = OpLabel
1284                OpBranchConditional %false %if_true %if_false
1285 
1286 %if_true     = OpLabel
1287 %true_copy   = OpCopyObject %boolt %false
1288                OpBranch %if_tnext
1289 %if_tnext    = OpLabel
1290                OpBranch %exit
1291 
1292 %if_false    = OpLabel
1293 %false_copy  = OpCopyObject %boolt %false
1294                OpBranch %if_fnext
1295 %if_fnext    = OpLabel
1296                OpBranch %exit
1297 
1298 %exit        = OpLabel
1299 %value       = OpPhi %boolt %true_copy %if_tnext %false_copy %if_fnext
1300                OpReturn
1301                OpFunctionEnd
1302 )";
1303 
1304   CompileSuccessfully(str);
1305   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1306 }
1307 
TEST_F(ValidateSSA,DominanceCheckIgnoresUsesInUnreachableBlocksDefInBlockGood)1308 TEST_F(ValidateSSA,
1309        DominanceCheckIgnoresUsesInUnreachableBlocksDefInBlockGood) {
1310   std::string str = kHeader + kBasicTypes +
1311                     R"(
1312 %func        = OpFunction %voidt None %vfunct
1313 %entry       = OpLabel
1314 %def         = OpCopyObject %boolt %false
1315                OpReturn
1316 
1317 %unreach     = OpLabel
1318 %use         = OpCopyObject %boolt %def
1319                OpReturn
1320                OpFunctionEnd
1321 )";
1322 
1323   CompileSuccessfully(str);
1324   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
1325 }
1326 
TEST_F(ValidateSSA,PhiVariableUnreachableDefNotInParentBlock)1327 TEST_F(ValidateSSA, PhiVariableUnreachableDefNotInParentBlock) {
1328   std::string str = kHeader + "OpName %unreachable \"unreachable\"\n" +
1329                     kBasicTypes +
1330                     R"(
1331 %func        = OpFunction %voidt None %vfunct
1332 %entry       = OpLabel
1333                OpBranch %if_false
1334 
1335 %unreachable = OpLabel
1336 %copy        = OpCopyObject %boolt %false
1337                OpBranch %if_tnext
1338 %if_tnext    = OpLabel
1339                OpBranch %exit
1340 
1341 %if_false    = OpLabel
1342 %false_copy  = OpCopyObject %boolt %false
1343                OpBranch %if_fnext
1344 %if_fnext    = OpLabel
1345                OpBranch %exit
1346 
1347 %exit        = OpLabel
1348 %value       = OpPhi %boolt %copy %if_tnext %false_copy %if_fnext
1349                OpReturn
1350                OpFunctionEnd
1351 )";
1352 
1353   CompileSuccessfully(str);
1354   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1355 }
1356 
TEST_F(ValidateSSA,DominanceCheckIgnoresUsesInUnreachableBlocksDefIsParamGood)1357 TEST_F(ValidateSSA,
1358        DominanceCheckIgnoresUsesInUnreachableBlocksDefIsParamGood) {
1359   std::string str = kHeader + kBasicTypes +
1360                     R"(
1361 %void_fn_int = OpTypeFunction %voidt %uintt
1362 %func        = OpFunction %voidt None %void_fn_int
1363 %int_param   = OpFunctionParameter %uintt
1364 %entry       = OpLabel
1365                OpReturn
1366 
1367 %unreach     = OpLabel
1368 %use         = OpCopyObject %uintt %int_param
1369                OpReturn
1370                OpFunctionEnd
1371 )";
1372 
1373   CompileSuccessfully(str);
1374   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
1375 }
1376 
TEST_F(ValidateSSA,UseFunctionParameterFromOtherFunctionBad)1377 TEST_F(ValidateSSA, UseFunctionParameterFromOtherFunctionBad) {
1378   std::string str = kHeader +
1379                     "OpName %first \"first\"\n"
1380                     "OpName %func \"func\"\n" +
1381                     "OpName %func2 \"func2\"\n" + kBasicTypes +
1382                     R"(
1383 %viifunct  = OpTypeFunction %voidt %uintt %uintt
1384 %func      = OpFunction %voidt None %viifunct
1385 %first     = OpFunctionParameter %uintt
1386 %second    = OpFunctionParameter %uintt
1387              OpFunctionEnd
1388 %func2     = OpFunction %voidt None %viifunct
1389 %first2    = OpFunctionParameter %uintt
1390 %second2   = OpFunctionParameter %uintt
1391 %entry2    = OpLabel
1392 %baduse    = OpIAdd %uintt %first %first2
1393              OpReturn
1394              OpFunctionEnd
1395 )";
1396 
1397   CompileSuccessfully(str);
1398   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1399   EXPECT_THAT(
1400       getDiagnosticString(),
1401       MatchesRegex("ID .\\[%first\\] used in function .\\[%func2\\] is used "
1402                    "outside of it's defining function .\\[%func\\]\n"
1403                    "  %func = OpFunction %void None %14\n"));
1404 }
1405 
TEST_F(ValidateSSA,TypeForwardPointerForwardReference)1406 TEST_F(ValidateSSA, TypeForwardPointerForwardReference) {
1407   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/429
1408   //
1409   // ForwardPointers can references instructions that have not been defined
1410   std::string str = R"(
1411                OpCapability Kernel
1412                OpCapability Addresses
1413                OpCapability Linkage
1414                OpMemoryModel Logical OpenCL
1415                OpName %intptrt "intptrt"
1416                OpTypeForwardPointer %intptrt UniformConstant
1417        %uint = OpTypeInt 32 0
1418     %intptrt = OpTypePointer UniformConstant %uint
1419 )";
1420 
1421   CompileSuccessfully(str);
1422   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1423 }
1424 
TEST_F(ValidateSSA,TypeStructForwardReference)1425 TEST_F(ValidateSSA, TypeStructForwardReference) {
1426   std::string str = R"(
1427                OpCapability Kernel
1428                OpCapability Addresses
1429                OpCapability Linkage
1430                OpMemoryModel Logical OpenCL
1431                OpName %structptr "structptr"
1432                OpTypeForwardPointer %structptr UniformConstant
1433        %uint = OpTypeInt 32 0
1434    %structt1 = OpTypeStruct %structptr %uint
1435    %structt2 = OpTypeStruct %uint %structptr
1436    %structt3 = OpTypeStruct %uint %uint %structptr
1437    %structt4 = OpTypeStruct %uint %uint %uint %structptr
1438   %structptr = OpTypePointer UniformConstant %structt1
1439 )";
1440 
1441   CompileSuccessfully(str);
1442   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1443 }
1444 
1445 // TODO(umar): OpGroupMemberDecorate
1446 
1447 }  // namespace
1448 }  // namespace val
1449 }  // namespace spvtools
1450