1 // Copyright (c) 2019 Google LLC
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 #include "test/opt/assembly_builder.h"
16 #include "test/opt/pass_fixture.h"
17 #include "test/opt/pass_utils.h"
18 
19 namespace spvtools {
20 namespace opt {
21 namespace {
22 
23 using WrapOpKillTest = PassTest<::testing::Test>;
24 
TEST_F(WrapOpKillTest,SingleOpKill)25 TEST_F(WrapOpKillTest, SingleOpKill) {
26   const std::string text = R"(
27 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
28 ; CHECK: [[main]] = OpFunction
29 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
30 ; CHECK: [[orig_kill]] = OpFunction
31 ; CHECK-NEXT: OpLabel
32 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
33 ; CHECK-NEXT: OpReturn
34 ; CHECK: [[new_kill]] = OpFunction
35 ; CHECK-NEXT: OpLabel
36 ; CHECK-NEXT: OpKill
37 ; CHECK-NEXT: OpFunctionEnd
38                OpCapability Shader
39           %1 = OpExtInstImport "GLSL.std.450"
40                OpMemoryModel Logical GLSL450
41                OpEntryPoint Fragment %main "main"
42                OpExecutionMode %main OriginUpperLeft
43                OpSource GLSL 330
44                OpName %main "main"
45        %void = OpTypeVoid
46           %5 = OpTypeFunction %void
47        %bool = OpTypeBool
48        %true = OpConstantTrue %bool
49        %main = OpFunction %void None %5
50           %8 = OpLabel
51                OpBranch %9
52           %9 = OpLabel
53                OpLoopMerge %10 %11 None
54                OpBranch %12
55          %12 = OpLabel
56                OpBranchConditional %true %13 %10
57          %13 = OpLabel
58                OpBranch %11
59          %11 = OpLabel
60          %14 = OpFunctionCall %void %kill_
61                OpBranch %9
62          %10 = OpLabel
63                OpReturn
64                OpFunctionEnd
65       %kill_ = OpFunction %void None %5
66          %15 = OpLabel
67                OpKill
68                OpFunctionEnd
69   )";
70 
71   SinglePassRunAndMatch<WrapOpKill>(text, true);
72 }
73 
TEST_F(WrapOpKillTest,MultipleOpKillInSameFunc)74 TEST_F(WrapOpKillTest, MultipleOpKillInSameFunc) {
75   const std::string text = R"(
76 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
77 ; CHECK: [[main]] = OpFunction
78 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
79 ; CHECK: [[orig_kill]] = OpFunction
80 ; CHECK-NEXT: OpLabel
81 ; CHECK-NEXT: OpSelectionMerge
82 ; CHECK-NEXT: OpBranchConditional
83 ; CHECK-NEXT: OpLabel
84 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
85 ; CHECK-NEXT: OpReturn
86 ; CHECK-NEXT: OpLabel
87 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
88 ; CHECK-NEXT: OpReturn
89 ; CHECK: [[new_kill]] = OpFunction
90 ; CHECK-NEXT: OpLabel
91 ; CHECK-NEXT: OpKill
92 ; CHECK-NEXT: OpFunctionEnd
93                OpCapability Shader
94           %1 = OpExtInstImport "GLSL.std.450"
95                OpMemoryModel Logical GLSL450
96                OpEntryPoint Fragment %main "main"
97                OpExecutionMode %main OriginUpperLeft
98                OpSource GLSL 330
99                OpName %main "main"
100        %void = OpTypeVoid
101           %5 = OpTypeFunction %void
102        %bool = OpTypeBool
103        %true = OpConstantTrue %bool
104        %main = OpFunction %void None %5
105           %8 = OpLabel
106                OpBranch %9
107           %9 = OpLabel
108                OpLoopMerge %10 %11 None
109                OpBranch %12
110          %12 = OpLabel
111                OpBranchConditional %true %13 %10
112          %13 = OpLabel
113                OpBranch %11
114          %11 = OpLabel
115          %14 = OpFunctionCall %void %kill_
116                OpBranch %9
117          %10 = OpLabel
118                OpReturn
119                OpFunctionEnd
120       %kill_ = OpFunction %void None %5
121          %15 = OpLabel
122                OpSelectionMerge %16 None
123                OpBranchConditional %true %17 %18
124          %17 = OpLabel
125                OpKill
126          %18 = OpLabel
127                OpKill
128          %16 = OpLabel
129                OpReturn
130                OpFunctionEnd
131   )";
132 
133   SinglePassRunAndMatch<WrapOpKill>(text, true);
134 }
135 
TEST_F(WrapOpKillTest,MultipleOpKillInDifferentFunc)136 TEST_F(WrapOpKillTest, MultipleOpKillInDifferentFunc) {
137   const std::string text = R"(
138 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
139 ; CHECK: [[main]] = OpFunction
140 ; CHECK: OpFunctionCall %void [[orig_kill1:%\w+]]
141 ; CHECK-NEXT: OpFunctionCall %void [[orig_kill2:%\w+]]
142 ; CHECK: [[orig_kill1]] = OpFunction
143 ; CHECK-NEXT: OpLabel
144 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
145 ; CHECK-NEXT: OpReturn
146 ; CHECK: [[orig_kill2]] = OpFunction
147 ; CHECK-NEXT: OpLabel
148 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
149 ; CHECK-NEXT: OpReturn
150 ; CHECK: [[new_kill]] = OpFunction
151 ; CHECK-NEXT: OpLabel
152 ; CHECK-NEXT: OpKill
153 ; CHECK-NEXT: OpFunctionEnd
154                OpCapability Shader
155           %1 = OpExtInstImport "GLSL.std.450"
156                OpMemoryModel Logical GLSL450
157                OpEntryPoint Fragment %main "main"
158                OpExecutionMode %main OriginUpperLeft
159                OpSource GLSL 330
160                OpName %main "main"
161        %void = OpTypeVoid
162           %4 = OpTypeFunction %void
163        %bool = OpTypeBool
164        %true = OpConstantTrue %bool
165        %main = OpFunction %void None %4
166           %7 = OpLabel
167                OpBranch %8
168           %8 = OpLabel
169                OpLoopMerge %9 %10 None
170                OpBranch %11
171          %11 = OpLabel
172                OpBranchConditional %true %12 %9
173          %12 = OpLabel
174                OpBranch %10
175          %10 = OpLabel
176          %13 = OpFunctionCall %void %14
177          %15 = OpFunctionCall %void %16
178                OpBranch %8
179           %9 = OpLabel
180                OpReturn
181                OpFunctionEnd
182          %14 = OpFunction %void None %4
183          %17 = OpLabel
184                OpKill
185                OpFunctionEnd
186          %16 = OpFunction %void None %4
187          %18 = OpLabel
188                OpKill
189                OpFunctionEnd
190   )";
191 
192   SinglePassRunAndMatch<WrapOpKill>(text, true);
193 }
194 
TEST_F(WrapOpKillTest,SingleOpTerminateInvocation)195 TEST_F(WrapOpKillTest, SingleOpTerminateInvocation) {
196   const std::string text = R"(
197 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
198 ; CHECK: [[main]] = OpFunction
199 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
200 ; CHECK: [[orig_kill]] = OpFunction
201 ; CHECK-NEXT: OpLabel
202 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
203 ; CHECK-NEXT: OpReturn
204 ; CHECK: [[new_kill]] = OpFunction
205 ; CHECK-NEXT: OpLabel
206 ; CHECK-NEXT: OpTerminateInvocation
207 ; CHECK-NEXT: OpFunctionEnd
208                OpCapability Shader
209                OpExtension "SPV_KHR_terminate_invocation"
210           %1 = OpExtInstImport "GLSL.std.450"
211                OpMemoryModel Logical GLSL450
212                OpEntryPoint Fragment %main "main"
213                OpExecutionMode %main OriginUpperLeft
214                OpSource GLSL 330
215                OpName %main "main"
216        %void = OpTypeVoid
217           %5 = OpTypeFunction %void
218        %bool = OpTypeBool
219        %true = OpConstantTrue %bool
220        %main = OpFunction %void None %5
221           %8 = OpLabel
222                OpBranch %9
223           %9 = OpLabel
224                OpLoopMerge %10 %11 None
225                OpBranch %12
226          %12 = OpLabel
227                OpBranchConditional %true %13 %10
228          %13 = OpLabel
229                OpBranch %11
230          %11 = OpLabel
231          %14 = OpFunctionCall %void %kill_
232                OpBranch %9
233          %10 = OpLabel
234                OpReturn
235                OpFunctionEnd
236       %kill_ = OpFunction %void None %5
237          %15 = OpLabel
238                OpTerminateInvocation
239                OpFunctionEnd
240   )";
241 
242   SinglePassRunAndMatch<WrapOpKill>(text, true);
243 }
244 
TEST_F(WrapOpKillTest,MultipleTerminateInvocationInSameFunc)245 TEST_F(WrapOpKillTest, MultipleTerminateInvocationInSameFunc) {
246   const std::string text = R"(
247 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
248 ; CHECK: [[main]] = OpFunction
249 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
250 ; CHECK: [[orig_kill]] = OpFunction
251 ; CHECK-NEXT: OpLabel
252 ; CHECK-NEXT: OpSelectionMerge
253 ; CHECK-NEXT: OpBranchConditional
254 ; CHECK-NEXT: OpLabel
255 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
256 ; CHECK-NEXT: OpReturn
257 ; CHECK-NEXT: OpLabel
258 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
259 ; CHECK-NEXT: OpReturn
260 ; CHECK: [[new_kill]] = OpFunction
261 ; CHECK-NEXT: OpLabel
262 ; CHECK-NEXT: OpTerminateInvocation
263 ; CHECK-NEXT: OpFunctionEnd
264                OpCapability Shader
265                OpExtension "SPV_KHR_terminate_invocation"
266           %1 = OpExtInstImport "GLSL.std.450"
267                OpMemoryModel Logical GLSL450
268                OpEntryPoint Fragment %main "main"
269                OpExecutionMode %main OriginUpperLeft
270                OpSource GLSL 330
271                OpName %main "main"
272        %void = OpTypeVoid
273           %5 = OpTypeFunction %void
274        %bool = OpTypeBool
275        %true = OpConstantTrue %bool
276        %main = OpFunction %void None %5
277           %8 = OpLabel
278                OpBranch %9
279           %9 = OpLabel
280                OpLoopMerge %10 %11 None
281                OpBranch %12
282          %12 = OpLabel
283                OpBranchConditional %true %13 %10
284          %13 = OpLabel
285                OpBranch %11
286          %11 = OpLabel
287          %14 = OpFunctionCall %void %kill_
288                OpBranch %9
289          %10 = OpLabel
290                OpReturn
291                OpFunctionEnd
292       %kill_ = OpFunction %void None %5
293          %15 = OpLabel
294                OpSelectionMerge %16 None
295                OpBranchConditional %true %17 %18
296          %17 = OpLabel
297                OpTerminateInvocation
298          %18 = OpLabel
299                OpTerminateInvocation
300          %16 = OpLabel
301                OpReturn
302                OpFunctionEnd
303   )";
304 
305   SinglePassRunAndMatch<WrapOpKill>(text, true);
306 }
307 
TEST_F(WrapOpKillTest,MultipleOpTerminateInvocationDifferentFunc)308 TEST_F(WrapOpKillTest, MultipleOpTerminateInvocationDifferentFunc) {
309   const std::string text = R"(
310 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
311 ; CHECK: [[main]] = OpFunction
312 ; CHECK: OpFunctionCall %void [[orig_kill1:%\w+]]
313 ; CHECK-NEXT: OpFunctionCall %void [[orig_kill2:%\w+]]
314 ; CHECK: [[orig_kill1]] = OpFunction
315 ; CHECK-NEXT: OpLabel
316 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
317 ; CHECK-NEXT: OpReturn
318 ; CHECK: [[orig_kill2]] = OpFunction
319 ; CHECK-NEXT: OpLabel
320 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
321 ; CHECK-NEXT: OpReturn
322 ; CHECK: [[new_kill]] = OpFunction
323 ; CHECK-NEXT: OpLabel
324 ; CHECK-NEXT: OpTerminateInvocation
325 ; CHECK-NEXT: OpFunctionEnd
326                OpCapability Shader
327                OpExtension "SPV_KHR_terminate_invocation"
328           %1 = OpExtInstImport "GLSL.std.450"
329                OpMemoryModel Logical GLSL450
330                OpEntryPoint Fragment %main "main"
331                OpExecutionMode %main OriginUpperLeft
332                OpSource GLSL 330
333                OpName %main "main"
334        %void = OpTypeVoid
335           %4 = OpTypeFunction %void
336        %bool = OpTypeBool
337        %true = OpConstantTrue %bool
338        %main = OpFunction %void None %4
339           %7 = OpLabel
340                OpBranch %8
341           %8 = OpLabel
342                OpLoopMerge %9 %10 None
343                OpBranch %11
344          %11 = OpLabel
345                OpBranchConditional %true %12 %9
346          %12 = OpLabel
347                OpBranch %10
348          %10 = OpLabel
349          %13 = OpFunctionCall %void %14
350          %15 = OpFunctionCall %void %16
351                OpBranch %8
352           %9 = OpLabel
353                OpReturn
354                OpFunctionEnd
355          %14 = OpFunction %void None %4
356          %17 = OpLabel
357                OpTerminateInvocation
358                OpFunctionEnd
359          %16 = OpFunction %void None %4
360          %18 = OpLabel
361                OpTerminateInvocation
362                OpFunctionEnd
363   )";
364 
365   SinglePassRunAndMatch<WrapOpKill>(text, true);
366 }
367 
TEST_F(WrapOpKillTest,KillAndTerminateInvocationSameFunc)368 TEST_F(WrapOpKillTest, KillAndTerminateInvocationSameFunc) {
369   const std::string text = R"(
370 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
371 ; CHECK: [[main]] = OpFunction
372 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
373 ; CHECK: [[orig_kill]] = OpFunction
374 ; CHECK-NEXT: OpLabel
375 ; CHECK-NEXT: OpSelectionMerge
376 ; CHECK-NEXT: OpBranchConditional
377 ; CHECK-NEXT: OpLabel
378 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
379 ; CHECK-NEXT: OpReturn
380 ; CHECK-NEXT: OpLabel
381 ; CHECK-NEXT: OpFunctionCall %void [[new_terminate:%\w+]]
382 ; CHECK-NEXT: OpReturn
383 ; CHECK: [[new_kill]] = OpFunction
384 ; CHECK-NEXT: OpLabel
385 ; CHECK-NEXT: OpKill
386 ; CHECK-NEXT: OpFunctionEnd
387 ; CHECK-NEXT: [[new_terminate]] = OpFunction
388 ; CHECK-NEXT: OpLabel
389 ; CHECK-NEXT: OpTerminateInvocation
390 ; CHECK-NEXT: OpFunctionEnd
391                OpCapability Shader
392                OpExtension "SPV_KHR_terminate_invocation"
393           %1 = OpExtInstImport "GLSL.std.450"
394                OpMemoryModel Logical GLSL450
395                OpEntryPoint Fragment %main "main"
396                OpExecutionMode %main OriginUpperLeft
397                OpSource GLSL 330
398                OpName %main "main"
399        %void = OpTypeVoid
400           %5 = OpTypeFunction %void
401        %bool = OpTypeBool
402        %true = OpConstantTrue %bool
403        %main = OpFunction %void None %5
404           %8 = OpLabel
405                OpBranch %9
406           %9 = OpLabel
407                OpLoopMerge %10 %11 None
408                OpBranch %12
409          %12 = OpLabel
410                OpBranchConditional %true %13 %10
411          %13 = OpLabel
412                OpBranch %11
413          %11 = OpLabel
414          %14 = OpFunctionCall %void %kill_
415                OpBranch %9
416          %10 = OpLabel
417                OpReturn
418                OpFunctionEnd
419       %kill_ = OpFunction %void None %5
420          %15 = OpLabel
421                OpSelectionMerge %16 None
422                OpBranchConditional %true %17 %18
423          %17 = OpLabel
424                OpKill
425          %18 = OpLabel
426                OpTerminateInvocation
427          %16 = OpLabel
428                OpReturn
429                OpFunctionEnd
430   )";
431 
432   SinglePassRunAndMatch<WrapOpKill>(text, true);
433 }
434 
TEST_F(WrapOpKillTest,KillAndTerminateInvocationDifferentFunc)435 TEST_F(WrapOpKillTest, KillAndTerminateInvocationDifferentFunc) {
436   const std::string text = R"(
437 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
438 ; CHECK: [[main]] = OpFunction
439 ; CHECK: OpFunctionCall %void [[orig_kill1:%\w+]]
440 ; CHECK-NEXT: OpFunctionCall %void [[orig_kill2:%\w+]]
441 ; CHECK: [[orig_kill1]] = OpFunction
442 ; CHECK-NEXT: OpLabel
443 ; CHECK-NEXT: OpFunctionCall %void [[new_terminate:%\w+]]
444 ; CHECK-NEXT: OpReturn
445 ; CHECK: [[orig_kill2]] = OpFunction
446 ; CHECK-NEXT: OpLabel
447 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
448 ; CHECK-NEXT: OpReturn
449 ; CHECK: [[new_kill]] = OpFunction
450 ; CHECK-NEXT: OpLabel
451 ; CHECK-NEXT: OpKill
452 ; CHECK-NEXT: OpFunctionEnd
453 ; CHECK-NEXT: [[new_terminate]] = OpFunction
454 ; CHECK-NEXT: OpLabel
455 ; CHECK-NEXT: OpTerminateInvocation
456 ; CHECK-NEXT: OpFunctionEnd
457                OpCapability Shader
458                OpExtension "SPV_KHR_terminate_invocation"
459           %1 = OpExtInstImport "GLSL.std.450"
460                OpMemoryModel Logical GLSL450
461                OpEntryPoint Fragment %main "main"
462                OpExecutionMode %main OriginUpperLeft
463                OpSource GLSL 330
464                OpName %main "main"
465        %void = OpTypeVoid
466           %4 = OpTypeFunction %void
467        %bool = OpTypeBool
468        %true = OpConstantTrue %bool
469        %main = OpFunction %void None %4
470           %7 = OpLabel
471                OpBranch %8
472           %8 = OpLabel
473                OpLoopMerge %9 %10 None
474                OpBranch %11
475          %11 = OpLabel
476                OpBranchConditional %true %12 %9
477          %12 = OpLabel
478                OpBranch %10
479          %10 = OpLabel
480          %13 = OpFunctionCall %void %14
481          %15 = OpFunctionCall %void %16
482                OpBranch %8
483           %9 = OpLabel
484                OpReturn
485                OpFunctionEnd
486          %14 = OpFunction %void None %4
487          %17 = OpLabel
488                OpTerminateInvocation
489                OpFunctionEnd
490          %16 = OpFunction %void None %4
491          %18 = OpLabel
492                OpKill
493                OpFunctionEnd
494   )";
495 
496   SinglePassRunAndMatch<WrapOpKill>(text, true);
497 }
498 
TEST_F(WrapOpKillTest,FuncWithReturnValue)499 TEST_F(WrapOpKillTest, FuncWithReturnValue) {
500   const std::string text = R"(
501 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
502 ; CHECK: [[main]] = OpFunction
503 ; CHECK: OpFunctionCall %int [[orig_kill:%\w+]]
504 ; CHECK: [[orig_kill]] = OpFunction
505 ; CHECK-NEXT: OpLabel
506 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
507 ; CHECK-NEXT: [[undef:%\w+]] = OpUndef %int
508 ; CHECK-NEXT: OpReturnValue [[undef]]
509 ; CHECK: [[new_kill]] = OpFunction
510 ; CHECK-NEXT: OpLabel
511 ; CHECK-NEXT: OpKill
512 ; CHECK-NEXT: OpFunctionEnd
513                OpCapability Shader
514           %1 = OpExtInstImport "GLSL.std.450"
515                OpMemoryModel Logical GLSL450
516                OpEntryPoint Fragment %main "main"
517                OpExecutionMode %main OriginUpperLeft
518                OpSource GLSL 330
519                OpName %main "main"
520        %void = OpTypeVoid
521           %5 = OpTypeFunction %void
522         %int = OpTypeInt 32 1
523   %func_type = OpTypeFunction %int
524        %bool = OpTypeBool
525        %true = OpConstantTrue %bool
526        %main = OpFunction %void None %5
527           %8 = OpLabel
528                OpBranch %9
529           %9 = OpLabel
530                OpLoopMerge %10 %11 None
531                OpBranch %12
532          %12 = OpLabel
533                OpBranchConditional %true %13 %10
534          %13 = OpLabel
535                OpBranch %11
536          %11 = OpLabel
537          %14 = OpFunctionCall %int %kill_
538                OpBranch %9
539          %10 = OpLabel
540                OpReturn
541                OpFunctionEnd
542       %kill_ = OpFunction %int None %func_type
543          %15 = OpLabel
544                OpKill
545                OpFunctionEnd
546   )";
547 
548   SinglePassRunAndMatch<WrapOpKill>(text, true);
549 }
550 
TEST_F(WrapOpKillTest,IdBoundOverflow1)551 TEST_F(WrapOpKillTest, IdBoundOverflow1) {
552   const std::string text = R"(
553 OpCapability GeometryStreams
554 OpMemoryModel Logical GLSL450
555 OpEntryPoint Fragment %main "main"
556 OpExecutionMode %main OriginUpperLeft
557 %2 = OpTypeVoid
558 %3 = OpTypeFunction %2
559 %bool = OpTypeBool
560 %true = OpConstantTrue %bool
561 %main = OpFunction %2 None %3
562 %8 = OpLabel
563 OpBranch %9
564 %9 = OpLabel
565 OpLoopMerge %10 %11 None
566 OpBranch %12
567 %12 = OpLabel
568 OpBranchConditional %true %13 %10
569 %13 = OpLabel
570 OpBranch %11
571 %11 = OpLabel
572 %14 = OpFunctionCall %void %kill_
573 OpBranch %9
574 %10 = OpLabel
575 OpReturn
576 OpFunctionEnd
577 %kill_ = OpFunction %2 Pure|Const %3
578 %4194302 = OpLabel
579 OpKill
580 OpFunctionEnd
581 )";
582 
583   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
584 
585   std::vector<Message> messages = {
586       {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
587   SetMessageConsumer(GetTestMessageConsumer(messages));
588   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
589   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
590 }
591 
TEST_F(WrapOpKillTest,IdBoundOverflow2)592 TEST_F(WrapOpKillTest, IdBoundOverflow2) {
593   const std::string text = R"(
594 OpCapability GeometryStreams
595 OpMemoryModel Logical GLSL450
596 OpEntryPoint Fragment %main "main"
597 OpExecutionMode %main OriginUpperLeft
598 %2 = OpTypeVoid
599 %3 = OpTypeFunction %2
600 %bool = OpTypeBool
601 %true = OpConstantTrue %bool
602 %main = OpFunction %2 None %3
603 %8 = OpLabel
604 OpBranch %9
605 %9 = OpLabel
606 OpLoopMerge %10 %11 None
607 OpBranch %12
608 %12 = OpLabel
609 OpBranchConditional %true %13 %10
610 %13 = OpLabel
611 OpBranch %11
612 %11 = OpLabel
613 %14 = OpFunctionCall %void %kill_
614 OpBranch %9
615 %10 = OpLabel
616 OpReturn
617 OpFunctionEnd
618 %kill_ = OpFunction %2 Pure|Const %3
619 %4194301 = OpLabel
620 OpKill
621 OpFunctionEnd
622 )";
623 
624   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
625 
626   std::vector<Message> messages = {
627       {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
628   SetMessageConsumer(GetTestMessageConsumer(messages));
629   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
630   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
631 }
632 
TEST_F(WrapOpKillTest,IdBoundOverflow3)633 TEST_F(WrapOpKillTest, IdBoundOverflow3) {
634   const std::string text = R"(
635 OpCapability GeometryStreams
636 OpMemoryModel Logical GLSL450
637 OpEntryPoint Fragment %main "main"
638 OpExecutionMode %main OriginUpperLeft
639 %2 = OpTypeVoid
640 %3 = OpTypeFunction %2
641 %bool = OpTypeBool
642 %true = OpConstantTrue %bool
643 %main = OpFunction %2 None %3
644 %8 = OpLabel
645 OpBranch %9
646 %9 = OpLabel
647 OpLoopMerge %10 %11 None
648 OpBranch %12
649 %12 = OpLabel
650 OpBranchConditional %true %13 %10
651 %13 = OpLabel
652 OpBranch %11
653 %11 = OpLabel
654 %14 = OpFunctionCall %void %kill_
655 OpBranch %9
656 %10 = OpLabel
657 OpReturn
658 OpFunctionEnd
659 %kill_ = OpFunction %2 Pure|Const %3
660 %4194300 = OpLabel
661 OpKill
662 OpFunctionEnd
663 )";
664 
665   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
666 
667   std::vector<Message> messages = {
668       {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
669   SetMessageConsumer(GetTestMessageConsumer(messages));
670   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
671   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
672 }
673 
TEST_F(WrapOpKillTest,IdBoundOverflow4)674 TEST_F(WrapOpKillTest, IdBoundOverflow4) {
675   const std::string text = R"(
676 OpCapability DerivativeControl
677 OpMemoryModel Logical GLSL450
678 OpEntryPoint Fragment %main "main"
679 OpExecutionMode %main OriginUpperLeft
680 OpDecorate %2 Location 539091968
681 %2 = OpTypeVoid
682 %3 = OpTypeFunction %2
683 %bool = OpTypeBool
684 %true = OpConstantTrue %bool
685 %main = OpFunction %2 None %3
686 %8 = OpLabel
687 OpBranch %9
688 %9 = OpLabel
689 OpLoopMerge %10 %11 None
690 OpBranch %12
691 %12 = OpLabel
692 OpBranchConditional %true %13 %10
693 %13 = OpLabel
694 OpBranch %11
695 %11 = OpLabel
696 %14 = OpFunctionCall %void %kill_
697 OpBranch %9
698 %10 = OpLabel
699 OpReturn
700 OpFunctionEnd
701 %kill_ = OpFunction %2 Inline|Pure|Const %3
702 %4194302 = OpLabel
703 OpKill
704 OpFunctionEnd
705 )";
706 
707   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
708 
709   std::vector<Message> messages = {
710       {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
711   SetMessageConsumer(GetTestMessageConsumer(messages));
712   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
713   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
714 }
715 
TEST_F(WrapOpKillTest,IdBoundOverflow5)716 TEST_F(WrapOpKillTest, IdBoundOverflow5) {
717   const std::string text = R"(
718                OpCapability Shader
719                OpMemoryModel Logical GLSL450
720                OpEntryPoint Fragment %1 "main"
721                OpExecutionMode %1 OriginUpperLeft
722                OpDecorate %void Location 539091968
723        %void = OpTypeVoid
724           %3 = OpTypeFunction %void
725       %float = OpTypeFloat 32
726   %_struct_5 = OpTypeStruct %float %float
727   %_struct_6 = OpTypeStruct %_struct_5
728 %_ptr_Function__struct_6 = OpTypePointer Function %_struct_6
729 %_ptr_Output_float = OpTypePointer Output %float
730           %9 = OpTypeFunction %_struct_5 %_ptr_Function__struct_6
731        %bool = OpTypeBool
732        %true = OpConstantTrue %bool
733           %1 = OpFunction %void None %3
734          %12 = OpLabel
735          %13 = OpVariable %_ptr_Function__struct_6 Function
736                OpBranch %14
737          %14 = OpLabel
738                OpLoopMerge %15 %16 None
739                OpBranch %17
740          %17 = OpLabel
741                OpBranchConditional %true %18 %15
742          %18 = OpLabel
743                OpBranch %16
744          %16 = OpLabel
745          %19 = OpFunctionCall %void %20
746          %21 = OpFunctionCall %_struct_5 %22 %13
747                OpBranch %14
748          %15 = OpLabel
749                OpReturn
750                OpFunctionEnd
751          %20 = OpFunction %void Inline|Pure|Const %3
752          %23 = OpLabel
753          %24 = OpVariable %_ptr_Function__struct_6 Function
754          %25 = OpFunctionCall %_struct_5 %26 %24
755                OpKill
756                OpFunctionEnd
757          %26 = OpFunction %_struct_5 None %9
758          %27 = OpLabel
759                OpUnreachable
760                OpFunctionEnd
761          %22 = OpFunction %_struct_5 Inline %9
762     %4194295 = OpLabel
763                OpKill
764                OpFunctionEnd
765 )";
766 
767   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
768 
769   std::vector<Message> messages = {
770       {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
771   SetMessageConsumer(GetTestMessageConsumer(messages));
772   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
773   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
774 }
775 
TEST_F(WrapOpKillTest,SkipEntryPoint)776 TEST_F(WrapOpKillTest, SkipEntryPoint) {
777   const std::string text = R"(
778 OpCapability GeometryStreams
779 OpMemoryModel Logical GLSL450
780 OpEntryPoint Fragment %4 "main"
781 OpExecutionMode %4 OriginUpperLeft
782 %2 = OpTypeVoid
783 %3 = OpTypeFunction %2
784 %4 = OpFunction %2 Pure|Const %3
785 %5 = OpLabel
786 OpKill
787 OpFunctionEnd
788 )";
789 
790   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
791   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
792 }
793 
TEST_F(WrapOpKillTest,SkipFunctionNotInContinue)794 TEST_F(WrapOpKillTest, SkipFunctionNotInContinue) {
795   const std::string text = R"(
796 OpCapability GeometryStreams
797 OpMemoryModel Logical GLSL450
798 OpEntryPoint Fragment %main "main"
799 OpExecutionMode %main OriginUpperLeft
800 %2 = OpTypeVoid
801 %3 = OpTypeFunction %2
802 %bool = OpTypeBool
803 %true = OpConstantTrue %bool
804 %main = OpFunction %2 None %3
805 %6 = OpLabel
806 %7 = OpFunctionCall %void %4
807 OpReturn
808 OpFunctionEnd
809 %4 = OpFunction %2 Pure|Const %3
810 %5 = OpLabel
811 OpKill
812 OpFunctionEnd
813 )";
814 
815   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
816   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
817 }
818 
TEST_F(WrapOpKillTest,SetParentBlock)819 TEST_F(WrapOpKillTest, SetParentBlock) {
820   const std::string text = R"(
821 OpCapability Shader
822 OpMemoryModel Logical GLSL450
823 OpEntryPoint Fragment %main "main"
824 OpExecutionMode %main OriginUpperLeft
825 %void = OpTypeVoid
826 %bool = OpTypeBool
827 %undef = OpUndef %bool
828 %void_fn = OpTypeFunction %void
829 %main = OpFunction %void None %void_fn
830 %entry = OpLabel
831 OpBranch %loop
832 %loop = OpLabel
833 OpLoopMerge %merge %continue None
834 OpBranchConditional %undef %merge %continue
835 %continue = OpLabel
836 %call = OpFunctionCall %void %kill_func
837 OpBranch %loop
838 %merge = OpLabel
839 OpReturn
840 OpFunctionEnd
841 %kill_func = OpFunction %void None %void_fn
842 %kill_entry = OpLabel
843 OpKill
844 OpFunctionEnd
845 )";
846 
847   auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
848   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
849   result = SinglePassRunToBinary<WrapOpKill>(text, true);
850   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
851 }
852 
TEST_F(WrapOpKillTest,KillInSingleBlockLoop)853 TEST_F(WrapOpKillTest, KillInSingleBlockLoop) {
854   const std::string text = R"(
855 ; CHECK: OpFunction %void
856 ; CHECK: OpFunction %void
857 ; CHECK-NOT: OpKill
858 ; CHECK: OpFunctionCall %void [[new_kill:%\w+]]
859 ; CHECK-NOT: OpKill
860 ; CHECK: [[new_kill]] = OpFunction
861 ; CHECK-NEXT: OpLabel
862 ; CHECK-NEXT: OpKill
863 ; CHECK-NEXT: OpFunctionEnd
864               OpCapability Shader
865               OpCapability Linkage
866               OpMemoryModel Logical GLSL450
867       %void = OpTypeVoid
868       %bool = OpTypeBool
869      %undef = OpUndef %bool
870    %void_fn = OpTypeFunction %void
871       %main = OpFunction %void None %void_fn
872 %main_entry = OpLabel
873               OpBranch %loop
874       %loop = OpLabel
875       %call = OpFunctionCall %void %sub
876               OpLoopMerge %exit %loop None
877               OpBranchConditional %undef %loop %exit
878       %exit = OpLabel
879               OpReturn
880               OpFunctionEnd
881        %sub = OpFunction %void None %void_fn
882  %sub_entry = OpLabel
883               OpSelectionMerge %ret None
884               OpBranchConditional %undef %kill %ret
885       %kill = OpLabel
886               OpKill
887        %ret = OpLabel
888               OpReturn
889               OpFunctionEnd
890 )";
891 
892   SinglePassRunAndMatch<WrapOpKill>(text, true);
893 }
894 
TEST_F(WrapOpKillTest,DebugInfoSimple)895 TEST_F(WrapOpKillTest, DebugInfoSimple) {
896   const std::string text = R"(
897 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
898 ; CHECK: [[main]] = OpFunction
899 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
900 ; CHECK: [[orig_kill]] = OpFunction
901 ; CHECK-NEXT: OpLabel
902 ; CHECK-NEXT: {{%\d+}} = OpExtInst %void [[ext:%\d+]] DebugScope
903 ; CHECK-NEXT: OpLine [[file:%\d+]] 100 200
904 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
905 ; CHECK:      {{%\d+}} = OpExtInst %void [[ext]] DebugNoScope
906 ; CHECK-NEXT: OpReturn
907 ; CHECK: [[new_kill]] = OpFunction
908 ; CHECK-NEXT: OpLabel
909 ; CHECK-NEXT: OpKill
910 ; CHECK-NEXT: OpFunctionEnd
911                OpCapability Shader
912           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
913                OpMemoryModel Logical GLSL450
914                OpEntryPoint Fragment %main "main"
915                OpExecutionMode %main OriginUpperLeft
916           %2 = OpString "File name"
917                OpSource GLSL 330
918                OpName %main "main"
919        %void = OpTypeVoid
920           %5 = OpTypeFunction %void
921        %bool = OpTypeBool
922        %true = OpConstantTrue %bool
923           %3 = OpExtInst %void %1 DebugSource %2
924           %4 = OpExtInst %void %1 DebugCompilationUnit 0 0 %3 GLSL
925        %main = OpFunction %void None %5
926           %8 = OpLabel
927                OpBranch %9
928           %9 = OpLabel
929                OpLoopMerge %10 %11 None
930                OpBranch %12
931          %12 = OpLabel
932                OpBranchConditional %true %13 %10
933          %13 = OpLabel
934                OpBranch %11
935          %11 = OpLabel
936          %14 = OpFunctionCall %void %kill_
937                OpBranch %9
938          %10 = OpLabel
939                OpReturn
940                OpFunctionEnd
941       %kill_ = OpFunction %void None %5
942          %15 = OpLabel
943          %16 = OpExtInst %void %1 DebugScope %4
944                OpLine %2 100 200
945                OpKill
946                OpFunctionEnd
947   )";
948 
949   SinglePassRunAndMatch<WrapOpKill>(text, true);
950 }
951 
952 }  // namespace
953 }  // namespace opt
954 }  // namespace spvtools
955