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
19namespace spvtools {
20namespace opt {
21namespace {
22
23using WrapOpKillTest = PassTest<::testing::Test>;
24
25TEST_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
74TEST_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
136TEST_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
195TEST_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
245TEST_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
308TEST_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
368TEST_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
435TEST_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
499TEST_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
551TEST_F(WrapOpKillTest, IdBoundOverflow1) {
552  const std::string text = R"(
553OpCapability GeometryStreams
554OpMemoryModel Logical GLSL450
555OpEntryPoint Fragment %main "main"
556OpExecutionMode %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
563OpBranch %9
564%9 = OpLabel
565OpLoopMerge %10 %11 None
566OpBranch %12
567%12 = OpLabel
568OpBranchConditional %true %13 %10
569%13 = OpLabel
570OpBranch %11
571%11 = OpLabel
572%14 = OpFunctionCall %void %kill_
573OpBranch %9
574%10 = OpLabel
575OpReturn
576OpFunctionEnd
577%kill_ = OpFunction %2 Pure|Const %3
578%4194302 = OpLabel
579OpKill
580OpFunctionEnd
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
592TEST_F(WrapOpKillTest, IdBoundOverflow2) {
593  const std::string text = R"(
594OpCapability GeometryStreams
595OpMemoryModel Logical GLSL450
596OpEntryPoint Fragment %main "main"
597OpExecutionMode %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
604OpBranch %9
605%9 = OpLabel
606OpLoopMerge %10 %11 None
607OpBranch %12
608%12 = OpLabel
609OpBranchConditional %true %13 %10
610%13 = OpLabel
611OpBranch %11
612%11 = OpLabel
613%14 = OpFunctionCall %void %kill_
614OpBranch %9
615%10 = OpLabel
616OpReturn
617OpFunctionEnd
618%kill_ = OpFunction %2 Pure|Const %3
619%4194301 = OpLabel
620OpKill
621OpFunctionEnd
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
633TEST_F(WrapOpKillTest, IdBoundOverflow3) {
634  const std::string text = R"(
635OpCapability GeometryStreams
636OpMemoryModel Logical GLSL450
637OpEntryPoint Fragment %main "main"
638OpExecutionMode %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
645OpBranch %9
646%9 = OpLabel
647OpLoopMerge %10 %11 None
648OpBranch %12
649%12 = OpLabel
650OpBranchConditional %true %13 %10
651%13 = OpLabel
652OpBranch %11
653%11 = OpLabel
654%14 = OpFunctionCall %void %kill_
655OpBranch %9
656%10 = OpLabel
657OpReturn
658OpFunctionEnd
659%kill_ = OpFunction %2 Pure|Const %3
660%4194300 = OpLabel
661OpKill
662OpFunctionEnd
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
674TEST_F(WrapOpKillTest, IdBoundOverflow4) {
675  const std::string text = R"(
676OpCapability DerivativeControl
677OpMemoryModel Logical GLSL450
678OpEntryPoint Fragment %main "main"
679OpExecutionMode %main OriginUpperLeft
680OpDecorate %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
687OpBranch %9
688%9 = OpLabel
689OpLoopMerge %10 %11 None
690OpBranch %12
691%12 = OpLabel
692OpBranchConditional %true %13 %10
693%13 = OpLabel
694OpBranch %11
695%11 = OpLabel
696%14 = OpFunctionCall %void %kill_
697OpBranch %9
698%10 = OpLabel
699OpReturn
700OpFunctionEnd
701%kill_ = OpFunction %2 Inline|Pure|Const %3
702%4194302 = OpLabel
703OpKill
704OpFunctionEnd
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
716TEST_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
776TEST_F(WrapOpKillTest, SkipEntryPoint) {
777  const std::string text = R"(
778OpCapability GeometryStreams
779OpMemoryModel Logical GLSL450
780OpEntryPoint Fragment %4 "main"
781OpExecutionMode %4 OriginUpperLeft
782%2 = OpTypeVoid
783%3 = OpTypeFunction %2
784%4 = OpFunction %2 Pure|Const %3
785%5 = OpLabel
786OpKill
787OpFunctionEnd
788)";
789
790  auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
791  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
792}
793
794TEST_F(WrapOpKillTest, SkipFunctionNotInContinue) {
795  const std::string text = R"(
796OpCapability GeometryStreams
797OpMemoryModel Logical GLSL450
798OpEntryPoint Fragment %main "main"
799OpExecutionMode %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
807OpReturn
808OpFunctionEnd
809%4 = OpFunction %2 Pure|Const %3
810%5 = OpLabel
811OpKill
812OpFunctionEnd
813)";
814
815  auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
816  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
817}
818
819TEST_F(WrapOpKillTest, SetParentBlock) {
820  const std::string text = R"(
821OpCapability Shader
822OpMemoryModel Logical GLSL450
823OpEntryPoint Fragment %main "main"
824OpExecutionMode %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
831OpBranch %loop
832%loop = OpLabel
833OpLoopMerge %merge %continue None
834OpBranchConditional %undef %merge %continue
835%continue = OpLabel
836%call = OpFunctionCall %void %kill_func
837OpBranch %loop
838%merge = OpLabel
839OpReturn
840OpFunctionEnd
841%kill_func = OpFunction %void None %void_fn
842%kill_entry = OpLabel
843OpKill
844OpFunctionEnd
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
853TEST_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
895TEST_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