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 "gmock/gmock.h"
16 #include "test/opt/assembly_builder.h"
17 #include "test/opt/pass_fixture.h"
18 #include "test/opt/pass_utils.h"
19
20 namespace spvtools {
21 namespace opt {
22 namespace {
23
24 using WrapOpKillTest = PassTest<::testing::Test>;
25
TEST_F(WrapOpKillTest,SingleOpKill)26 TEST_F(WrapOpKillTest, SingleOpKill) {
27 const std::string text = R"(
28 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
29 ; CHECK: [[main]] = OpFunction
30 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
31 ; CHECK: [[orig_kill]] = OpFunction
32 ; CHECK-NEXT: OpLabel
33 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
34 ; CHECK-NEXT: OpReturn
35 ; CHECK: [[new_kill]] = OpFunction
36 ; CHECK-NEXT: OpLabel
37 ; CHECK-NEXT: OpKill
38 ; CHECK-NEXT: OpFunctionEnd
39 OpCapability Shader
40 %1 = OpExtInstImport "GLSL.std.450"
41 OpMemoryModel Logical GLSL450
42 OpEntryPoint Fragment %main "main"
43 OpExecutionMode %main OriginUpperLeft
44 OpSource GLSL 330
45 OpName %main "main"
46 %void = OpTypeVoid
47 %5 = OpTypeFunction %void
48 %bool = OpTypeBool
49 %true = OpConstantTrue %bool
50 %main = OpFunction %void None %5
51 %8 = OpLabel
52 OpBranch %9
53 %9 = OpLabel
54 OpLoopMerge %10 %11 None
55 OpBranch %12
56 %12 = OpLabel
57 OpBranchConditional %true %13 %10
58 %13 = OpLabel
59 OpBranch %11
60 %11 = OpLabel
61 %14 = OpFunctionCall %void %kill_
62 OpBranch %9
63 %10 = OpLabel
64 OpReturn
65 OpFunctionEnd
66 %kill_ = OpFunction %void None %5
67 %15 = OpLabel
68 OpKill
69 OpFunctionEnd
70 )";
71
72 SinglePassRunAndMatch<WrapOpKill>(text, true);
73 }
74
TEST_F(WrapOpKillTest,MultipleOpKillInSameFunc)75 TEST_F(WrapOpKillTest, MultipleOpKillInSameFunc) {
76 const std::string text = R"(
77 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
78 ; CHECK: [[main]] = OpFunction
79 ; CHECK: OpFunctionCall %void [[orig_kill:%\w+]]
80 ; CHECK: [[orig_kill]] = OpFunction
81 ; CHECK-NEXT: OpLabel
82 ; CHECK-NEXT: OpSelectionMerge
83 ; CHECK-NEXT: OpBranchConditional
84 ; CHECK-NEXT: OpLabel
85 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
86 ; CHECK-NEXT: OpReturn
87 ; CHECK-NEXT: OpLabel
88 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
89 ; CHECK-NEXT: OpReturn
90 ; CHECK: [[new_kill]] = OpFunction
91 ; CHECK-NEXT: OpLabel
92 ; CHECK-NEXT: OpKill
93 ; CHECK-NEXT: OpFunctionEnd
94 OpCapability Shader
95 %1 = OpExtInstImport "GLSL.std.450"
96 OpMemoryModel Logical GLSL450
97 OpEntryPoint Fragment %main "main"
98 OpExecutionMode %main OriginUpperLeft
99 OpSource GLSL 330
100 OpName %main "main"
101 %void = OpTypeVoid
102 %5 = OpTypeFunction %void
103 %bool = OpTypeBool
104 %true = OpConstantTrue %bool
105 %main = OpFunction %void None %5
106 %8 = OpLabel
107 OpBranch %9
108 %9 = OpLabel
109 OpLoopMerge %10 %11 None
110 OpBranch %12
111 %12 = OpLabel
112 OpBranchConditional %true %13 %10
113 %13 = OpLabel
114 OpBranch %11
115 %11 = OpLabel
116 %14 = OpFunctionCall %void %kill_
117 OpBranch %9
118 %10 = OpLabel
119 OpReturn
120 OpFunctionEnd
121 %kill_ = OpFunction %void None %5
122 %15 = OpLabel
123 OpSelectionMerge %16 None
124 OpBranchConditional %true %17 %18
125 %17 = OpLabel
126 OpKill
127 %18 = OpLabel
128 OpKill
129 %16 = OpLabel
130 OpReturn
131 OpFunctionEnd
132 )";
133
134 SinglePassRunAndMatch<WrapOpKill>(text, true);
135 }
136
TEST_F(WrapOpKillTest,MultipleOpKillInDifferentFunc)137 TEST_F(WrapOpKillTest, MultipleOpKillInDifferentFunc) {
138 const std::string text = R"(
139 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
140 ; CHECK: [[main]] = OpFunction
141 ; CHECK: OpFunctionCall %void [[orig_kill1:%\w+]]
142 ; CHECK-NEXT: OpFunctionCall %void [[orig_kill2:%\w+]]
143 ; CHECK: [[orig_kill1]] = OpFunction
144 ; CHECK-NEXT: OpLabel
145 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
146 ; CHECK-NEXT: OpReturn
147 ; CHECK: [[orig_kill2]] = OpFunction
148 ; CHECK-NEXT: OpLabel
149 ; CHECK-NEXT: OpFunctionCall %void [[new_kill]]
150 ; CHECK-NEXT: OpReturn
151 ; CHECK: [[new_kill]] = OpFunction
152 ; CHECK-NEXT: OpLabel
153 ; CHECK-NEXT: OpKill
154 ; CHECK-NEXT: OpFunctionEnd
155 OpCapability Shader
156 %1 = OpExtInstImport "GLSL.std.450"
157 OpMemoryModel Logical GLSL450
158 OpEntryPoint Fragment %main "main"
159 OpExecutionMode %main OriginUpperLeft
160 OpSource GLSL 330
161 OpName %main "main"
162 %void = OpTypeVoid
163 %4 = OpTypeFunction %void
164 %bool = OpTypeBool
165 %true = OpConstantTrue %bool
166 %main = OpFunction %void None %4
167 %7 = OpLabel
168 OpBranch %8
169 %8 = OpLabel
170 OpLoopMerge %9 %10 None
171 OpBranch %11
172 %11 = OpLabel
173 OpBranchConditional %true %12 %9
174 %12 = OpLabel
175 OpBranch %10
176 %10 = OpLabel
177 %13 = OpFunctionCall %void %14
178 %15 = OpFunctionCall %void %16
179 OpBranch %8
180 %9 = OpLabel
181 OpReturn
182 OpFunctionEnd
183 %14 = OpFunction %void None %4
184 %17 = OpLabel
185 OpKill
186 OpFunctionEnd
187 %16 = OpFunction %void None %4
188 %18 = OpLabel
189 OpKill
190 OpFunctionEnd
191 )";
192
193 SinglePassRunAndMatch<WrapOpKill>(text, true);
194 }
195
TEST_F(WrapOpKillTest,FuncWithReturnValue)196 TEST_F(WrapOpKillTest, FuncWithReturnValue) {
197 const std::string text = R"(
198 ; CHECK: OpEntryPoint Fragment [[main:%\w+]]
199 ; CHECK: [[main]] = OpFunction
200 ; CHECK: OpFunctionCall %int [[orig_kill:%\w+]]
201 ; CHECK: [[orig_kill]] = OpFunction
202 ; CHECK-NEXT: OpLabel
203 ; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
204 ; CHECK-NEXT: [[undef:%\w+]] = OpUndef %int
205 ; CHECK-NEXT: OpReturnValue [[undef]]
206 ; CHECK: [[new_kill]] = OpFunction
207 ; CHECK-NEXT: OpLabel
208 ; CHECK-NEXT: OpKill
209 ; CHECK-NEXT: OpFunctionEnd
210 OpCapability Shader
211 %1 = OpExtInstImport "GLSL.std.450"
212 OpMemoryModel Logical GLSL450
213 OpEntryPoint Fragment %main "main"
214 OpExecutionMode %main OriginUpperLeft
215 OpSource GLSL 330
216 OpName %main "main"
217 %void = OpTypeVoid
218 %5 = OpTypeFunction %void
219 %int = OpTypeInt 32 1
220 %func_type = OpTypeFunction %int
221 %bool = OpTypeBool
222 %true = OpConstantTrue %bool
223 %main = OpFunction %void None %5
224 %8 = OpLabel
225 OpBranch %9
226 %9 = OpLabel
227 OpLoopMerge %10 %11 None
228 OpBranch %12
229 %12 = OpLabel
230 OpBranchConditional %true %13 %10
231 %13 = OpLabel
232 OpBranch %11
233 %11 = OpLabel
234 %14 = OpFunctionCall %int %kill_
235 OpBranch %9
236 %10 = OpLabel
237 OpReturn
238 OpFunctionEnd
239 %kill_ = OpFunction %int None %func_type
240 %15 = OpLabel
241 OpKill
242 OpFunctionEnd
243 )";
244
245 SinglePassRunAndMatch<WrapOpKill>(text, true);
246 }
247
TEST_F(WrapOpKillTest,IdBoundOverflow1)248 TEST_F(WrapOpKillTest, IdBoundOverflow1) {
249 const std::string text = R"(
250 OpCapability GeometryStreams
251 OpMemoryModel Logical GLSL450
252 OpEntryPoint Fragment %main "main"
253 OpExecutionMode %main OriginUpperLeft
254 %2 = OpTypeVoid
255 %3 = OpTypeFunction %2
256 %bool = OpTypeBool
257 %true = OpConstantTrue %bool
258 %main = OpFunction %2 None %3
259 %8 = OpLabel
260 OpBranch %9
261 %9 = OpLabel
262 OpLoopMerge %10 %11 None
263 OpBranch %12
264 %12 = OpLabel
265 OpBranchConditional %true %13 %10
266 %13 = OpLabel
267 OpBranch %11
268 %11 = OpLabel
269 %14 = OpFunctionCall %void %kill_
270 OpBranch %9
271 %10 = OpLabel
272 OpReturn
273 OpFunctionEnd
274 %kill_ = OpFunction %2 Pure|Const %3
275 %4194302 = OpLabel
276 OpKill
277 OpFunctionEnd
278 )";
279
280 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
281
282 std::vector<Message> messages = {
283 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
284 SetMessageConsumer(GetTestMessageConsumer(messages));
285 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
286 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
287 }
288
TEST_F(WrapOpKillTest,IdBoundOverflow2)289 TEST_F(WrapOpKillTest, IdBoundOverflow2) {
290 const std::string text = R"(
291 OpCapability GeometryStreams
292 OpMemoryModel Logical GLSL450
293 OpEntryPoint Fragment %main "main"
294 OpExecutionMode %main OriginUpperLeft
295 %2 = OpTypeVoid
296 %3 = OpTypeFunction %2
297 %bool = OpTypeBool
298 %true = OpConstantTrue %bool
299 %main = OpFunction %2 None %3
300 %8 = OpLabel
301 OpBranch %9
302 %9 = OpLabel
303 OpLoopMerge %10 %11 None
304 OpBranch %12
305 %12 = OpLabel
306 OpBranchConditional %true %13 %10
307 %13 = OpLabel
308 OpBranch %11
309 %11 = OpLabel
310 %14 = OpFunctionCall %void %kill_
311 OpBranch %9
312 %10 = OpLabel
313 OpReturn
314 OpFunctionEnd
315 %kill_ = OpFunction %2 Pure|Const %3
316 %4194301 = OpLabel
317 OpKill
318 OpFunctionEnd
319 )";
320
321 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
322
323 std::vector<Message> messages = {
324 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
325 SetMessageConsumer(GetTestMessageConsumer(messages));
326 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
327 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
328 }
329
TEST_F(WrapOpKillTest,IdBoundOverflow3)330 TEST_F(WrapOpKillTest, IdBoundOverflow3) {
331 const std::string text = R"(
332 OpCapability GeometryStreams
333 OpMemoryModel Logical GLSL450
334 OpEntryPoint Fragment %main "main"
335 OpExecutionMode %main OriginUpperLeft
336 %2 = OpTypeVoid
337 %3 = OpTypeFunction %2
338 %bool = OpTypeBool
339 %true = OpConstantTrue %bool
340 %main = OpFunction %2 None %3
341 %8 = OpLabel
342 OpBranch %9
343 %9 = OpLabel
344 OpLoopMerge %10 %11 None
345 OpBranch %12
346 %12 = OpLabel
347 OpBranchConditional %true %13 %10
348 %13 = OpLabel
349 OpBranch %11
350 %11 = OpLabel
351 %14 = OpFunctionCall %void %kill_
352 OpBranch %9
353 %10 = OpLabel
354 OpReturn
355 OpFunctionEnd
356 %kill_ = OpFunction %2 Pure|Const %3
357 %4194300 = OpLabel
358 OpKill
359 OpFunctionEnd
360 )";
361
362 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
363
364 std::vector<Message> messages = {
365 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
366 SetMessageConsumer(GetTestMessageConsumer(messages));
367 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
368 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
369 }
370
TEST_F(WrapOpKillTest,IdBoundOverflow4)371 TEST_F(WrapOpKillTest, IdBoundOverflow4) {
372 const std::string text = R"(
373 OpCapability DerivativeControl
374 OpMemoryModel Logical GLSL450
375 OpEntryPoint Fragment %main "main"
376 OpExecutionMode %main OriginUpperLeft
377 OpDecorate %2 Location 539091968
378 %2 = OpTypeVoid
379 %3 = OpTypeFunction %2
380 %bool = OpTypeBool
381 %true = OpConstantTrue %bool
382 %main = OpFunction %2 None %3
383 %8 = OpLabel
384 OpBranch %9
385 %9 = OpLabel
386 OpLoopMerge %10 %11 None
387 OpBranch %12
388 %12 = OpLabel
389 OpBranchConditional %true %13 %10
390 %13 = OpLabel
391 OpBranch %11
392 %11 = OpLabel
393 %14 = OpFunctionCall %void %kill_
394 OpBranch %9
395 %10 = OpLabel
396 OpReturn
397 OpFunctionEnd
398 %kill_ = OpFunction %2 Inline|Pure|Const %3
399 %4194302 = OpLabel
400 OpKill
401 OpFunctionEnd
402 )";
403
404 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
405
406 std::vector<Message> messages = {
407 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
408 SetMessageConsumer(GetTestMessageConsumer(messages));
409 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
410 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
411 }
412
TEST_F(WrapOpKillTest,IdBoundOverflow5)413 TEST_F(WrapOpKillTest, IdBoundOverflow5) {
414 const std::string text = R"(
415 OpCapability Shader
416 OpMemoryModel Logical GLSL450
417 OpEntryPoint Fragment %1 "main"
418 OpExecutionMode %1 OriginUpperLeft
419 OpDecorate %void Location 539091968
420 %void = OpTypeVoid
421 %3 = OpTypeFunction %void
422 %float = OpTypeFloat 32
423 %_struct_5 = OpTypeStruct %float %float
424 %_struct_6 = OpTypeStruct %_struct_5
425 %_ptr_Function__struct_6 = OpTypePointer Function %_struct_6
426 %_ptr_Output_float = OpTypePointer Output %float
427 %9 = OpTypeFunction %_struct_5 %_ptr_Function__struct_6
428 %bool = OpTypeBool
429 %true = OpConstantTrue %bool
430 %1 = OpFunction %void None %3
431 %12 = OpLabel
432 %13 = OpVariable %_ptr_Function__struct_6 Function
433 OpBranch %14
434 %14 = OpLabel
435 OpLoopMerge %15 %16 None
436 OpBranch %17
437 %17 = OpLabel
438 OpBranchConditional %true %18 %15
439 %18 = OpLabel
440 OpBranch %16
441 %16 = OpLabel
442 %19 = OpFunctionCall %void %20
443 %21 = OpFunctionCall %_struct_5 %22 %13
444 OpBranch %14
445 %15 = OpLabel
446 OpReturn
447 OpFunctionEnd
448 %20 = OpFunction %void Inline|Pure|Const %3
449 %23 = OpLabel
450 %24 = OpVariable %_ptr_Function__struct_6 Function
451 %25 = OpFunctionCall %_struct_5 %26 %24
452 OpKill
453 OpFunctionEnd
454 %26 = OpFunction %_struct_5 None %9
455 %27 = OpLabel
456 OpUnreachable
457 OpFunctionEnd
458 %22 = OpFunction %_struct_5 Inline %9
459 %4194295 = OpLabel
460 OpKill
461 OpFunctionEnd
462 )";
463
464 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
465
466 std::vector<Message> messages = {
467 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
468 SetMessageConsumer(GetTestMessageConsumer(messages));
469 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
470 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
471 }
472
TEST_F(WrapOpKillTest,SkipEntryPoint)473 TEST_F(WrapOpKillTest, SkipEntryPoint) {
474 const std::string text = R"(
475 OpCapability GeometryStreams
476 OpMemoryModel Logical GLSL450
477 OpEntryPoint Fragment %4 "main"
478 OpExecutionMode %4 OriginUpperLeft
479 %2 = OpTypeVoid
480 %3 = OpTypeFunction %2
481 %4 = OpFunction %2 Pure|Const %3
482 %5 = OpLabel
483 OpKill
484 OpFunctionEnd
485 )";
486
487 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
488 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
489 }
490
TEST_F(WrapOpKillTest,SkipFunctionNotInContinue)491 TEST_F(WrapOpKillTest, SkipFunctionNotInContinue) {
492 const std::string text = R"(
493 OpCapability GeometryStreams
494 OpMemoryModel Logical GLSL450
495 OpEntryPoint Fragment %main "main"
496 OpExecutionMode %main OriginUpperLeft
497 %2 = OpTypeVoid
498 %3 = OpTypeFunction %2
499 %bool = OpTypeBool
500 %true = OpConstantTrue %bool
501 %main = OpFunction %2 None %3
502 %6 = OpLabel
503 %7 = OpFunctionCall %void %4
504 OpReturn
505 OpFunctionEnd
506 %4 = OpFunction %2 Pure|Const %3
507 %5 = OpLabel
508 OpKill
509 OpFunctionEnd
510 )";
511
512 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
513 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
514 }
515
TEST_F(WrapOpKillTest,SetParentBlock)516 TEST_F(WrapOpKillTest, SetParentBlock) {
517 const std::string text = R"(
518 OpCapability Shader
519 OpMemoryModel Logical GLSL450
520 OpEntryPoint Fragment %main "main"
521 OpExecutionMode %main OriginUpperLeft
522 %void = OpTypeVoid
523 %bool = OpTypeBool
524 %undef = OpUndef %bool
525 %void_fn = OpTypeFunction %void
526 %main = OpFunction %void None %void_fn
527 %entry = OpLabel
528 OpBranch %loop
529 %loop = OpLabel
530 OpLoopMerge %merge %continue None
531 OpBranchConditional %undef %merge %continue
532 %continue = OpLabel
533 %call = OpFunctionCall %void %kill_func
534 OpBranch %loop
535 %merge = OpLabel
536 OpReturn
537 OpFunctionEnd
538 %kill_func = OpFunction %void None %void_fn
539 %kill_entry = OpLabel
540 OpKill
541 OpFunctionEnd
542 )";
543
544 auto result = SinglePassRunToBinary<WrapOpKill>(text, true);
545 EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
546 result = SinglePassRunToBinary<WrapOpKill>(text, true);
547 EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
548 }
549
550 } // namespace
551 } // namespace opt
552 } // namespace spvtools
553