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