1 // Copyright (c) 2023 Google 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 #include "spirv-tools/optimizer.hpp"
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 InterlockInvocationPlacementTest = PassTest<::testing::Test>;
24
TEST_F(InterlockInvocationPlacementTest,CheckUnchangedIfNotFragment)25 TEST_F(InterlockInvocationPlacementTest, CheckUnchangedIfNotFragment) {
26 const std::string kTest = R"(
27 OpCapability Shader
28 OpCapability FragmentShaderSampleInterlockEXT
29 OpExtension "SPV_EXT_fragment_shader_interlock"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Vertex %main "main"
32 OpExecutionMode %main SampleInterlockOrderedEXT
33 OpName %main "main"
34 %void = OpTypeVoid
35 %1 = OpTypeFunction %void
36 %main = OpFunction %void None %1
37 %2 = OpLabel
38 OpBeginInvocationInterlockEXT
39 OpBeginInvocationInterlockEXT
40 OpEndInvocationInterlockEXT
41 OpBeginInvocationInterlockEXT
42 OpEndInvocationInterlockEXT
43 OpReturn
44 OpFunctionEnd
45 )";
46 SetTargetEnv(SPV_ENV_VULKAN_1_3);
47 EXPECT_EQ(
48 Pass::Status::SuccessWithoutChange,
49 std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
50 kTest, /* skip_nop= */ false, /* do_validation= */ false)));
51 }
52
TEST_F(InterlockInvocationPlacementTest,CheckUnchangedWithoutCapability)53 TEST_F(InterlockInvocationPlacementTest, CheckUnchangedWithoutCapability) {
54 const std::string kTest = R"(
55 OpCapability Shader
56 OpExtension "SPV_EXT_fragment_shader_interlock"
57 OpMemoryModel Logical GLSL450
58 OpEntryPoint Fragment %main "main"
59 OpExecutionMode %main OriginUpperLeft
60 OpExecutionMode %main SampleInterlockOrderedEXT
61 OpName %main "main"
62 %void = OpTypeVoid
63 %1 = OpTypeFunction %void
64 %main = OpFunction %void None %1
65 %2 = OpLabel
66 OpBeginInvocationInterlockEXT
67 OpBeginInvocationInterlockEXT
68 OpEndInvocationInterlockEXT
69 OpBeginInvocationInterlockEXT
70 OpEndInvocationInterlockEXT
71 OpReturn
72 OpFunctionEnd
73 )";
74 SetTargetEnv(SPV_ENV_VULKAN_1_3);
75 EXPECT_EQ(
76 Pass::Status::SuccessWithoutChange,
77 std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
78 kTest, /* skip_nop= */ false, /* do_validation= */ false)));
79 }
80
TEST_F(InterlockInvocationPlacementTest,CheckSingleBasicBlock)81 TEST_F(InterlockInvocationPlacementTest, CheckSingleBasicBlock) {
82 // We're using OpNoLine as a generic standin for any other instruction, to
83 // test that begin and end aren't moved.
84 const std::string kTest = R"(
85 OpCapability Shader
86 OpCapability FragmentShaderSampleInterlockEXT
87 OpExtension "SPV_EXT_fragment_shader_interlock"
88 OpMemoryModel Logical GLSL450
89 OpEntryPoint Fragment %main "main"
90 OpExecutionMode %main OriginUpperLeft
91 OpExecutionMode %main SampleInterlockOrderedEXT
92 OpName %main "main"
93 %void = OpTypeVoid
94 %1 = OpTypeFunction %void
95 %main = OpFunction %void None %1
96 ; CHECK: OpLabel
97 %2 = OpLabel
98 ; CHECK-NEXT: OpNoLine
99 OpNoLine
100 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
101 OpBeginInvocationInterlockEXT
102 OpBeginInvocationInterlockEXT
103 OpEndInvocationInterlockEXT
104 OpBeginInvocationInterlockEXT
105 ; CHECK-NEXT: OpNoLine
106 OpNoLine
107 ; CHECK-NEXT: OpEndInvocationInterlockEXT
108 OpEndInvocationInterlockEXT
109 ; CHECK-NEXT: OpNoLine
110 OpNoLine
111 ; CHECK-NEXT: OpReturn
112 OpReturn
113 OpFunctionEnd
114 )";
115 SetTargetEnv(SPV_ENV_VULKAN_1_3);
116 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
117 kTest, /* skip_nop= */ false);
118 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
119 }
120
TEST_F(InterlockInvocationPlacementTest,CheckFunctionCallExtractionBegin)121 TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionBegin) {
122 const std::string kTest = R"(
123 OpCapability Shader
124 OpCapability FragmentShaderSampleInterlockEXT
125 OpExtension "SPV_EXT_fragment_shader_interlock"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint Fragment %main "main"
128 OpExecutionMode %main OriginUpperLeft
129 OpExecutionMode %main SampleInterlockOrderedEXT
130 OpName %main "main"
131 %void = OpTypeVoid
132 %1 = OpTypeFunction %void
133 %foo = OpFunction %void None %1
134 ; CHECK: OpLabel
135 ; CHECK-NOT: OpBeginInvocationInterlockEXT
136 %2 = OpLabel
137 OpBeginInvocationInterlockEXT
138 OpBeginInvocationInterlockEXT
139 OpReturn
140 ; CHECK: OpFunctionEnd
141 OpFunctionEnd
142 %main = OpFunction %void None %1
143 ; CHECK: OpLabel
144 %3 = OpLabel
145 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
146 ; CHECK-NEXT: OpFunctionCall
147 %4 = OpFunctionCall %void %foo
148 ; CHECK-NEXT: OpReturn
149 OpReturn
150 OpFunctionEnd
151 )";
152 SetTargetEnv(SPV_ENV_VULKAN_1_3);
153 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
154 kTest, /* skip_nop= */ false);
155 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
156 }
157
TEST_F(InterlockInvocationPlacementTest,CheckFunctionCallExtractionEnd)158 TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionEnd) {
159 const std::string kTest = R"(
160 OpCapability Shader
161 OpCapability FragmentShaderSampleInterlockEXT
162 OpExtension "SPV_EXT_fragment_shader_interlock"
163 OpMemoryModel Logical GLSL450
164 OpEntryPoint Fragment %main "main"
165 OpExecutionMode %main OriginUpperLeft
166 OpExecutionMode %main SampleInterlockOrderedEXT
167 OpName %main "main"
168 %void = OpTypeVoid
169 %1 = OpTypeFunction %void
170 %foo = OpFunction %void None %1
171 ; CHECK: OpLabel
172 ; CHECK-NOT: OpEndInvocationInterlockEXT
173 %2 = OpLabel
174 OpEndInvocationInterlockEXT
175 OpEndInvocationInterlockEXT
176 OpReturn
177 ; CHECK: OpFunctionEnd
178 OpFunctionEnd
179 %main = OpFunction %void None %1
180 ; CHECK: OpLabel
181 %3 = OpLabel
182 ; CHECK-NEXT: OpFunctionCall
183 %4 = OpFunctionCall %void %foo
184 ; CHECK-NEXT: OpEndInvocationInterlockEXT
185 ; CHECK-NEXT: OpReturn
186 OpReturn
187 OpFunctionEnd
188 )";
189 SetTargetEnv(SPV_ENV_VULKAN_1_3);
190 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
191 kTest, /* skip_nop= */ false);
192 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
193 }
194
TEST_F(InterlockInvocationPlacementTest,CheckFunctionCallExtractionRepeatedCall)195 TEST_F(InterlockInvocationPlacementTest,
196 CheckFunctionCallExtractionRepeatedCall) {
197 const std::string kTest = R"(
198 OpCapability Shader
199 OpCapability FragmentShaderSampleInterlockEXT
200 OpExtension "SPV_EXT_fragment_shader_interlock"
201 OpMemoryModel Logical GLSL450
202 OpEntryPoint Fragment %main "main"
203 OpExecutionMode %main OriginUpperLeft
204 OpExecutionMode %main SampleInterlockOrderedEXT
205 OpName %main "main"
206 %void = OpTypeVoid
207 %1 = OpTypeFunction %void
208 %foo = OpFunction %void None %1
209 ; CHECK: OpLabel
210 ; CHECK-NOT: OpBeginInvocationInterlockEXT
211 ; CHECK-NOT: OpEndInvocationInterlockEXT
212 %2 = OpLabel
213 OpBeginInvocationInterlockEXT
214 OpEndInvocationInterlockEXT
215 OpReturn
216 ; CHECK: OpFunctionEnd
217 OpFunctionEnd
218 %main = OpFunction %void None %1
219 ; CHECK: OpLabel
220 %3 = OpLabel
221 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
222 ; CHECK-NEXT: OpFunctionCall
223 %4 = OpFunctionCall %void %foo
224 ; CHECK-NEXT: OpFunctionCall
225 %5 = OpFunctionCall %void %foo
226 ; CHECK-NEXT: OpEndInvocationInterlockEXT
227 ; CHECK-NEXT: OpReturn
228 OpReturn
229 OpFunctionEnd
230 )";
231 SetTargetEnv(SPV_ENV_VULKAN_1_3);
232 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
233 kTest, /* skip_nop= */ false);
234 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
235 }
236
TEST_F(InterlockInvocationPlacementTest,CheckFunctionCallExtractionNestedCall)237 TEST_F(InterlockInvocationPlacementTest,
238 CheckFunctionCallExtractionNestedCall) {
239 const std::string kTest = R"(
240 OpCapability Shader
241 OpCapability FragmentShaderSampleInterlockEXT
242 OpExtension "SPV_EXT_fragment_shader_interlock"
243 OpMemoryModel Logical GLSL450
244 OpEntryPoint Fragment %main "main"
245 OpExecutionMode %main OriginUpperLeft
246 OpExecutionMode %main SampleInterlockOrderedEXT
247 OpName %main "main"
248 %void = OpTypeVoid
249 %1 = OpTypeFunction %void
250 %foo = OpFunction %void None %1
251 ; CHECK: OpLabel
252 ; CHECK-NOT: OpBeginInvocationInterlockEXT
253 ; CHECK-NOT: OpEndInvocationInterlockEXT
254 %2 = OpLabel
255 OpBeginInvocationInterlockEXT
256 OpEndInvocationInterlockEXT
257 OpReturn
258 ; CHECK: OpFunctionEnd
259 OpFunctionEnd
260 %bar = OpFunction %void None %1
261 ; CHECK: OpLabel
262 ; CHECK-NOT: OpBeginInvocationInterlockEXT
263 ; CHECK-NOT: OpEndInvocationInterlockEXT
264 %3 = OpLabel
265 %4 = OpFunctionCall %void %foo
266 OpReturn
267 ; CHECK: OpFunctionEnd
268 OpFunctionEnd
269 %main = OpFunction %void None %1
270 ; CHECK: OpLabel
271 %5 = OpLabel
272 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
273 ; CHECK-NEXT: OpFunctionCall
274 %6 = OpFunctionCall %void %bar
275 ; CHECK-NEXT: OpEndInvocationInterlockEXT
276 ; CHECK-NEXT: OpReturn
277 OpReturn
278 OpFunctionEnd
279 )";
280 SetTargetEnv(SPV_ENV_VULKAN_1_3);
281 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
282 kTest, /* skip_nop= */ false);
283 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
284 }
285
TEST_F(InterlockInvocationPlacementTest,CheckLoopExtraction)286 TEST_F(InterlockInvocationPlacementTest, CheckLoopExtraction) {
287 // Tests that any begin or end instructions in a loop are moved outside of the
288 // loop.
289 const std::string kTest = R"(
290 OpCapability Shader
291 OpCapability FragmentShaderSampleInterlockEXT
292 OpExtension "SPV_EXT_fragment_shader_interlock"
293 OpMemoryModel Logical GLSL450
294 OpEntryPoint Fragment %main "main"
295 OpExecutionMode %main OriginUpperLeft
296 OpExecutionMode %main SampleInterlockOrderedEXT
297 %void = OpTypeVoid
298 %bool = OpTypeBool
299 %true = OpConstantTrue %bool
300 %1 = OpTypeFunction %void
301 %main = OpFunction %void None %1
302
303 %2 = OpLabel
304 ; CHECK: OpBeginInvocationInterlockEXT
305 ; CHECK-NOT: OpBeginInvocationInterlockEXT
306 ; CHECK-NOT: OpEndInvocationInterlockEXT
307 OpBranch %3
308
309 %3 = OpLabel
310 OpLoopMerge %3 %4 None
311 ; CHECK: OpBranchConditional
312 ; CHECK-NOT: OpBeginInvocationInterlockEXT
313 ; CHECK-NOT: OpEndInvocationInterlockEXT
314 OpBranchConditional %true %4 %5
315
316 %4 = OpLabel
317 OpBeginInvocationInterlockEXT
318 OpEndInvocationInterlockEXT
319 ; CHECK: OpBranch
320 OpBranch %3
321
322 ; CHECK-NEXT: OpLabel
323 %5 = OpLabel
324 ; CHECK-NEXT: OpEndInvocationInterlockEXT
325 ; CHECK-NOT: OpEndInvocationInterlockEXT
326 OpEndInvocationInterlockEXT
327 OpReturn
328 OpFunctionEnd
329 )";
330 SetTargetEnv(SPV_ENV_VULKAN_1_3);
331 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
332 kTest, /* skip_nop= */ false);
333 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
334 }
335
TEST_F(InterlockInvocationPlacementTest,CheckAddBeginToElse)336 TEST_F(InterlockInvocationPlacementTest, CheckAddBeginToElse) {
337 // Test that if there is a begin in a single branch of a conditional, begin
338 // will be added to the other branch.
339 const std::string kTest = R"(
340 OpCapability Shader
341 OpCapability FragmentShaderSampleInterlockEXT
342 OpExtension "SPV_EXT_fragment_shader_interlock"
343 OpMemoryModel Logical GLSL450
344 OpEntryPoint Fragment %main "main"
345 OpExecutionMode %main OriginUpperLeft
346 OpExecutionMode %main SampleInterlockOrderedEXT
347 OpName %main "main"
348 %void = OpTypeVoid
349 %bool = OpTypeBool
350 %true = OpConstantTrue %bool
351 %1 = OpTypeFunction %void
352 %main = OpFunction %void None %1
353
354 %2 = OpLabel
355 ; CHECK-NOT: OpBeginInvocationInterlockEXT
356 OpSelectionMerge %5 None
357 ; CHECK: OpBranchConditional
358 OpBranchConditional %true %3 %4
359
360 ; CHECK-NEXT: OpLabel
361 %3 = OpLabel
362 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
363 OpBeginInvocationInterlockEXT
364 OpEndInvocationInterlockEXT
365 ; CHECK-NEXT: OpBranch
366 OpBranch %5
367
368 %4 = OpLabel
369 ; CHECK: OpBeginInvocationInterlockEXT
370 ; CHECK-NEXT: OpBranch
371 OpBranch %5
372
373 ; CHECK-NEXT: OpLabel
374 %5 = OpLabel
375 OpBeginInvocationInterlockEXT
376 ; CHECK-NEXT: OpEndInvocationInterlockEXT
377 OpEndInvocationInterlockEXT
378 OpReturn
379 OpFunctionEnd
380 )";
381 SetTargetEnv(SPV_ENV_VULKAN_1_3);
382 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
383 kTest, /* skip_nop= */ false);
384 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
385 }
386
TEST_F(InterlockInvocationPlacementTest,CheckAddEndToElse)387 TEST_F(InterlockInvocationPlacementTest, CheckAddEndToElse) {
388 const std::string kTest = R"(
389 OpCapability Shader
390 OpCapability FragmentShaderSampleInterlockEXT
391 OpExtension "SPV_EXT_fragment_shader_interlock"
392 OpMemoryModel Logical GLSL450
393 OpEntryPoint Fragment %main "main"
394 OpExecutionMode %main OriginUpperLeft
395 OpExecutionMode %main SampleInterlockOrderedEXT
396 OpName %main "main"
397 %void = OpTypeVoid
398 %bool = OpTypeBool
399 %true = OpConstantTrue %bool
400 %1 = OpTypeFunction %void
401 %main = OpFunction %void None %1
402
403 %2 = OpLabel
404 ; CHECK: OpBeginInvocationInterlockEXT
405 OpBeginInvocationInterlockEXT
406 ; CHECK-NOT: OpEndInvocationInterlockEXT
407 OpEndInvocationInterlockEXT
408 OpSelectionMerge %5 None
409 ; CHECK: OpBranchConditional
410 OpBranchConditional %true %3 %4
411
412 ; CHECK-NEXT: OpLabel
413 %3 = OpLabel
414 OpBeginInvocationInterlockEXT
415 ; CHECK-NEXT: OpEndInvocationInterlockEXT
416 OpEndInvocationInterlockEXT
417 ; CHECK-NEXT: OpBranch
418 OpBranch %5
419
420 %4 = OpLabel
421 ; CHECK: OpEndInvocationInterlockEXT
422 ; CHECK-NEXT: OpBranch
423 OpBranch %5
424
425 ; CHECK-NEXT: OpLabel
426 %5 = OpLabel
427 ; CHECK-NOT: OpEndInvocationInterlockEXT
428 OpReturn
429 OpFunctionEnd
430 )";
431 SetTargetEnv(SPV_ENV_VULKAN_1_3);
432 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
433 kTest, /* skip_nop= */ false);
434 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
435 }
436
TEST_F(InterlockInvocationPlacementTest,CheckSplitIfWithoutElseBegin)437 TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseBegin) {
438 // Test that if there is a begin in the then branch of a conditional, and no
439 // else branch, an else branch with a begin will created.
440 const std::string kTest = R"(
441 OpCapability Shader
442 OpCapability FragmentShaderSampleInterlockEXT
443 OpExtension "SPV_EXT_fragment_shader_interlock"
444 OpMemoryModel Logical GLSL450
445 OpEntryPoint Fragment %main "main"
446 OpExecutionMode %main OriginUpperLeft
447 OpExecutionMode %main SampleInterlockOrderedEXT
448 OpName %main "main"
449 %void = OpTypeVoid
450 %bool = OpTypeBool
451 %true = OpConstantTrue %bool
452 %1 = OpTypeFunction %void
453 %main = OpFunction %void None %1
454
455 %2 = OpLabel
456 ; CHECK-NOT: OpBeginInvocationInterlockEXT
457 OpSelectionMerge %5 None
458 ; CHECK: OpBranchConditional
459 OpBranchConditional %true %3 %5
460
461 ; CHECK-NEXT: OpLabel
462 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
463 ; CHECK-NEXT: OpBranch
464
465 ; CHECK-NEXT: OpLabel
466 %3 = OpLabel
467 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
468 ; CHECK-NOT: OpEndInvocationInterlockEXT
469 OpBeginInvocationInterlockEXT
470 OpEndInvocationInterlockEXT
471 OpBranch %5
472
473 ; CHECK: OpLabel
474 %5 = OpLabel
475 ; CHECK-NOT: OpBeginInvocationInterlockEXT
476 OpBeginInvocationInterlockEXT
477 ; CHECK-NEXT: OpEndInvocationInterlockEXT
478 OpEndInvocationInterlockEXT
479 OpReturn
480 OpFunctionEnd
481 )";
482 SetTargetEnv(SPV_ENV_VULKAN_1_3);
483 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
484 kTest, /* skip_nop= */ false);
485 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
486 }
487
TEST_F(InterlockInvocationPlacementTest,CheckSplitIfWithoutElseEnd)488 TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseEnd) {
489 const std::string kTest = R"(
490 OpCapability Shader
491 OpCapability FragmentShaderSampleInterlockEXT
492 OpExtension "SPV_EXT_fragment_shader_interlock"
493 OpMemoryModel Logical GLSL450
494 OpEntryPoint Fragment %main "main"
495 OpExecutionMode %main OriginUpperLeft
496 OpExecutionMode %main SampleInterlockOrderedEXT
497 OpName %main "main"
498 %void = OpTypeVoid
499 %bool = OpTypeBool
500 %true = OpConstantTrue %bool
501 %1 = OpTypeFunction %void
502 %main = OpFunction %void None %1
503
504 %2 = OpLabel
505
506 ; CHECK: OpBeginInvocationInterlockEXT
507 OpBeginInvocationInterlockEXT
508 ; CHECK-NOT: OpEndInvocationInterlockEXT
509 OpEndInvocationInterlockEXT
510 ; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
511 OpSelectionMerge %5 None
512 ; CHECK-NEXT: OpBranchConditional %true [[then:%\d+]] [[else:%\d+]]
513 OpBranchConditional %true %3 %5
514
515 ; CHECK-NEXT: [[else]] = OpLabel
516 ; CHECK-NEXT: OpEndInvocationInterlockEXT
517 ; CHECK-NEXT: OpBranch [[merge]]
518
519 ; CHECK-NEXT: [[then]] = OpLabel
520 %3 = OpLabel
521 ; CHECK-NEXT: OpEndInvocationInterlockEXT
522 OpBeginInvocationInterlockEXT
523 OpEndInvocationInterlockEXT
524 ; CHECK-NEXT: OpBranch [[merge]]
525 OpBranch %5
526
527 ; CHECK-NEXT: [[merge]] = OpLabel
528 %5 = OpLabel
529 ; CHECK-NEXT: OpReturn
530 OpReturn
531 OpFunctionEnd
532 )";
533 SetTargetEnv(SPV_ENV_VULKAN_1_3);
534 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
535 kTest, /* skip_nop= */ false);
536 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
537 }
538
TEST_F(InterlockInvocationPlacementTest,CheckSplitSwitch)539 TEST_F(InterlockInvocationPlacementTest, CheckSplitSwitch) {
540 // Test that if there is a begin or end in a single branch of a switch, begin
541 // or end will be added to all the other branches.
542 const std::string kTest = R"(
543 OpCapability Shader
544 OpCapability FragmentShaderSampleInterlockEXT
545 OpExtension "SPV_EXT_fragment_shader_interlock"
546 OpMemoryModel Logical GLSL450
547 OpEntryPoint Fragment %main "main"
548 OpExecutionMode %main OriginUpperLeft
549 OpExecutionMode %main SampleInterlockOrderedEXT
550 OpName %main "main"
551 %void = OpTypeVoid
552 %uint = OpTypeInt 32 0
553 %uint_1 = OpConstant %uint 1
554 %1 = OpTypeFunction %void
555 %main = OpFunction %void None %1
556
557 ; CHECK: OpLabel
558 %2 = OpLabel
559 ; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
560 OpSelectionMerge %8 None
561 ; CHECK-NEXT: OpSwitch %uint_1 [[default:%\d+]] 0 [[case_0:%\d+]] 1 [[case_1:%\d+]] 2 [[case_2:%\d+]]
562 OpSwitch %uint_1 %8 0 %4 1 %5 2 %8
563
564 ; CHECK-NEXT: [[case_2]] = OpLabel
565 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
566 ; CHECK-NEXT: OpBranch [[merge]]
567
568 ; CHECK-NEXT: [[default]] = OpLabel
569 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
570 ; CHECK-NEXT: OpBranch [[merge]]
571
572 ; CHECK-NEXT: [[case_0]] = OpLabel
573 %4 = OpLabel
574 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
575 ; CHECK-NOT: OpEndInvocationInterlockEXT
576 OpBeginInvocationInterlockEXT
577 OpEndInvocationInterlockEXT
578 ; CHECK-NEXT: OpNoLine
579 OpNoLine
580 ; CHECK-NEXT: OpBranch [[merge]]
581 OpBranch %8
582
583 ; CHECK-NEXT: [[case_1]] = OpLabel
584 %5 = OpLabel
585 ; CHECK-NEXT: OpBeginInvocationInterlockEXT
586 ; CHECK-NOT: OpEndInvocationInterlockEXT
587 OpBeginInvocationInterlockEXT
588 OpEndInvocationInterlockEXT
589 ; CHECK-NEXT: OpNoLine
590 OpNoLine
591 ; CHECK-NEXT: OpNoLine
592 OpNoLine
593 ; CHECK-NEXT: OpBranch [[merge]]
594 OpBranch %8
595
596 ; CHECK-NEXT: [[merge]] = OpLabel
597 %8 = OpLabel
598 ; CHECK-NOT: OpBeginInvocationInterlockEXT
599 OpBeginInvocationInterlockEXT
600 ; CHECK-NEXT: OpEndInvocationInterlockEXT
601 OpEndInvocationInterlockEXT
602 OpReturn
603 OpFunctionEnd
604 )";
605 SetTargetEnv(SPV_ENV_VULKAN_1_3);
606 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
607 kTest, /* skip_nop= */ false);
608 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
609 }
610
611 } // namespace
612 } // namespace opt
613 } // namespace spvtools
614