• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
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 "src/reader/spirv/function.h"
17 #include "src/reader/spirv/parser_impl_test_helper.h"
18 #include "src/reader/spirv/spirv_tools_helpers_test.h"
19 
20 namespace tint {
21 namespace reader {
22 namespace spirv {
23 namespace {
24 
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27 
28 // Make a local name so it's easier to triage errors.
29 using SpvParserCFGTest = SpvParserTest;
30 
Dump(const std::vector<uint32_t> & v)31 std::string Dump(const std::vector<uint32_t>& v) {
32   std::ostringstream o;
33   o << "{";
34   for (auto a : v) {
35     o << a << " ";
36   }
37   o << "}";
38   return o.str();
39 }
40 
41 using ::testing::ElementsAre;
42 using ::testing::Eq;
43 using ::testing::UnorderedElementsAre;
44 
CommonTypes()45 std::string CommonTypes() {
46   return R"(
47     OpCapability Shader
48     OpMemoryModel Logical Simple
49     OpEntryPoint Fragment %100 "main"
50     OpExecutionMode %100 OriginUpperLeft
51 
52     OpName %var "var"
53 
54     %void = OpTypeVoid
55     %voidfn = OpTypeFunction %void
56 
57     %bool = OpTypeBool
58     %cond = OpConstantNull %bool
59     %cond2 = OpConstantTrue %bool
60     %cond3 = OpConstantFalse %bool
61 
62     %uint = OpTypeInt 32 0
63     %int = OpTypeInt 32 1
64     %selector = OpConstant %uint 42
65     %signed_selector = OpConstant %int 42
66 
67     %uintfn = OpTypeFunction %uint
68 
69     %uint_0 = OpConstant %uint 0
70     %uint_1 = OpConstant %uint 1
71     %uint_2 = OpConstant %uint 2
72     %uint_3 = OpConstant %uint 3
73     %uint_4 = OpConstant %uint 4
74     %uint_5 = OpConstant %uint 5
75     %uint_6 = OpConstant %uint 6
76     %uint_7 = OpConstant %uint 7
77     %uint_8 = OpConstant %uint 8
78     %uint_10 = OpConstant %uint 10
79     %uint_20 = OpConstant %uint 20
80     %uint_30 = OpConstant %uint 30
81     %uint_40 = OpConstant %uint 40
82     %uint_50 = OpConstant %uint 50
83     %uint_90 = OpConstant %uint 90
84     %uint_99 = OpConstant %uint 99
85 
86     %ptr_Private_uint = OpTypePointer Private %uint
87     %var = OpVariable %ptr_Private_uint Private
88 
89     %999 = OpConstant %uint 999
90   )";
91 }
92 
93 /// Runs the necessary flow until and including labeling control
94 /// flow constructs.
95 /// @returns the result of labeling control flow constructs.
FlowLabelControlFlowConstructs(FunctionEmitter * fe)96 bool FlowLabelControlFlowConstructs(FunctionEmitter* fe) {
97   fe->RegisterBasicBlocks();
98   EXPECT_TRUE(fe->RegisterMerges()) << fe->parser()->error();
99   fe->ComputeBlockOrderAndPositions();
100   EXPECT_TRUE(fe->VerifyHeaderContinueMergeOrder()) << fe->parser()->error();
101   return fe->LabelControlFlowConstructs();
102 }
103 
104 /// Runs the necessary flow until and including finding switch case
105 /// headers.
106 /// @returns the result of finding switch case headers.
FlowFindSwitchCaseHeaders(FunctionEmitter * fe)107 bool FlowFindSwitchCaseHeaders(FunctionEmitter* fe) {
108   EXPECT_TRUE(FlowLabelControlFlowConstructs(fe)) << fe->parser()->error();
109   return fe->FindSwitchCaseHeaders();
110 }
111 
112 /// Runs the necessary flow until and including classify CFG edges,
113 /// @returns the result of classify CFG edges.
FlowClassifyCFGEdges(FunctionEmitter * fe)114 bool FlowClassifyCFGEdges(FunctionEmitter* fe) {
115   EXPECT_TRUE(FlowFindSwitchCaseHeaders(fe)) << fe->parser()->error();
116   return fe->ClassifyCFGEdges();
117 }
118 
119 /// Runs the necessary flow until and including finding if-selection
120 /// internal headers.
121 /// @returns the result of classify CFG edges.
FlowFindIfSelectionInternalHeaders(FunctionEmitter * fe)122 bool FlowFindIfSelectionInternalHeaders(FunctionEmitter* fe) {
123   EXPECT_TRUE(FlowClassifyCFGEdges(fe)) << fe->parser()->error();
124   return fe->FindIfSelectionInternalHeaders();
125 }
126 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_SingleBlock)127 TEST_F(SpvParserCFGTest, TerminatorsAreValid_SingleBlock) {
128   auto p = parser(test::Assemble(CommonTypes() + R"(
129      %100 = OpFunction %void None %voidfn
130 
131      %42 = OpLabel
132      OpReturn
133 
134      OpFunctionEnd
135   )"));
136   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
137   auto fe = p->function_emitter(100);
138   fe.RegisterBasicBlocks();
139   EXPECT_TRUE(fe.TerminatorsAreValid());
140 }
141 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Sequence)142 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Sequence) {
143   auto p = parser(test::Assemble(CommonTypes() + R"(
144      %100 = OpFunction %void None %voidfn
145 
146      %20 = OpLabel
147      OpBranch %30
148 
149      %30 = OpLabel
150      OpReturn
151 
152      OpFunctionEnd
153   )"));
154   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
155   auto fe = p->function_emitter(100);
156   fe.RegisterBasicBlocks();
157   EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
158 }
159 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_If)160 TEST_F(SpvParserCFGTest, TerminatorsAreValid_If) {
161   auto p = parser(test::Assemble(CommonTypes() + R"(
162      %100 = OpFunction %void None %voidfn
163 
164      %20 = OpLabel
165      OpSelectionMerge %99 None
166      OpBranchConditional %cond %30 %40
167 
168      %30 = OpLabel
169      OpBranch %99
170 
171      %40 = OpLabel
172      OpBranch %99
173 
174      %99 = OpLabel
175      OpReturn
176 
177      OpFunctionEnd
178   )"));
179   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
180   auto fe = p->function_emitter(100);
181   fe.RegisterBasicBlocks();
182   EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
183 }
184 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Switch)185 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Switch) {
186   auto p = parser(test::Assemble(CommonTypes() + R"(
187      %100 = OpFunction %void None %voidfn
188 
189      %10 = OpLabel
190      OpSelectionMerge %99 None
191      OpSwitch %selector %80 20 %20 30 %30
192 
193      %20 = OpLabel
194      OpBranch %30 ; fall through
195 
196      %30 = OpLabel
197      OpBranch %99
198 
199      %80 = OpLabel
200      OpBranch %99
201 
202      %99 = OpLabel
203      OpReturn
204 
205      OpFunctionEnd
206   )"));
207   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
208   auto fe = p->function_emitter(100);
209   fe.RegisterBasicBlocks();
210   EXPECT_TRUE(fe.TerminatorsAreValid());
211 }
212 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Loop_SingleBlock)213 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Loop_SingleBlock) {
214   auto p = parser(test::Assemble(CommonTypes() + R"(
215      %100 = OpFunction %void None %voidfn
216 
217      %10 = OpLabel
218      OpBranch %20
219 
220      %20 = OpLabel
221      OpLoopMerge %99 %20 None
222      OpBranchConditional %cond %20 %99
223 
224      %99 = OpLabel
225      OpReturn
226 
227      OpFunctionEnd
228   )"));
229   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
230   auto fe = p->function_emitter(100);
231   fe.RegisterBasicBlocks();
232   EXPECT_TRUE(fe.TerminatorsAreValid());
233 }
234 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Loop_Simple)235 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Loop_Simple) {
236   auto p = parser(test::Assemble(CommonTypes() + R"(
237      %100 = OpFunction %void None %voidfn
238 
239      %10 = OpLabel
240      OpBranch %20
241 
242      %20 = OpLabel
243      OpLoopMerge %99 %40 None
244      OpBranchConditional %cond %30 %99
245 
246      %30 = OpLabel
247      OpBranch %40
248 
249      %40 = OpLabel
250      OpBranch %20 ; back edge
251 
252      %99 = OpLabel
253      OpReturn
254 
255      OpFunctionEnd
256   )"));
257   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
258   auto fe = p->function_emitter(100);
259   fe.RegisterBasicBlocks();
260   EXPECT_TRUE(fe.TerminatorsAreValid());
261 }
262 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Kill)263 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Kill) {
264   auto p = parser(test::Assemble(CommonTypes() + R"(
265      %100 = OpFunction %void None %voidfn
266 
267      %10 = OpLabel
268      OpKill
269 
270      OpFunctionEnd
271   )"));
272   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
273   auto fe = p->function_emitter(100);
274   fe.RegisterBasicBlocks();
275   EXPECT_TRUE(fe.TerminatorsAreValid());
276 }
277 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_Unreachable)278 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Unreachable) {
279   auto p = parser(test::Assemble(CommonTypes() + R"(
280      %100 = OpFunction %void None %voidfn
281 
282      %10 = OpLabel
283      OpUnreachable
284 
285      OpFunctionEnd
286   )"));
287   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
288   auto fe = p->function_emitter(100);
289   fe.RegisterBasicBlocks();
290   EXPECT_TRUE(fe.TerminatorsAreValid());
291 }
292 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_MissingTerminator)293 TEST_F(SpvParserCFGTest, TerminatorsAreValid_MissingTerminator) {
294   auto p = parser(test::Assemble(CommonTypes() + R"(
295      %100 = OpFunction %void None %voidfn
296 
297      %10 = OpLabel
298 
299      OpFunctionEnd
300   )"));
301   // The SPIRV-Tools internal representation rejects this case earlier.
302   EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
303 }
304 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_DisallowLoopToEntryBlock)305 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowLoopToEntryBlock) {
306   auto p = parser(test::Assemble(CommonTypes() + R"(
307      %100 = OpFunction %void None %voidfn
308 
309      %10 = OpLabel
310      OpBranch %20
311 
312      %20 = OpLabel
313      OpBranch %10 ; not allowed
314 
315      OpFunctionEnd
316   )"));
317   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
318   auto fe = p->function_emitter(100);
319   fe.RegisterBasicBlocks();
320   EXPECT_FALSE(fe.TerminatorsAreValid());
321   EXPECT_THAT(p->error(), Eq("Block 20 branches to function entry block 10"));
322 }
323 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_DisallowNonBlock)324 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowNonBlock) {
325   auto p = parser(test::Assemble(CommonTypes() + R"(
326      %100 = OpFunction %void None %voidfn
327 
328      %10 = OpLabel
329      OpBranch %999 ; definitely wrong
330 
331      OpFunctionEnd
332   )"));
333   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
334   auto fe = p->function_emitter(100);
335   fe.RegisterBasicBlocks();
336   EXPECT_FALSE(fe.TerminatorsAreValid());
337   EXPECT_THAT(p->error(),
338               Eq("Block 10 in function 100 branches to 999 which is "
339                  "not a block in the function"));
340 }
341 
TEST_F(SpvParserCFGTest,TerminatorsAreValid_DisallowBlockInDifferentFunction)342 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowBlockInDifferentFunction) {
343   auto p = parser(test::Assemble(CommonTypes() + R"(
344      %100 = OpFunction %void None %voidfn
345 
346      %10 = OpLabel
347      OpBranch %210
348 
349      OpFunctionEnd
350 
351 
352      %200 = OpFunction %void None %voidfn
353 
354      %210 = OpLabel
355      OpReturn
356 
357      OpFunctionEnd
358   )"));
359   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
360   auto fe = p->function_emitter(100);
361   fe.RegisterBasicBlocks();
362   EXPECT_FALSE(fe.TerminatorsAreValid());
363   EXPECT_THAT(p->error(), Eq("Block 10 in function 100 branches to 210 which "
364                              "is not a block in the function"));
365 }
366 
TEST_F(SpvParserCFGTest,RegisterMerges_NoMerges)367 TEST_F(SpvParserCFGTest, RegisterMerges_NoMerges) {
368   auto p = parser(test::Assemble(CommonTypes() + R"(
369      %100 = OpFunction %void None %voidfn
370 
371      %10 = OpLabel
372      OpReturn
373 
374      OpFunctionEnd
375   )"));
376   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
377   auto fe = p->function_emitter(100);
378   fe.RegisterBasicBlocks();
379   EXPECT_TRUE(fe.RegisterMerges());
380 
381   const auto* bi = fe.GetBlockInfo(10);
382   ASSERT_NE(bi, nullptr);
383   EXPECT_EQ(bi->merge_for_header, 0u);
384   EXPECT_EQ(bi->continue_for_header, 0u);
385   EXPECT_EQ(bi->header_for_merge, 0u);
386   EXPECT_EQ(bi->header_for_continue, 0u);
387   EXPECT_FALSE(bi->is_continue_entire_loop);
388 }
389 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodSelectionMerge_BranchConditional)390 TEST_F(SpvParserCFGTest, RegisterMerges_GoodSelectionMerge_BranchConditional) {
391   auto p = parser(test::Assemble(CommonTypes() + R"(
392      %100 = OpFunction %void None %voidfn
393 
394      %10 = OpLabel
395      OpSelectionMerge %99 None
396      OpBranchConditional %cond %20 %99
397 
398      %20 = OpLabel
399      OpBranch %99
400 
401      %99 = OpLabel
402      OpReturn
403 
404      OpFunctionEnd
405   )"));
406   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
407   auto fe = p->function_emitter(100);
408   fe.RegisterBasicBlocks();
409   EXPECT_TRUE(fe.RegisterMerges());
410 
411   // Header points to the merge
412   const auto* bi10 = fe.GetBlockInfo(10);
413   ASSERT_NE(bi10, nullptr);
414   EXPECT_EQ(bi10->merge_for_header, 99u);
415   EXPECT_EQ(bi10->continue_for_header, 0u);
416   EXPECT_EQ(bi10->header_for_merge, 0u);
417   EXPECT_EQ(bi10->header_for_continue, 0u);
418   EXPECT_FALSE(bi10->is_continue_entire_loop);
419 
420   // Middle block is neither header nor merge
421   const auto* bi20 = fe.GetBlockInfo(20);
422   ASSERT_NE(bi20, nullptr);
423   EXPECT_EQ(bi20->merge_for_header, 0u);
424   EXPECT_EQ(bi20->continue_for_header, 0u);
425   EXPECT_EQ(bi20->header_for_merge, 0u);
426   EXPECT_EQ(bi20->header_for_continue, 0u);
427   EXPECT_FALSE(bi20->is_continue_entire_loop);
428 
429   // Merge block points to the header
430   const auto* bi99 = fe.GetBlockInfo(99);
431   ASSERT_NE(bi99, nullptr);
432   EXPECT_EQ(bi99->merge_for_header, 0u);
433   EXPECT_EQ(bi99->continue_for_header, 0u);
434   EXPECT_EQ(bi99->header_for_merge, 10u);
435   EXPECT_EQ(bi99->header_for_continue, 0u);
436   EXPECT_FALSE(bi99->is_continue_entire_loop);
437 }
438 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodSelectionMerge_Switch)439 TEST_F(SpvParserCFGTest, RegisterMerges_GoodSelectionMerge_Switch) {
440   auto p = parser(test::Assemble(CommonTypes() + R"(
441      %100 = OpFunction %void None %voidfn
442 
443      %10 = OpLabel
444      OpSelectionMerge %99 None
445      OpSwitch %selector %99 20 %20
446 
447      %20 = OpLabel
448      OpBranch %99
449 
450      %99 = OpLabel
451      OpReturn
452 
453      OpFunctionEnd
454   )"));
455   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
456   auto fe = p->function_emitter(100);
457   fe.RegisterBasicBlocks();
458   EXPECT_TRUE(fe.RegisterMerges());
459 
460   // Header points to the merge
461   const auto* bi10 = fe.GetBlockInfo(10);
462   ASSERT_NE(bi10, nullptr);
463   EXPECT_EQ(bi10->merge_for_header, 99u);
464   EXPECT_EQ(bi10->continue_for_header, 0u);
465   EXPECT_EQ(bi10->header_for_merge, 0u);
466   EXPECT_EQ(bi10->header_for_continue, 0u);
467   EXPECT_FALSE(bi10->is_continue_entire_loop);
468 
469   // Middle block is neither header nor merge
470   const auto* bi20 = fe.GetBlockInfo(20);
471   ASSERT_NE(bi20, nullptr);
472   EXPECT_EQ(bi20->merge_for_header, 0u);
473   EXPECT_EQ(bi20->continue_for_header, 0u);
474   EXPECT_EQ(bi20->header_for_merge, 0u);
475   EXPECT_EQ(bi20->header_for_continue, 0u);
476   EXPECT_FALSE(bi20->is_continue_entire_loop);
477 
478   // Merge block points to the header
479   const auto* bi99 = fe.GetBlockInfo(99);
480   ASSERT_NE(bi99, nullptr);
481   EXPECT_EQ(bi99->merge_for_header, 0u);
482   EXPECT_EQ(bi99->continue_for_header, 0u);
483   EXPECT_EQ(bi99->header_for_merge, 10u);
484   EXPECT_EQ(bi99->header_for_continue, 0u);
485   EXPECT_FALSE(bi99->is_continue_entire_loop);
486 }
487 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodLoopMerge_SingleBlockLoop)488 TEST_F(SpvParserCFGTest, RegisterMerges_GoodLoopMerge_SingleBlockLoop) {
489   auto p = parser(test::Assemble(CommonTypes() + R"(
490      %100 = OpFunction %void None %voidfn
491 
492      %10 = OpLabel
493      OpBranch %20
494 
495      %20 = OpLabel
496      OpLoopMerge %99 %20 None
497      OpBranchConditional %cond %20 %99
498 
499      %99 = OpLabel
500      OpReturn
501 
502      OpFunctionEnd
503   )"));
504   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
505   auto fe = p->function_emitter(100);
506   fe.RegisterBasicBlocks();
507   EXPECT_TRUE(fe.RegisterMerges());
508 
509   // Entry block is not special
510   const auto* bi10 = fe.GetBlockInfo(10);
511   ASSERT_NE(bi10, nullptr);
512   EXPECT_EQ(bi10->merge_for_header, 0u);
513   EXPECT_EQ(bi10->continue_for_header, 0u);
514   EXPECT_EQ(bi10->header_for_merge, 0u);
515   EXPECT_EQ(bi10->header_for_continue, 0u);
516   EXPECT_FALSE(bi10->is_continue_entire_loop);
517 
518   // Single block loop is its own continue, and marked as single block loop.
519   const auto* bi20 = fe.GetBlockInfo(20);
520   ASSERT_NE(bi20, nullptr);
521   EXPECT_EQ(bi20->merge_for_header, 99u);
522   EXPECT_EQ(bi20->continue_for_header, 20u);
523   EXPECT_EQ(bi20->header_for_merge, 0u);
524   EXPECT_EQ(bi20->header_for_continue, 20u);
525   EXPECT_TRUE(bi20->is_continue_entire_loop);
526 
527   // Merge block points to the header
528   const auto* bi99 = fe.GetBlockInfo(99);
529   ASSERT_NE(bi99, nullptr);
530   EXPECT_EQ(bi99->merge_for_header, 0u);
531   EXPECT_EQ(bi99->continue_for_header, 0u);
532   EXPECT_EQ(bi99->header_for_merge, 20u);
533   EXPECT_EQ(bi99->header_for_continue, 0u);
534   EXPECT_FALSE(bi99->is_continue_entire_loop);
535 }
536 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsHeader)537 TEST_F(SpvParserCFGTest,
538        RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsHeader) {
539   auto p = parser(test::Assemble(CommonTypes() + R"(
540      %100 = OpFunction %void None %voidfn
541 
542      %10 = OpLabel
543      OpBranch %20
544 
545      %20 = OpLabel
546      OpLoopMerge %99 %20 None
547      OpBranch %40
548 
549      %40 = OpLabel
550      OpBranch %20
551 
552      %99 = OpLabel
553      OpReturn
554 
555      OpFunctionEnd
556   )"));
557   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
558   auto fe = p->function_emitter(100);
559   fe.RegisterBasicBlocks();
560   EXPECT_TRUE(fe.RegisterMerges());
561 
562   // Loop header points to continue (itself) and merge
563   const auto* bi20 = fe.GetBlockInfo(20);
564   ASSERT_NE(bi20, nullptr);
565   EXPECT_EQ(bi20->merge_for_header, 99u);
566   EXPECT_EQ(bi20->continue_for_header, 20u);
567   EXPECT_EQ(bi20->header_for_merge, 0u);
568   EXPECT_EQ(bi20->header_for_continue, 20u);
569   EXPECT_TRUE(bi20->is_continue_entire_loop);
570 
571   // Backedge block, but is not a declared header, merge, or continue
572   const auto* bi40 = fe.GetBlockInfo(40);
573   ASSERT_NE(bi40, nullptr);
574   EXPECT_EQ(bi40->merge_for_header, 0u);
575   EXPECT_EQ(bi40->continue_for_header, 0u);
576   EXPECT_EQ(bi40->header_for_merge, 0u);
577   EXPECT_EQ(bi40->header_for_continue, 0u);
578   EXPECT_FALSE(bi40->is_continue_entire_loop);
579 
580   // Merge block points to the header
581   const auto* bi99 = fe.GetBlockInfo(99);
582   ASSERT_NE(bi99, nullptr);
583   EXPECT_EQ(bi99->merge_for_header, 0u);
584   EXPECT_EQ(bi99->continue_for_header, 0u);
585   EXPECT_EQ(bi99->header_for_merge, 20u);
586   EXPECT_EQ(bi99->header_for_continue, 0u);
587   EXPECT_FALSE(bi99->is_continue_entire_loop);
588 }
589 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_Branch)590 TEST_F(SpvParserCFGTest,
591        RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_Branch) {
592   auto p = parser(test::Assemble(CommonTypes() + R"(
593      %100 = OpFunction %void None %voidfn
594 
595      %10 = OpLabel
596      OpBranch %20
597 
598      %20 = OpLabel
599      OpLoopMerge %99 %40 None
600      OpBranch %30
601 
602      %30 = OpLabel
603      OpBranchConditional %cond %40 %99
604 
605      %40 = OpLabel
606      OpBranch %20
607 
608      %99 = OpLabel
609      OpReturn
610 
611      OpFunctionEnd
612   )"));
613   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
614   auto fe = p->function_emitter(100);
615   fe.RegisterBasicBlocks();
616   EXPECT_TRUE(fe.RegisterMerges());
617 
618   // Loop header points to continue and merge
619   const auto* bi20 = fe.GetBlockInfo(20);
620   ASSERT_NE(bi20, nullptr);
621   EXPECT_EQ(bi20->merge_for_header, 99u);
622   EXPECT_EQ(bi20->continue_for_header, 40u);
623   EXPECT_EQ(bi20->header_for_merge, 0u);
624   EXPECT_EQ(bi20->header_for_continue, 0u);
625   EXPECT_FALSE(bi20->is_continue_entire_loop);
626 
627   // Continue block points to header
628   const auto* bi40 = fe.GetBlockInfo(40);
629   ASSERT_NE(bi40, nullptr);
630   EXPECT_EQ(bi40->merge_for_header, 0u);
631   EXPECT_EQ(bi40->continue_for_header, 0u);
632   EXPECT_EQ(bi40->header_for_merge, 0u);
633   EXPECT_EQ(bi40->header_for_continue, 20u);
634   EXPECT_FALSE(bi40->is_continue_entire_loop);
635 
636   // Merge block points to the header
637   const auto* bi99 = fe.GetBlockInfo(99);
638   ASSERT_NE(bi99, nullptr);
639   EXPECT_EQ(bi99->merge_for_header, 0u);
640   EXPECT_EQ(bi99->continue_for_header, 0u);
641   EXPECT_EQ(bi99->header_for_merge, 20u);
642   EXPECT_EQ(bi99->header_for_continue, 0u);
643   EXPECT_FALSE(bi99->is_continue_entire_loop);
644 }
645 
TEST_F(SpvParserCFGTest,RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_BranchConditional)646 TEST_F(
647     SpvParserCFGTest,
648     RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_BranchConditional) {  // NOLINT
649   auto p = parser(test::Assemble(CommonTypes() + R"(
650      %100 = OpFunction %void None %voidfn
651 
652      %10 = OpLabel
653      OpBranch %20
654 
655      %20 = OpLabel
656      OpLoopMerge %99 %40 None
657      OpBranchConditional %cond %30 %99
658 
659      %30 = OpLabel
660      OpBranch %40
661 
662      %40 = OpLabel
663      OpBranch %20
664 
665      %99 = OpLabel
666      OpReturn
667 
668      OpFunctionEnd
669   )"));
670   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
671   auto fe = p->function_emitter(100);
672   fe.RegisterBasicBlocks();
673   EXPECT_TRUE(fe.RegisterMerges());
674 
675   // Loop header points to continue and merge
676   const auto* bi20 = fe.GetBlockInfo(20);
677   ASSERT_NE(bi20, nullptr);
678   EXPECT_EQ(bi20->merge_for_header, 99u);
679   EXPECT_EQ(bi20->continue_for_header, 40u);
680   EXPECT_EQ(bi20->header_for_merge, 0u);
681   EXPECT_EQ(bi20->header_for_continue, 0u);
682   EXPECT_FALSE(bi20->is_continue_entire_loop);
683 
684   // Continue block points to header
685   const auto* bi40 = fe.GetBlockInfo(40);
686   ASSERT_NE(bi40, nullptr);
687   EXPECT_EQ(bi40->merge_for_header, 0u);
688   EXPECT_EQ(bi40->continue_for_header, 0u);
689   EXPECT_EQ(bi40->header_for_merge, 0u);
690   EXPECT_EQ(bi40->header_for_continue, 20u);
691   EXPECT_FALSE(bi40->is_continue_entire_loop);
692 
693   // Merge block points to the header
694   const auto* bi99 = fe.GetBlockInfo(99);
695   ASSERT_NE(bi99, nullptr);
696   EXPECT_EQ(bi99->merge_for_header, 0u);
697   EXPECT_EQ(bi99->continue_for_header, 0u);
698   EXPECT_EQ(bi99->header_for_merge, 20u);
699   EXPECT_EQ(bi99->header_for_continue, 0u);
700   EXPECT_FALSE(bi99->is_continue_entire_loop);
701 }
702 
TEST_F(SpvParserCFGTest,RegisterMerges_SelectionMerge_BadTerminator)703 TEST_F(SpvParserCFGTest, RegisterMerges_SelectionMerge_BadTerminator) {
704   auto p = parser(test::Assemble(CommonTypes() + R"(
705      %100 = OpFunction %void None %voidfn
706 
707      %10 = OpLabel
708      OpSelectionMerge %99 None
709      OpBranch %20
710 
711      %20 = OpLabel
712      OpBranch %99
713 
714      %99 = OpLabel
715      OpReturn
716 
717      OpFunctionEnd
718   )"));
719   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
720   auto fe = p->function_emitter(100);
721   fe.RegisterBasicBlocks();
722   EXPECT_FALSE(fe.RegisterMerges());
723   EXPECT_THAT(p->error(), Eq("Selection header 10 does not end in an "
724                              "OpBranchConditional or OpSwitch instruction"));
725 }
726 
TEST_F(SpvParserCFGTest,RegisterMerges_LoopMerge_BadTerminator)727 TEST_F(SpvParserCFGTest, RegisterMerges_LoopMerge_BadTerminator) {
728   auto p = parser(test::Assemble(CommonTypes() + R"(
729      %100 = OpFunction %void None %voidfn
730 
731      %10 = OpLabel
732      OpBranch %20
733 
734      %20 = OpLabel
735      OpLoopMerge %99 %40 None
736      OpSwitch %selector %99 30 %30
737 
738      %30 = OpLabel
739      OpBranch %99
740 
741      %40 = OpLabel
742      OpBranch %20
743 
744      %99 = OpLabel
745      OpReturn
746 
747      OpFunctionEnd
748   )"));
749   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
750   auto fe = p->function_emitter(100);
751   fe.RegisterBasicBlocks();
752   EXPECT_FALSE(fe.RegisterMerges());
753   EXPECT_THAT(p->error(), Eq("Loop header 20 does not end in an OpBranch or "
754                              "OpBranchConditional instruction"));
755 }
756 
TEST_F(SpvParserCFGTest,RegisterMerges_BadMergeBlock)757 TEST_F(SpvParserCFGTest, RegisterMerges_BadMergeBlock) {
758   auto p = parser(test::Assemble(CommonTypes() + R"(
759      %100 = OpFunction %void None %voidfn
760 
761      %10 = OpLabel
762      OpSelectionMerge %void None
763      OpBranchConditional %cond %30 %99
764 
765      %30 = OpLabel
766      OpBranch %99
767 
768      %99 = OpLabel
769      OpReturn
770 
771      OpFunctionEnd
772   )"));
773   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
774   auto fe = p->function_emitter(100);
775   fe.RegisterBasicBlocks();
776   EXPECT_FALSE(fe.RegisterMerges());
777   EXPECT_THAT(p->error(),
778               Eq("Structured header block 10 declares invalid merge block 2"));
779 }
780 
TEST_F(SpvParserCFGTest,RegisterMerges_HeaderIsItsOwnMerge)781 TEST_F(SpvParserCFGTest, RegisterMerges_HeaderIsItsOwnMerge) {
782   auto p = parser(test::Assemble(CommonTypes() + R"(
783      %100 = OpFunction %void None %voidfn
784 
785      %10 = OpLabel
786      OpSelectionMerge %10 None
787      OpBranchConditional %cond %30 %99
788 
789      %30 = OpLabel
790      OpBranch %99
791 
792      %99 = OpLabel
793      OpReturn
794 
795      OpFunctionEnd
796   )"));
797   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
798   auto fe = p->function_emitter(100);
799   fe.RegisterBasicBlocks();
800   EXPECT_FALSE(fe.RegisterMerges());
801   EXPECT_THAT(p->error(),
802               Eq("Structured header block 10 cannot be its own merge block"));
803 }
804 
TEST_F(SpvParserCFGTest,RegisterMerges_MergeReused)805 TEST_F(SpvParserCFGTest, RegisterMerges_MergeReused) {
806   auto p = parser(test::Assemble(CommonTypes() + R"(
807      %100 = OpFunction %void None %voidfn
808 
809      %10 = OpLabel
810      OpSelectionMerge %49 None
811      OpBranchConditional %cond %20 %49
812 
813      %20 = OpLabel
814      OpBranch %49
815 
816      %49 = OpLabel
817      OpBranch %50
818 
819      %50 = OpLabel
820      OpSelectionMerge %49 None  ; can't reuse merge block
821      OpBranchConditional %cond %60 %99
822 
823      %60 = OpLabel
824      OpBranch %99
825 
826      %99 = OpLabel
827      OpReturn
828 
829      OpFunctionEnd
830   )"));
831   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
832   auto fe = p->function_emitter(100);
833   fe.RegisterBasicBlocks();
834   EXPECT_FALSE(fe.RegisterMerges());
835   EXPECT_THAT(
836       p->error(),
837       Eq("Block 49 declared as merge block for more than one header: 10, 50"));
838 }
839 
TEST_F(SpvParserCFGTest,RegisterMerges_EntryBlockIsLoopHeader)840 TEST_F(SpvParserCFGTest, RegisterMerges_EntryBlockIsLoopHeader) {
841   auto p = parser(test::Assemble(CommonTypes() + R"(
842      %100 = OpFunction %void None %voidfn
843 
844      %10 = OpLabel
845      OpLoopMerge %99 %30 None
846      OpBranchConditional %cond %10 %99
847 
848      %30 = OpLabel
849      OpBranch %10
850 
851      %99 = OpLabel
852      OpReturn
853 
854      OpFunctionEnd
855   )"));
856   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
857   auto fe = p->function_emitter(100);
858   fe.RegisterBasicBlocks();
859   EXPECT_FALSE(fe.RegisterMerges());
860   EXPECT_THAT(p->error(),
861               Eq("Function entry block 10 cannot be a loop header"));
862 }
863 
TEST_F(SpvParserCFGTest,RegisterMerges_BadContinueTarget)864 TEST_F(SpvParserCFGTest, RegisterMerges_BadContinueTarget) {
865   auto p = parser(test::Assemble(CommonTypes() + R"(
866      %100 = OpFunction %void None %voidfn
867 
868      %10 = OpLabel
869      OpBranch %20
870 
871      %20 = OpLabel
872      OpLoopMerge %99 %999 None
873      OpBranchConditional %cond %20 %99
874 
875      %99 = OpLabel
876      OpReturn
877 
878      OpFunctionEnd
879   )"));
880   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
881   auto fe = p->function_emitter(100);
882   fe.RegisterBasicBlocks();
883   EXPECT_FALSE(fe.RegisterMerges());
884   EXPECT_THAT(p->error(),
885               Eq("Structured header 20 declares invalid continue target 999"));
886 }
887 
TEST_F(SpvParserCFGTest,RegisterMerges_MergeSameAsContinue)888 TEST_F(SpvParserCFGTest, RegisterMerges_MergeSameAsContinue) {
889   auto p = parser(test::Assemble(CommonTypes() + R"(
890      %100 = OpFunction %void None %voidfn
891 
892      %10 = OpLabel
893      OpBranch %20
894 
895      %20 = OpLabel
896      OpLoopMerge %50 %50 None
897      OpBranchConditional %cond %20 %99
898 
899 
900      %50 = OpLabel
901      OpBranch %20
902 
903      %99 = OpLabel
904      OpReturn
905 
906      OpFunctionEnd
907   )"));
908   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
909   auto fe = p->function_emitter(100);
910   fe.RegisterBasicBlocks();
911   EXPECT_FALSE(fe.RegisterMerges());
912   EXPECT_THAT(p->error(),
913               Eq("Invalid structured header block 20: declares block 50 as "
914                  "both its merge block and continue target"));
915 }
916 
TEST_F(SpvParserCFGTest,RegisterMerges_ContinueReused)917 TEST_F(SpvParserCFGTest, RegisterMerges_ContinueReused) {
918   auto p = parser(test::Assemble(CommonTypes() + R"(
919      %100 = OpFunction %void None %voidfn
920 
921      %10 = OpLabel
922      OpBranch %20
923 
924      %20 = OpLabel
925      OpLoopMerge %49 %40 None
926      OpBranchConditional %cond %30 %49
927 
928      %30 = OpLabel
929      OpBranch %40
930 
931      %40 = OpLabel
932      OpBranch %20
933 
934      %49 = OpLabel
935      OpBranch %50
936 
937      %50 = OpLabel
938      OpLoopMerge %99 %40 None
939      OpBranchConditional %cond %60 %99
940 
941      %60 = OpLabel
942      OpBranch %70
943 
944      %70 = OpLabel
945      OpBranch %50
946 
947      %99 = OpLabel
948      OpReturn
949 
950      OpFunctionEnd
951   )"));
952   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
953   auto fe = p->function_emitter(100);
954   fe.RegisterBasicBlocks();
955   EXPECT_FALSE(fe.RegisterMerges());
956   EXPECT_THAT(p->error(), Eq("Block 40 declared as continue target for more "
957                              "than one header: 20, 50"));
958 }
959 
TEST_F(SpvParserCFGTest,RegisterMerges_SingleBlockLoop_NotItsOwnContinue)960 TEST_F(SpvParserCFGTest, RegisterMerges_SingleBlockLoop_NotItsOwnContinue) {
961   auto p = parser(test::Assemble(CommonTypes() + R"(
962      %100 = OpFunction %void None %voidfn
963 
964      %10 = OpLabel
965      OpBranch %20
966 
967      %20 = OpLabel
968      OpLoopMerge %99 %30 None
969      OpBranchConditional %cond %20 %99
970 
971      %30 = OpLabel
972      OpBranch %20
973 
974      %99 = OpLabel
975      OpReturn
976 
977      OpFunctionEnd
978   )"));
979   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
980   auto fe = p->function_emitter(100);
981   fe.RegisterBasicBlocks();
982   EXPECT_FALSE(fe.RegisterMerges());
983   EXPECT_THAT(
984       p->error(),
985       Eq("Block 20 branches to itself but is not its own continue target"));
986 }
987 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_OneBlock)988 TEST_F(SpvParserCFGTest, ComputeBlockOrder_OneBlock) {
989   auto p = parser(test::Assemble(CommonTypes() + R"(
990      %100 = OpFunction %void None %voidfn
991 
992      %42 = OpLabel
993      OpReturn
994 
995      OpFunctionEnd
996   )"));
997   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
998   auto fe = p->function_emitter(100);
999   fe.RegisterBasicBlocks();
1000   fe.ComputeBlockOrderAndPositions();
1001 
1002   EXPECT_THAT(fe.block_order(), ElementsAre(42));
1003 
1004   const auto* bi = fe.GetBlockInfo(42);
1005   ASSERT_NE(bi, nullptr);
1006   EXPECT_EQ(bi->pos, 0u);
1007 }
1008 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_IgnoreStaticalyUnreachable)1009 TEST_F(SpvParserCFGTest, ComputeBlockOrder_IgnoreStaticalyUnreachable) {
1010   auto p = parser(test::Assemble(CommonTypes() + R"(
1011      %100 = OpFunction %void None %voidfn
1012 
1013      %10 = OpLabel
1014      OpBranch %20
1015 
1016      %15 = OpLabel ; statically dead
1017      OpReturn
1018 
1019      %20 = OpLabel
1020      OpReturn
1021 
1022      OpFunctionEnd
1023   )"));
1024   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1025   auto fe = p->function_emitter(100);
1026   fe.RegisterBasicBlocks();
1027   fe.ComputeBlockOrderAndPositions();
1028 
1029   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
1030 }
1031 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_KillIsDeadEnd)1032 TEST_F(SpvParserCFGTest, ComputeBlockOrder_KillIsDeadEnd) {
1033   auto p = parser(test::Assemble(CommonTypes() + R"(
1034      %100 = OpFunction %void None %voidfn
1035 
1036      %10 = OpLabel
1037      OpBranch %20
1038 
1039      %15 = OpLabel ; statically dead
1040      OpReturn
1041 
1042      %20 = OpLabel
1043      OpKill        ; Kill doesn't lead anywhere
1044 
1045      OpFunctionEnd
1046   )"));
1047   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1048   auto fe = p->function_emitter(100);
1049   fe.RegisterBasicBlocks();
1050   fe.ComputeBlockOrderAndPositions();
1051 
1052   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
1053 }
1054 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_UnreachableIsDeadEnd)1055 TEST_F(SpvParserCFGTest, ComputeBlockOrder_UnreachableIsDeadEnd) {
1056   auto p = parser(test::Assemble(CommonTypes() + R"(
1057      %100 = OpFunction %void None %voidfn
1058 
1059      %10 = OpLabel
1060      OpBranch %20
1061 
1062      %15 = OpLabel ; statically dead
1063      OpReturn
1064 
1065      %20 = OpLabel
1066      OpUnreachable ; Unreachable doesn't lead anywhere
1067 
1068      OpFunctionEnd
1069   )"));
1070   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1071   auto fe = p->function_emitter(100);
1072   fe.RegisterBasicBlocks();
1073   fe.ComputeBlockOrderAndPositions();
1074 
1075   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
1076 }
1077 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_ReorderSequence)1078 TEST_F(SpvParserCFGTest, ComputeBlockOrder_ReorderSequence) {
1079   auto p = parser(test::Assemble(CommonTypes() + R"(
1080      %100 = OpFunction %void None %voidfn
1081 
1082      %10 = OpLabel
1083      OpSelectionMerge %99 None
1084      OpBranchConditional %cond %20 %30
1085 
1086      %30 = OpLabel
1087      OpReturn
1088 
1089      %20 = OpLabel
1090      OpBranch %30 ; backtrack, but does dominate %30
1091 
1092      %99 = OpLabel
1093      OpReturn
1094 
1095      OpFunctionEnd
1096   )"));
1097   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1098   auto fe = p->function_emitter(100);
1099   fe.RegisterBasicBlocks();
1100   fe.ComputeBlockOrderAndPositions();
1101 
1102   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
1103 
1104   const auto* bi10 = fe.GetBlockInfo(10);
1105   ASSERT_NE(bi10, nullptr);
1106   EXPECT_EQ(bi10->pos, 0u);
1107   const auto* bi20 = fe.GetBlockInfo(20);
1108   ASSERT_NE(bi20, nullptr);
1109   EXPECT_EQ(bi20->pos, 1u);
1110   const auto* bi30 = fe.GetBlockInfo(30);
1111   ASSERT_NE(bi30, nullptr);
1112   EXPECT_EQ(bi30->pos, 2u);
1113   const auto* bi99 = fe.GetBlockInfo(99);
1114   ASSERT_NE(bi99, nullptr);
1115   EXPECT_EQ(bi99->pos, 3u);
1116 }
1117 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_DupConditionalBranch)1118 TEST_F(SpvParserCFGTest, ComputeBlockOrder_DupConditionalBranch) {
1119   auto p = parser(test::Assemble(CommonTypes() + R"(
1120      %100 = OpFunction %void None %voidfn
1121 
1122      %10 = OpLabel
1123      OpSelectionMerge %99 None
1124      OpBranchConditional %cond %20 %20
1125 
1126      %20 = OpLabel
1127      OpBranch %99
1128 
1129      %99 = OpLabel
1130      OpReturn
1131 
1132      OpFunctionEnd
1133   )"));
1134   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1135   auto fe = p->function_emitter(100);
1136   fe.RegisterBasicBlocks();
1137   fe.ComputeBlockOrderAndPositions();
1138 
1139   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
1140 }
1141 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_RespectConditionalBranchOrder)1142 TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectConditionalBranchOrder) {
1143   auto p = parser(test::Assemble(CommonTypes() + R"(
1144      %100 = OpFunction %void None %voidfn
1145 
1146      %10 = OpLabel
1147      OpSelectionMerge %99 None
1148      OpBranchConditional %cond %20 %30
1149 
1150      %30 = OpLabel
1151      OpReturn
1152 
1153      %20 = OpLabel
1154      OpBranch %99
1155 
1156      %99 = OpLabel ; dominated by %20, so follow %20
1157      OpReturn
1158 
1159      OpFunctionEnd
1160   )"));
1161   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1162   auto fe = p->function_emitter(100);
1163   fe.RegisterBasicBlocks();
1164   fe.ComputeBlockOrderAndPositions();
1165 
1166   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
1167 }
1168 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_TrueOnlyBranch)1169 TEST_F(SpvParserCFGTest, ComputeBlockOrder_TrueOnlyBranch) {
1170   auto p = parser(test::Assemble(CommonTypes() + R"(
1171      %100 = OpFunction %void None %voidfn
1172 
1173      %10 = OpLabel
1174      OpSelectionMerge %99 None
1175      OpBranchConditional %cond %20 %99
1176 
1177      %99 = OpLabel
1178      OpReturn
1179 
1180      %20 = OpLabel
1181      OpBranch %99
1182 
1183      OpFunctionEnd
1184   )"));
1185   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1186   auto fe = p->function_emitter(100);
1187   fe.RegisterBasicBlocks();
1188   fe.ComputeBlockOrderAndPositions();
1189 
1190   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
1191 }
1192 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_FalseOnlyBranch)1193 TEST_F(SpvParserCFGTest, ComputeBlockOrder_FalseOnlyBranch) {
1194   auto p = parser(test::Assemble(CommonTypes() + R"(
1195      %100 = OpFunction %void None %voidfn
1196 
1197      %10 = OpLabel
1198      OpSelectionMerge %99 None
1199      OpBranchConditional %cond %99 %20
1200 
1201      %99 = OpLabel
1202      OpReturn
1203 
1204      %20 = OpLabel
1205      OpBranch %99
1206 
1207      OpFunctionEnd
1208   )"));
1209   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1210   auto fe = p->function_emitter(100);
1211   fe.RegisterBasicBlocks();
1212   fe.ComputeBlockOrderAndPositions();
1213 
1214   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
1215 }
1216 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_SwitchOrderNaturallyReversed)1217 TEST_F(SpvParserCFGTest, ComputeBlockOrder_SwitchOrderNaturallyReversed) {
1218   auto p = parser(test::Assemble(CommonTypes() + R"(
1219      %100 = OpFunction %void None %voidfn
1220 
1221      %10 = OpLabel
1222      OpSelectionMerge %99 None
1223      OpSwitch %selector %99 20 %20 30 %30
1224 
1225      %99 = OpLabel
1226      OpReturn
1227 
1228      %30 = OpLabel
1229      OpReturn
1230 
1231      %20 = OpLabel
1232      OpBranch %99
1233 
1234      OpFunctionEnd
1235   )"));
1236   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1237   auto fe = p->function_emitter(100);
1238   fe.RegisterBasicBlocks();
1239   fe.ComputeBlockOrderAndPositions();
1240 
1241   EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 99));
1242 }
1243 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_SwitchWithDefaultOrderNaturallyReversed)1244 TEST_F(SpvParserCFGTest,
1245        ComputeBlockOrder_SwitchWithDefaultOrderNaturallyReversed) {
1246   auto p = parser(test::Assemble(CommonTypes() + R"(
1247      %100 = OpFunction %void None %voidfn
1248 
1249      %10 = OpLabel
1250      OpSelectionMerge %99 None
1251      OpSwitch %selector %80 20 %20 30 %30
1252 
1253      %80 = OpLabel ; the default case
1254      OpBranch %99
1255 
1256      %99 = OpLabel
1257      OpReturn
1258 
1259      %30 = OpLabel
1260      OpReturn
1261 
1262      %20 = OpLabel
1263      OpBranch %99
1264 
1265      OpFunctionEnd
1266   )"));
1267   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1268   auto fe = p->function_emitter(100);
1269   fe.RegisterBasicBlocks();
1270   fe.ComputeBlockOrderAndPositions();
1271 
1272   EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
1273 }
1274 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Switch_DefaultSameAsACase)1275 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Switch_DefaultSameAsACase) {
1276   auto p = parser(test::Assemble(CommonTypes() + R"(
1277      %100 = OpFunction %void None %voidfn
1278 
1279      %10 = OpLabel
1280      OpSelectionMerge %99 None
1281      OpSwitch %selector %30 20 %20 30 %30 40 %40
1282 
1283      %99 = OpLabel
1284      OpReturn
1285 
1286      %30 = OpLabel
1287      OpBranch %99
1288 
1289      %20 = OpLabel
1290      OpBranch %99
1291 
1292      %40 = OpLabel
1293      OpBranch %99
1294 
1295      OpFunctionEnd
1296   )"));
1297   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1298   auto fe = p->function_emitter(100);
1299   fe.RegisterBasicBlocks();
1300   fe.ComputeBlockOrderAndPositions();
1301 
1302   EXPECT_THAT(fe.block_order(), ElementsAre(10, 40, 20, 30, 99));
1303 }
1304 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_RespectSwitchCaseFallthrough)1305 TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough) {
1306   auto assembly = CommonTypes() + R"(
1307      %100 = OpFunction %void None %voidfn
1308 
1309      %10 = OpLabel
1310      OpSelectionMerge %99 None
1311      ; SPIR-V validation requires a fallthrough destination to immediately
1312      ; follow the source. So %20 -> %40, %30 -> %50
1313      OpSwitch %selector %99 20 %20 40 %40 30 %30 50 %50
1314 
1315      %50 = OpLabel
1316      OpBranch %99
1317 
1318      %99 = OpLabel
1319      OpReturn
1320 
1321      %40 = OpLabel
1322      OpBranch %99
1323 
1324      %30 = OpLabel
1325      OpBranch %50 ; fallthrough
1326 
1327      %20 = OpLabel
1328      OpBranch %40 ; fallthrough
1329 
1330      OpFunctionEnd
1331   )";
1332   auto p = parser(test::Assemble(assembly));
1333   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1334   auto fe = p->function_emitter(100);
1335   fe.RegisterBasicBlocks();
1336   fe.ComputeBlockOrderAndPositions();
1337 
1338   EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 20, 40, 99))
1339       << assembly;
1340 }
1341 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_RespectSwitchCaseFallthrough_FromDefault)1342 TEST_F(SpvParserCFGTest,
1343        ComputeBlockOrder_RespectSwitchCaseFallthrough_FromDefault) {
1344   auto assembly = CommonTypes() + R"(
1345      %100 = OpFunction %void None %voidfn
1346 
1347      %10 = OpLabel
1348      OpSelectionMerge %99 None
1349      OpSwitch %selector %80 20 %20 30 %30 40 %40
1350 
1351      %80 = OpLabel ; the default case
1352      OpBranch %30 ; fallthrough to another case
1353 
1354      %99 = OpLabel
1355      OpReturn
1356 
1357      %40 = OpLabel
1358      OpBranch %99
1359 
1360      %30 = OpLabel
1361      OpBranch %40
1362 
1363      %20 = OpLabel
1364      OpBranch %99
1365 
1366      OpFunctionEnd
1367   )";
1368   auto p = parser(test::Assemble(assembly));
1369   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1370   auto fe = p->function_emitter(100);
1371   fe.RegisterBasicBlocks();
1372   fe.ComputeBlockOrderAndPositions();
1373 
1374   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 40, 99))
1375       << assembly;
1376 }
1377 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_RespectSwitchCaseFallthrough_FromCaseToDefaultToCase)1378 TEST_F(SpvParserCFGTest,
1379        ComputeBlockOrder_RespectSwitchCaseFallthrough_FromCaseToDefaultToCase) {
1380   auto assembly = CommonTypes() + R"(
1381      %100 = OpFunction %void None %voidfn
1382 
1383      %10 = OpLabel
1384      OpSelectionMerge %99 None
1385      OpSwitch %selector %80 20 %20 30 %30
1386 
1387      %20 = OpLabel
1388      OpBranch %80 ; fallthrough to default
1389 
1390      %80 = OpLabel ; the default case
1391      OpBranch %30 ; fallthrough to 30
1392 
1393      %30 = OpLabel
1394      OpBranch %99
1395 
1396      %99 = OpLabel ; dominated by %30, so follow %30
1397      OpReturn
1398 
1399      OpFunctionEnd
1400   )";
1401   auto p = parser(test::Assemble(assembly));
1402   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1403   auto fe = p->function_emitter(100);
1404   fe.RegisterBasicBlocks();
1405   fe.ComputeBlockOrderAndPositions();
1406 
1407   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 99)) << assembly;
1408 }
1409 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_SwitchCasesFallthrough_OppositeDirections)1410 TEST_F(SpvParserCFGTest,
1411        ComputeBlockOrder_SwitchCasesFallthrough_OppositeDirections) {
1412   auto assembly = CommonTypes() + R"(
1413      %100 = OpFunction %void None %voidfn
1414 
1415      %10 = OpLabel
1416      OpSelectionMerge %99 None
1417      OpSwitch %selector %99 20 %20 30 %30 40 %40 50 %50
1418 
1419      %99 = OpLabel
1420      OpReturn
1421 
1422      %20 = OpLabel
1423      OpBranch %30 ; forward
1424 
1425      %40 = OpLabel
1426      OpBranch %99
1427 
1428      %30 = OpLabel
1429      OpBranch %99
1430 
1431      ; SPIR-V doesn't actually allow a fall-through that goes backward in the
1432      ; module. But the block ordering algorithm tolerates it.
1433      %50 = OpLabel
1434      OpBranch %40 ; backward
1435 
1436      OpFunctionEnd
1437   )";
1438   auto p = parser(test::Assemble(assembly));
1439   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1440   auto fe = p->function_emitter(100);
1441   fe.RegisterBasicBlocks();
1442   fe.ComputeBlockOrderAndPositions();
1443 
1444   EXPECT_THAT(fe.block_order(), ElementsAre(10, 50, 40, 20, 30, 99))
1445       << assembly;
1446 
1447   // We're deliberately testing a case that SPIR-V doesn't allow.
1448   p->DeliberatelyInvalidSpirv();
1449 }
1450 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_RespectSwitchCaseFallthrough_Interleaved)1451 TEST_F(SpvParserCFGTest,
1452        ComputeBlockOrder_RespectSwitchCaseFallthrough_Interleaved) {
1453   auto assembly = CommonTypes() + R"(
1454      %100 = OpFunction %void None %voidfn
1455 
1456      %10 = OpLabel
1457      OpSelectionMerge %99 None
1458      ; SPIR-V validation requires a fallthrough destination to immediately
1459      ; follow the source. So %20 -> %40
1460      OpSwitch %selector %99 20 %20 40 %40 30 %30 50 %50
1461 
1462      %99 = OpLabel
1463      OpReturn
1464 
1465      %20 = OpLabel
1466      OpBranch %40
1467 
1468      %30 = OpLabel
1469      OpBranch %50
1470 
1471      %40 = OpLabel
1472      OpBranch %60
1473 
1474      %50 = OpLabel
1475      OpBranch %70
1476 
1477      %60 = OpLabel
1478      OpBranch %99
1479 
1480      %70 = OpLabel
1481      OpBranch %99
1482 
1483      OpFunctionEnd
1484   )";
1485   auto p = parser(test::Assemble(assembly));
1486   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1487   auto fe = p->function_emitter(100);
1488   fe.RegisterBasicBlocks();
1489   fe.ComputeBlockOrderAndPositions();
1490 
1491   EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 70, 20, 40, 60, 99))
1492       << assembly;
1493 }
1494 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Nest_If_Contains_If)1495 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_If_Contains_If) {
1496   auto assembly = CommonTypes() + R"(
1497      %100 = OpFunction %void None %voidfn
1498 
1499      %10 = OpLabel
1500      OpSelectionMerge %99 None
1501      OpBranchConditional %cond %20 %50
1502 
1503      %99 = OpLabel
1504      OpReturn
1505 
1506      %20 = OpLabel
1507      OpSelectionMerge %49 None
1508      OpBranchConditional %cond %30 %40
1509 
1510      %49 = OpLabel
1511      OpBranch %99
1512 
1513      %30 = OpLabel
1514      OpBranch %49
1515 
1516      %40 = OpLabel
1517      OpBranch %49
1518 
1519      %50 = OpLabel
1520      OpSelectionMerge %79 None
1521      OpBranchConditional %cond %60 %70
1522 
1523      %79 = OpLabel
1524      OpBranch %99
1525 
1526      %60 = OpLabel
1527      OpBranch %79
1528 
1529      %70 = OpLabel
1530      OpBranch %79
1531 
1532      OpFunctionEnd
1533   )";
1534   auto p = parser(test::Assemble(assembly));
1535   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1536   auto fe = p->function_emitter(100);
1537   fe.RegisterBasicBlocks();
1538   fe.ComputeBlockOrderAndPositions();
1539 
1540   EXPECT_THAT(fe.block_order(),
1541               ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
1542       << assembly;
1543 }
1544 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Nest_If_In_SwitchCase)1545 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_If_In_SwitchCase) {
1546   auto assembly = CommonTypes() + R"(
1547      %100 = OpFunction %void None %voidfn
1548 
1549      %10 = OpLabel
1550      OpSelectionMerge %99 None
1551      OpSwitch %selector %50 20 %20 50 %50
1552 
1553      %99 = OpLabel
1554      OpReturn
1555 
1556      %20 = OpLabel
1557      OpSelectionMerge %49 None
1558      OpBranchConditional %cond %30 %40
1559 
1560      %49 = OpLabel
1561      OpBranch %99
1562 
1563      %30 = OpLabel
1564      OpBranch %49
1565 
1566      %40 = OpLabel
1567      OpBranch %49
1568 
1569      %50 = OpLabel
1570      OpSelectionMerge %79 None
1571      OpBranchConditional %cond %60 %70
1572 
1573      %79 = OpLabel
1574      OpBranch %99
1575 
1576      %60 = OpLabel
1577      OpBranch %79
1578 
1579      %70 = OpLabel
1580      OpBranch %79
1581 
1582      OpFunctionEnd
1583   )";
1584   auto p = parser(test::Assemble(assembly));
1585   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1586   auto fe = p->function_emitter(100);
1587   fe.RegisterBasicBlocks();
1588   fe.ComputeBlockOrderAndPositions();
1589 
1590   EXPECT_THAT(fe.block_order(),
1591               ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
1592       << assembly;
1593 }
1594 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Nest_IfFallthrough_In_SwitchCase)1595 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_IfFallthrough_In_SwitchCase) {
1596   auto assembly = CommonTypes() + R"(
1597      %100 = OpFunction %void None %voidfn
1598 
1599      %10 = OpLabel
1600      OpSelectionMerge %99 None
1601      OpSwitch %selector %50 20 %20 50 %50
1602 
1603      %99 = OpLabel
1604      OpReturn
1605 
1606      %20 = OpLabel
1607      OpSelectionMerge %49 None
1608      OpBranchConditional %cond %30 %40
1609 
1610      %49 = OpLabel
1611      OpBranchConditional %cond %99 %50 ; fallthrough
1612 
1613      %30 = OpLabel
1614      OpBranch %49
1615 
1616      %40 = OpLabel
1617      OpBranch %49
1618 
1619      %50 = OpLabel
1620      OpSelectionMerge %79 None
1621      OpBranchConditional %cond %60 %70
1622 
1623      %79 = OpLabel
1624      OpBranch %99
1625 
1626      %60 = OpLabel
1627      OpBranch %79
1628 
1629      %70 = OpLabel
1630      OpBranch %79
1631 
1632      OpFunctionEnd
1633   )";
1634   auto p = parser(test::Assemble(assembly));
1635   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1636   auto fe = p->function_emitter(100);
1637   fe.RegisterBasicBlocks();
1638   fe.ComputeBlockOrderAndPositions();
1639 
1640   EXPECT_THAT(fe.block_order(),
1641               ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
1642       << assembly;
1643 }
1644 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Nest_IfBreak_In_SwitchCase)1645 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_IfBreak_In_SwitchCase) {
1646   auto assembly = CommonTypes() + R"(
1647      %100 = OpFunction %void None %voidfn
1648 
1649      %10 = OpLabel
1650      OpSelectionMerge %99 None
1651      OpSwitch %selector %50 20 %20 50 %50
1652 
1653      %99 = OpLabel
1654      OpReturn
1655 
1656      %20 = OpLabel
1657      OpSelectionMerge %49 None
1658      OpBranchConditional %cond %99 %40 ; break-if
1659 
1660      %40 = OpLabel
1661      OpBranch %49
1662 
1663      %49 = OpLabel
1664      OpBranch %99
1665 
1666      %50 = OpLabel
1667      OpSelectionMerge %79 None
1668      OpBranchConditional %cond %60 %99 ; break-unless
1669 
1670      %60 = OpLabel
1671      OpBranch %79
1672 
1673      %79 = OpLabel ; dominated by 60, so must follow 60
1674      OpBranch %99
1675 
1676      OpFunctionEnd
1677   )";
1678   auto p = parser(test::Assemble(assembly));
1679   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1680   auto fe = p->function_emitter(100);
1681   fe.RegisterBasicBlocks();
1682   fe.ComputeBlockOrderAndPositions();
1683 
1684   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 49, 50, 60, 79, 99))
1685       << assembly;
1686 }
1687 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_SingleBlock_Simple)1688 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_Simple) {
1689   auto assembly = CommonTypes() + R"(
1690      %100 = OpFunction %void None %voidfn
1691 
1692      ; The entry block can't be the target of a branch
1693      %10 = OpLabel
1694      OpBranch %20
1695 
1696      %20 = OpLabel
1697      OpLoopMerge %99 %20 None
1698      OpBranchConditional %cond %20 %99
1699 
1700      %99 = OpLabel
1701      OpReturn
1702 
1703      OpFunctionEnd
1704   )";
1705   auto p = parser(test::Assemble(assembly));
1706   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1707   auto fe = p->function_emitter(100);
1708   fe.RegisterBasicBlocks();
1709   fe.ComputeBlockOrderAndPositions();
1710 
1711   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
1712 }
1713 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_SingleBlock_Infinite)1714 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_Infinite) {
1715   auto assembly = CommonTypes() + R"(
1716      %100 = OpFunction %void None %voidfn
1717 
1718      ; The entry block can't be the target of a branch
1719      %10 = OpLabel
1720      OpBranch %20
1721 
1722      %20 = OpLabel
1723      OpLoopMerge %99 %20 None
1724      OpBranch %20
1725 
1726      %99 = OpLabel
1727      OpReturn
1728 
1729      OpFunctionEnd
1730   )";
1731   auto p = parser(test::Assemble(assembly));
1732   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1733   auto fe = p->function_emitter(100);
1734   fe.RegisterBasicBlocks();
1735   fe.ComputeBlockOrderAndPositions();
1736 
1737   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
1738 }
1739 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_SingleBlock_DupInfinite)1740 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_DupInfinite) {
1741   auto assembly = CommonTypes() + R"(
1742      %100 = OpFunction %void None %voidfn
1743 
1744      ; The entry block can't be the target of a branch
1745      %10 = OpLabel
1746      OpBranch %20
1747 
1748      %20 = OpLabel
1749      OpLoopMerge %99 %20 None
1750      OpBranchConditional %cond %20 %20
1751 
1752      %99 = OpLabel
1753      OpReturn
1754 
1755      OpFunctionEnd
1756   )";
1757   auto p = parser(test::Assemble(assembly));
1758   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1759   auto fe = p->function_emitter(100);
1760   fe.RegisterBasicBlocks();
1761   fe.ComputeBlockOrderAndPositions();
1762 
1763   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
1764 }
1765 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_HeaderHasBreakIf)1766 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_HeaderHasBreakIf) {
1767   auto assembly = CommonTypes() + R"(
1768      %100 = OpFunction %void None %voidfn
1769 
1770      %10 = OpLabel
1771      OpBranch %20
1772 
1773      %20 = OpLabel
1774      OpLoopMerge %99 %50 None
1775      OpBranchConditional %cond %30 %99 ; like While
1776 
1777      %30 = OpLabel ; trivial body
1778      OpBranch %50
1779 
1780      %50 = OpLabel
1781      OpBranch %20
1782 
1783      %99 = OpLabel
1784      OpReturn
1785 
1786      OpFunctionEnd
1787   )";
1788   auto p = parser(test::Assemble(assembly));
1789   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1790   auto fe = p->function_emitter(100);
1791   fe.RegisterBasicBlocks();
1792   fe.ComputeBlockOrderAndPositions();
1793 
1794   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
1795 }
1796 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_HeaderHasBreakUnless)1797 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_HeaderHasBreakUnless) {
1798   auto assembly = CommonTypes() + R"(
1799      %100 = OpFunction %void None %voidfn
1800 
1801      %10 = OpLabel
1802      OpBranch %20
1803 
1804      %20 = OpLabel
1805      OpLoopMerge %99 %50 None
1806      OpBranchConditional %cond %99 %30 ; has break-unless
1807 
1808      %30 = OpLabel ; trivial body
1809      OpBranch %50
1810 
1811      %50 = OpLabel
1812      OpBranch %20
1813 
1814      %99 = OpLabel
1815      OpReturn
1816 
1817      OpFunctionEnd
1818   )";
1819   auto p = parser(test::Assemble(assembly));
1820   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1821   auto fe = p->function_emitter(100);
1822   fe.RegisterBasicBlocks();
1823   fe.ComputeBlockOrderAndPositions();
1824 
1825   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
1826 }
1827 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasBreak)1828 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreak) {
1829   auto assembly = CommonTypes() + R"(
1830      %100 = OpFunction %void None %voidfn
1831 
1832      %10 = OpLabel
1833      OpBranch %20
1834 
1835      %20 = OpLabel
1836      OpLoopMerge %99 %50 None
1837      OpBranchConditional %cond %30 %99
1838 
1839      %30 = OpLabel
1840      OpBranch %99 ; break
1841 
1842      %50 = OpLabel
1843      OpBranch %20
1844 
1845      %99 = OpLabel
1846      OpReturn
1847 
1848      OpFunctionEnd
1849   )";
1850   auto p = parser(test::Assemble(assembly));
1851   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1852   auto fe = p->function_emitter(100);
1853   fe.RegisterBasicBlocks();
1854   fe.ComputeBlockOrderAndPositions();
1855 
1856   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
1857 }
1858 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasBreakIf)1859 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreakIf) {
1860   auto assembly = CommonTypes() + R"(
1861      %100 = OpFunction %void None %voidfn
1862 
1863      %10 = OpLabel
1864      OpBranch %20
1865 
1866      %20 = OpLabel
1867      OpLoopMerge %99 %50 None
1868      OpBranchConditional %cond %30 %99
1869 
1870      %30 = OpLabel
1871      OpBranchConditional %cond2 %99 %40 ; break-if
1872 
1873      %40 = OpLabel
1874      OpBranch %50
1875 
1876      %50 = OpLabel
1877      OpBranch %20
1878 
1879      %99 = OpLabel
1880      OpReturn
1881 
1882      OpFunctionEnd
1883   )";
1884   auto p = parser(test::Assemble(assembly));
1885   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1886   auto fe = p->function_emitter(100);
1887   fe.RegisterBasicBlocks();
1888   fe.ComputeBlockOrderAndPositions();
1889 
1890   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
1891       << assembly;
1892 }
1893 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasBreakUnless)1894 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreakUnless) {
1895   auto assembly = CommonTypes() + R"(
1896      %100 = OpFunction %void None %voidfn
1897 
1898      %10 = OpLabel
1899      OpBranch %20
1900 
1901      %20 = OpLabel
1902      OpLoopMerge %99 %50 None
1903      OpBranchConditional %cond %30 %99
1904 
1905      %30 = OpLabel
1906      OpBranchConditional %cond2 %40 %99 ; break-unless
1907 
1908      %40 = OpLabel
1909      OpBranch %50
1910 
1911      %50 = OpLabel
1912      OpBranch %20
1913 
1914      %99 = OpLabel
1915      OpReturn
1916 
1917      OpFunctionEnd
1918   )";
1919   auto p = parser(test::Assemble(assembly));
1920   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1921   auto fe = p->function_emitter(100);
1922   fe.RegisterBasicBlocks();
1923   fe.ComputeBlockOrderAndPositions();
1924 
1925   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
1926       << assembly;
1927 }
1928 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_If)1929 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If) {
1930   auto assembly = CommonTypes() + R"(
1931      %100 = OpFunction %void None %voidfn
1932 
1933      %10 = OpLabel
1934      OpBranch %20
1935 
1936      %20 = OpLabel
1937      OpLoopMerge %99 %50 None
1938      OpBranchConditional %cond %30 %99
1939 
1940      %30 = OpLabel
1941      OpSelectionMerge %49 None
1942      OpBranchConditional %cond2 %40 %45 ; nested if
1943 
1944      %40 = OpLabel
1945      OpBranch %49
1946 
1947      %45 = OpLabel
1948      OpBranch %49
1949 
1950      %49 = OpLabel
1951      OpBranch %50
1952 
1953      %50 = OpLabel
1954      OpBranch %20
1955 
1956      %99 = OpLabel
1957      OpReturn
1958 
1959      OpFunctionEnd
1960   )";
1961   auto p = parser(test::Assemble(assembly));
1962   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
1963   auto fe = p->function_emitter(100);
1964   fe.RegisterBasicBlocks();
1965   fe.ComputeBlockOrderAndPositions();
1966 
1967   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 45, 49, 50, 99))
1968       << assembly;
1969 }
1970 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_If_Break)1971 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If_Break) {
1972   auto assembly = CommonTypes() + R"(
1973      %100 = OpFunction %void None %voidfn
1974 
1975      %10 = OpLabel
1976      OpBranch %20
1977 
1978      %20 = OpLabel
1979      OpLoopMerge %99 %50 None
1980      OpBranchConditional %cond %30 %99
1981 
1982      %30 = OpLabel
1983      OpSelectionMerge %49 None
1984      OpBranchConditional %cond2 %40 %49 ; nested if
1985 
1986      %40 = OpLabel
1987      OpBranch %99   ; break from nested if
1988 
1989      %49 = OpLabel
1990      OpBranch %50
1991 
1992      %50 = OpLabel
1993      OpBranch %20
1994 
1995      %99 = OpLabel
1996      OpReturn
1997 
1998      OpFunctionEnd
1999   )";
2000   auto p = parser(test::Assemble(assembly));
2001   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2002   auto fe = p->function_emitter(100);
2003   fe.RegisterBasicBlocks();
2004   fe.ComputeBlockOrderAndPositions();
2005 
2006   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99))
2007       << assembly;
2008 }
2009 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasContinueIf)2010 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasContinueIf) {
2011   auto assembly = CommonTypes() + R"(
2012      %100 = OpFunction %void None %voidfn
2013 
2014      %10 = OpLabel
2015      OpBranch %20
2016 
2017      %20 = OpLabel
2018      OpLoopMerge %99 %50 None
2019      OpBranchConditional %cond %30 %99
2020 
2021      %30 = OpLabel
2022      OpBranchConditional %cond2 %50 %40 ; continue-if
2023 
2024      %40 = OpLabel
2025      OpBranch %50
2026 
2027      %50 = OpLabel
2028      OpBranch %20
2029 
2030      %99 = OpLabel
2031      OpReturn
2032 
2033      OpFunctionEnd
2034   )";
2035   auto p = parser(test::Assemble(assembly));
2036   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2037   auto fe = p->function_emitter(100);
2038   fe.RegisterBasicBlocks();
2039   fe.ComputeBlockOrderAndPositions();
2040 
2041   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
2042       << assembly;
2043 }
2044 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasContinueUnless)2045 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasContinueUnless) {
2046   auto assembly = CommonTypes() + R"(
2047      %100 = OpFunction %void None %voidfn
2048 
2049      %10 = OpLabel
2050      OpBranch %20
2051 
2052      %20 = OpLabel
2053      OpLoopMerge %99 %50 None
2054      OpBranchConditional %cond %30 %99
2055 
2056      %30 = OpLabel
2057      OpBranchConditional %cond2 %40 %50 ; continue-unless
2058 
2059      %40 = OpLabel
2060      OpBranch %50
2061 
2062      %50 = OpLabel
2063      OpBranch %20
2064 
2065      %99 = OpLabel
2066      OpReturn
2067 
2068      OpFunctionEnd
2069   )";
2070   auto p = parser(test::Assemble(assembly));
2071   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2072   auto fe = p->function_emitter(100);
2073   fe.RegisterBasicBlocks();
2074   fe.ComputeBlockOrderAndPositions();
2075 
2076   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
2077       << assembly;
2078 }
2079 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_If_Continue)2080 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If_Continue) {
2081   auto assembly = CommonTypes() + R"(
2082      %100 = OpFunction %void None %voidfn
2083 
2084      %10 = OpLabel
2085      OpBranch %20
2086 
2087      %20 = OpLabel
2088      OpLoopMerge %99 %50 None
2089      OpBranchConditional %cond %30 %99
2090 
2091      %30 = OpLabel
2092      OpSelectionMerge %49 None
2093      OpBranchConditional %cond2 %40 %49 ; nested if
2094 
2095      %40 = OpLabel
2096      OpBranch %50   ; continue from nested if
2097 
2098      %49 = OpLabel
2099      OpBranch %50
2100 
2101      %50 = OpLabel
2102      OpBranch %20
2103 
2104      %99 = OpLabel
2105      OpReturn
2106 
2107      OpFunctionEnd
2108   )";
2109   auto p = parser(test::Assemble(assembly));
2110   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2111   auto fe = p->function_emitter(100);
2112   fe.RegisterBasicBlocks();
2113   fe.ComputeBlockOrderAndPositions();
2114 
2115   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99))
2116       << assembly;
2117 }
2118 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_Switch)2119 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch) {
2120   auto assembly = CommonTypes() + R"(
2121      %100 = OpFunction %void None %voidfn
2122 
2123      %10 = OpLabel
2124      OpBranch %20
2125 
2126      %20 = OpLabel
2127      OpLoopMerge %99 %50 None
2128      OpBranchConditional %cond %30 %99
2129 
2130      %30 = OpLabel
2131      OpSelectionMerge %49 None
2132      OpSwitch %selector %49 40 %40 45 %45 ; fully nested switch
2133 
2134      %40 = OpLabel
2135      OpBranch %49
2136 
2137      %45 = OpLabel
2138      OpBranch %49
2139 
2140      %49 = OpLabel
2141      OpBranch %50
2142 
2143      %50 = OpLabel
2144      OpBranch %20
2145 
2146      %99 = OpLabel
2147      OpReturn
2148 
2149      OpFunctionEnd
2150   )";
2151   auto p = parser(test::Assemble(assembly));
2152   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2153   auto fe = p->function_emitter(100);
2154   fe.RegisterBasicBlocks();
2155   fe.ComputeBlockOrderAndPositions();
2156 
2157   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
2158       << assembly;
2159 }
2160 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_Switch_CaseBreaks)2161 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseBreaks) {
2162   auto assembly = CommonTypes() + R"(
2163      %100 = OpFunction %void None %voidfn
2164 
2165      %10 = OpLabel
2166      OpBranch %20
2167 
2168      %20 = OpLabel
2169      OpLoopMerge %99 %50 None
2170      OpBranchConditional %cond %30 %99
2171 
2172      %30 = OpLabel
2173      OpSelectionMerge %49 None
2174      OpSwitch %selector %49 40 %40 45 %45
2175 
2176      %40 = OpLabel
2177      ; This case breaks out of the loop. This is not possible in C
2178      ; because "break" will escape the switch only.
2179      OpBranch %99
2180 
2181      %45 = OpLabel
2182      OpBranch %49
2183 
2184      %49 = OpLabel
2185      OpBranch %50
2186 
2187      %50 = OpLabel
2188      OpBranch %20
2189 
2190      %99 = OpLabel
2191      OpReturn
2192 
2193      OpFunctionEnd
2194   )";
2195   auto p = parser(test::Assemble(assembly));
2196   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2197   auto fe = p->function_emitter(100);
2198   fe.RegisterBasicBlocks();
2199   fe.ComputeBlockOrderAndPositions();
2200 
2201   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
2202       << assembly;
2203 
2204   // Fails SPIR-V validation:
2205   // Branch from block 40 to block 99 is an invalid exit from construct starting
2206   // at block 30; branch bypasses merge block 49
2207   p->DeliberatelyInvalidSpirv();
2208 }
2209 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Body_Switch_CaseContinues)2210 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseContinues) {
2211   auto assembly = CommonTypes() + R"(
2212      %100 = OpFunction %void None %voidfn
2213 
2214      %10 = OpLabel
2215      OpBranch %20
2216 
2217      %20 = OpLabel
2218      OpLoopMerge %99 %50 None
2219      OpBranchConditional %cond %30 %99
2220 
2221      %30 = OpLabel
2222      OpSelectionMerge %49 None
2223      OpSwitch %selector %49 40 %40 45 %45
2224 
2225      %40 = OpLabel
2226      OpBranch %50   ; continue bypasses switch merge
2227 
2228      %45 = OpLabel
2229      OpBranch %49
2230 
2231      %49 = OpLabel
2232      OpBranch %50
2233 
2234      %50 = OpLabel
2235      OpBranch %20
2236 
2237      %99 = OpLabel
2238      OpReturn
2239 
2240      OpFunctionEnd
2241   )";
2242   auto p = parser(test::Assemble(assembly));
2243   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2244   auto fe = p->function_emitter(100);
2245   fe.RegisterBasicBlocks();
2246   fe.ComputeBlockOrderAndPositions();
2247 
2248   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
2249       << assembly;
2250 }
2251 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak)2252 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak) {
2253   auto assembly = CommonTypes() + R"(
2254      %100 = OpFunction %void None %voidfn
2255 
2256      %10 = OpLabel
2257      OpBranch %20
2258 
2259      %20 = OpLabel
2260      OpLoopMerge %99 %50 None
2261      OpBranchConditional %cond %30 %99
2262 
2263      %30 = OpLabel
2264      ; OpSwitch must be preceded by a selection merge
2265      OpSwitch %selector %99 50 %50 ; default is break, 50 is continue
2266 
2267      %40 = OpLabel
2268      OpBranch %50
2269 
2270      %50 = OpLabel
2271      OpBranch %20
2272 
2273      %99 = OpLabel
2274      OpReturn
2275 
2276      OpFunctionEnd
2277   )";
2278   auto p = parser(test::Assemble(assembly));
2279   EXPECT_FALSE(p->Parse());
2280   EXPECT_FALSE(p->success());
2281   EXPECT_THAT(p->error(),
2282               HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
2283 }
2284 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Continue_Sequence)2285 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_Sequence) {
2286   auto assembly = CommonTypes() + R"(
2287      %100 = OpFunction %void None %voidfn
2288 
2289      %10 = OpLabel
2290      OpBranch %20
2291 
2292      %20 = OpLabel
2293      OpLoopMerge %99 %50 None
2294      OpBranchConditional %cond %30 %99
2295 
2296      %30 = OpLabel
2297      OpBranch %50
2298 
2299      %50 = OpLabel
2300      OpBranch %60
2301 
2302      %60 = OpLabel
2303      OpBranch %20
2304 
2305      %99 = OpLabel
2306      OpReturn
2307 
2308      OpFunctionEnd
2309   )";
2310   auto p = parser(test::Assemble(assembly));
2311   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2312   auto fe = p->function_emitter(100);
2313   fe.RegisterBasicBlocks();
2314   fe.ComputeBlockOrderAndPositions();
2315 
2316   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 99));
2317 }
2318 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Continue_ContainsIf)2319 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_ContainsIf) {
2320   auto assembly = CommonTypes() + R"(
2321      %100 = OpFunction %void None %voidfn
2322 
2323      %10 = OpLabel
2324      OpBranch %20
2325 
2326      %20 = OpLabel
2327      OpLoopMerge %99 %50 None
2328      OpBranchConditional %cond %30 %99
2329 
2330      %30 = OpLabel
2331      OpBranch %50
2332 
2333      %50 = OpLabel
2334      OpSelectionMerge %89 None
2335      OpBranchConditional %cond2 %60 %70
2336 
2337      %89 = OpLabel
2338      OpBranch %20 ; backedge
2339 
2340      %60 = OpLabel
2341      OpBranch %89
2342 
2343      %70 = OpLabel
2344      OpBranch %89
2345 
2346      %99 = OpLabel
2347      OpReturn
2348 
2349      OpFunctionEnd
2350   )";
2351   auto p = parser(test::Assemble(assembly));
2352   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2353   auto fe = p->function_emitter(100);
2354   fe.RegisterBasicBlocks();
2355   fe.ComputeBlockOrderAndPositions();
2356 
2357   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 70, 89, 99));
2358 }
2359 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Continue_HasBreakIf)2360 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_HasBreakIf) {
2361   auto assembly = CommonTypes() + R"(
2362      %100 = OpFunction %void None %voidfn
2363 
2364      %10 = OpLabel
2365      OpBranch %20
2366 
2367      %20 = OpLabel
2368      OpLoopMerge %99 %50 None
2369      OpBranchConditional %cond %30 %99
2370 
2371      %30 = OpLabel
2372      OpBranch %50
2373 
2374      %50 = OpLabel
2375      OpBranchConditional %cond2 %99 %20
2376 
2377      %99 = OpLabel
2378      OpReturn
2379 
2380      OpFunctionEnd
2381   )";
2382   auto p = parser(test::Assemble(assembly));
2383   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2384   auto fe = p->function_emitter(100);
2385   fe.RegisterBasicBlocks();
2386   fe.ComputeBlockOrderAndPositions();
2387 
2388   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
2389 }
2390 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Continue_HasBreakUnless)2391 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_HasBreakUnless) {
2392   auto assembly = CommonTypes() + R"(
2393      %100 = OpFunction %void None %voidfn
2394 
2395      %10 = OpLabel
2396      OpBranch %20
2397 
2398      %20 = OpLabel
2399      OpLoopMerge %99 %50 None
2400      OpBranchConditional %cond %30 %99
2401 
2402      %30 = OpLabel
2403      OpBranch %50
2404 
2405      %50 = OpLabel
2406      OpBranchConditional %cond2 %20 %99
2407 
2408      %99 = OpLabel
2409      OpReturn
2410 
2411      OpFunctionEnd
2412   )";
2413   auto p = parser(test::Assemble(assembly));
2414   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2415   auto fe = p->function_emitter(100);
2416   fe.RegisterBasicBlocks();
2417   fe.ComputeBlockOrderAndPositions();
2418 
2419   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
2420 }
2421 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Continue_SwitchBreak)2422 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_SwitchBreak) {
2423   auto assembly = CommonTypes() + R"(
2424      %100 = OpFunction %void None %voidfn
2425 
2426      %10 = OpLabel
2427      OpBranch %20
2428 
2429      %20 = OpLabel
2430      OpLoopMerge %99 %50 None
2431      OpBranchConditional %cond %30 %99
2432 
2433      %30 = OpLabel
2434      OpBranch %50
2435 
2436      %50 = OpLabel
2437      ; Updated SPIR-V rule:
2438      ; OpSwitch must be preceded by a selection.
2439      OpSwitch %selector %20 99 %99
2440 
2441      %99 = OpLabel
2442      OpReturn
2443 
2444      OpFunctionEnd
2445   )";
2446   auto p = parser(test::Assemble(assembly));
2447   EXPECT_FALSE(p->Parse());
2448   EXPECT_FALSE(p->success());
2449   EXPECT_THAT(p->error(),
2450               HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
2451 }
2452 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop)2453 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop) {
2454   auto assembly = CommonTypes() + R"(
2455      %100 = OpFunction %void None %voidfn
2456 
2457      %10 = OpLabel
2458      OpBranch %20
2459 
2460      %20 = OpLabel
2461      OpLoopMerge %99 %50 None
2462      OpBranchConditional %cond %30 %99
2463 
2464      %30 = OpLabel
2465      OpLoopMerge %49 %40 None
2466      OpBranchConditional %cond2 %35 %49
2467 
2468      %35 = OpLabel
2469      OpBranch %37
2470 
2471      %37 = OpLabel
2472      OpBranch %40
2473 
2474      %40 = OpLabel ; inner loop's continue
2475      OpBranch %30 ; backedge
2476 
2477      %49 = OpLabel ; inner loop's merge
2478      OpBranch %50
2479 
2480      %50 = OpLabel ; outer loop's continue
2481      OpBranch %20 ; outer loop's backege
2482 
2483      %99 = OpLabel
2484      OpReturn
2485 
2486      OpFunctionEnd
2487   )";
2488   auto p = parser(test::Assemble(assembly));
2489   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2490   auto fe = p->function_emitter(100);
2491   fe.RegisterBasicBlocks();
2492   fe.ComputeBlockOrderAndPositions();
2493 
2494   EXPECT_THAT(fe.block_order(),
2495               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2496 }
2497 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop_InnerBreak)2498 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerBreak) {
2499   auto assembly = CommonTypes() + R"(
2500      %100 = OpFunction %void None %voidfn
2501 
2502      %10 = OpLabel
2503      OpBranch %20
2504 
2505      %20 = OpLabel
2506      OpLoopMerge %99 %50 None
2507      OpBranchConditional %cond %30 %99
2508 
2509      %30 = OpLabel
2510      OpLoopMerge %49 %40 None
2511      OpBranchConditional %cond2 %35 %49
2512 
2513      %35 = OpLabel
2514      OpBranchConditional %cond3 %49 %37 ; break to inner merge
2515 
2516      %37 = OpLabel
2517      OpBranch %40
2518 
2519      %40 = OpLabel ; inner loop's continue
2520      OpBranch %30 ; backedge
2521 
2522      %49 = OpLabel ; inner loop's merge
2523      OpBranch %50
2524 
2525      %50 = OpLabel ; outer loop's continue
2526      OpBranch %20 ; outer loop's backege
2527 
2528      %99 = OpLabel
2529      OpReturn
2530 
2531      OpFunctionEnd
2532   )";
2533   auto p = parser(test::Assemble(assembly));
2534   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2535   auto fe = p->function_emitter(100);
2536   fe.RegisterBasicBlocks();
2537   fe.ComputeBlockOrderAndPositions();
2538 
2539   EXPECT_THAT(fe.block_order(),
2540               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2541 }
2542 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop_InnerContinue)2543 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinue) {
2544   auto assembly = CommonTypes() + R"(
2545      %100 = OpFunction %void None %voidfn
2546 
2547      %10 = OpLabel
2548      OpBranch %20
2549 
2550      %20 = OpLabel
2551      OpLoopMerge %99 %50 None
2552      OpBranchConditional %cond %30 %99
2553 
2554      %30 = OpLabel
2555      OpLoopMerge %49 %40 None
2556      OpBranchConditional %cond2 %35 %49
2557 
2558      %35 = OpLabel
2559      OpBranchConditional %cond3 %37 %49 ; continue to inner continue target
2560 
2561      %37 = OpLabel
2562      OpBranch %40
2563 
2564      %40 = OpLabel ; inner loop's continue
2565      OpBranch %30 ; backedge
2566 
2567      %49 = OpLabel ; inner loop's merge
2568      OpBranch %50
2569 
2570      %50 = OpLabel ; outer loop's continue
2571      OpBranch %20 ; outer loop's backege
2572 
2573      %99 = OpLabel
2574      OpReturn
2575 
2576      OpFunctionEnd
2577   )";
2578   auto p = parser(test::Assemble(assembly));
2579   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2580   auto fe = p->function_emitter(100);
2581   fe.RegisterBasicBlocks();
2582   fe.ComputeBlockOrderAndPositions();
2583 
2584   EXPECT_THAT(fe.block_order(),
2585               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2586 }
2587 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop_InnerContinueBreaks)2588 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinueBreaks) {
2589   auto assembly = CommonTypes() + R"(
2590      %100 = OpFunction %void None %voidfn
2591 
2592      %10 = OpLabel
2593      OpBranch %20
2594 
2595      %20 = OpLabel
2596      OpLoopMerge %99 %50 None
2597      OpBranchConditional %cond %30 %99
2598 
2599      %30 = OpLabel
2600      OpLoopMerge %49 %40 None
2601      OpBranchConditional %cond2 %35 %49
2602 
2603      %35 = OpLabel
2604      OpBranch %37
2605 
2606      %37 = OpLabel
2607      OpBranch %40
2608 
2609      %40 = OpLabel ; inner loop's continue
2610      OpBranchConditional %cond3 %30 %49 ; backedge and inner break
2611 
2612      %49 = OpLabel ; inner loop's merge
2613      OpBranch %50
2614 
2615      %50 = OpLabel ; outer loop's continue
2616      OpBranch %20 ; outer loop's backege
2617 
2618      %99 = OpLabel
2619      OpReturn
2620 
2621      OpFunctionEnd
2622   )";
2623   auto p = parser(test::Assemble(assembly));
2624   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2625   auto fe = p->function_emitter(100);
2626   fe.RegisterBasicBlocks();
2627   fe.ComputeBlockOrderAndPositions();
2628 
2629   EXPECT_THAT(fe.block_order(),
2630               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2631 }
2632 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop_InnerContinueContinues)2633 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinueContinues) {
2634   auto assembly = CommonTypes() + R"(
2635      %100 = OpFunction %void None %voidfn
2636 
2637      %10 = OpLabel
2638      OpBranch %20
2639 
2640      %20 = OpLabel
2641      OpLoopMerge %99 %50 None
2642      OpBranchConditional %cond %30 %99
2643 
2644      %30 = OpLabel
2645      OpLoopMerge %49 %40 None
2646      OpBranchConditional %cond2 %35 %49
2647 
2648      %35 = OpLabel
2649      OpBranch %37
2650 
2651      %37 = OpLabel
2652      OpBranch %40
2653 
2654      %40 = OpLabel ; inner loop's continue
2655      OpBranchConditional %cond3 %30 %50 ; backedge and continue to outer
2656 
2657      %49 = OpLabel ; inner loop's merge
2658      OpBranch %50
2659 
2660      %50 = OpLabel ; outer loop's continue
2661      OpBranch %20 ; outer loop's backege
2662 
2663      %99 = OpLabel
2664      OpReturn
2665 
2666      OpFunctionEnd
2667   )";
2668   auto p = parser(test::Assemble(assembly));
2669   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2670   auto fe = p->function_emitter(100);
2671   fe.RegisterBasicBlocks();
2672   fe.ComputeBlockOrderAndPositions();
2673 
2674   EXPECT_THAT(fe.block_order(),
2675               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2676 
2677   p->DeliberatelyInvalidSpirv();
2678   // SPIR-V validation fails:
2679   //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
2680   //    via a structured exit"
2681 }
2682 
TEST_F(SpvParserCFGTest,ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue)2683 TEST_F(SpvParserCFGTest,
2684        ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue) {
2685   auto assembly = CommonTypes() + R"(
2686      %100 = OpFunction %void None %voidfn
2687 
2688      %10 = OpLabel
2689      OpBranch %20
2690 
2691      %20 = OpLabel
2692      OpLoopMerge %99 %50 None
2693      OpBranchConditional %cond %30 %99
2694 
2695      %30 = OpLabel
2696      OpLoopMerge %49 %40 None
2697      OpBranchConditional %cond2 %35 %49
2698 
2699      %35 = OpLabel
2700      OpBranch %37
2701 
2702      %37 = OpLabel
2703      OpBranch %40
2704 
2705      %40 = OpLabel ; inner loop's continue
2706      ; This switch does triple duty:
2707      ; default -> backedge
2708      ; 49 -> loop break
2709      ; 49 -> inner loop break
2710      ; 50 -> outer loop continue
2711      OpSwitch %selector %30 49 %49 50 %50
2712 
2713      %49 = OpLabel ; inner loop's merge
2714      OpBranch %50
2715 
2716      %50 = OpLabel ; outer loop's continue
2717      OpBranch %20 ; outer loop's backege
2718 
2719      %99 = OpLabel
2720      OpReturn
2721 
2722      OpFunctionEnd
2723   )";
2724   auto p = parser(test::Assemble(assembly));
2725   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2726   auto fe = p->function_emitter(100);
2727   fe.RegisterBasicBlocks();
2728   fe.ComputeBlockOrderAndPositions();
2729 
2730   EXPECT_THAT(fe.block_order(),
2731               ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
2732 
2733   p->DeliberatelyInvalidSpirv();
2734   // SPIR-V validation fails:
2735   //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
2736   //    via a structured exit"
2737 }
2738 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_Selection_Good)2739 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_Selection_Good) {
2740   auto assembly = CommonTypes() + R"(
2741      %100 = OpFunction %void None %voidfn
2742 
2743      %10 = OpLabel
2744      OpSelectionMerge %99 None
2745      OpBranchConditional %cond %20 %30
2746 
2747      %20 = OpLabel
2748      OpBranch %99
2749 
2750      %30 = OpLabel
2751      OpBranch %99
2752 
2753      %99 = OpLabel
2754      OpReturn
2755 
2756      OpFunctionEnd
2757 )";
2758   auto p = parser(test::Assemble(assembly));
2759   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2760   auto fe = p->function_emitter(100);
2761   fe.RegisterBasicBlocks();
2762   fe.ComputeBlockOrderAndPositions();
2763   fe.RegisterMerges();
2764   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
2765 }
2766 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_SingleBlockLoop_Good)2767 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_SingleBlockLoop_Good) {
2768   auto assembly = CommonTypes() + R"(
2769      %100 = OpFunction %void None %voidfn
2770 
2771      %10 = OpLabel
2772      OpBranch %20
2773 
2774      %20 = OpLabel
2775      OpLoopMerge %99 %20 None
2776      OpBranchConditional %cond %20 %99
2777 
2778      %99 = OpLabel
2779      OpReturn
2780 
2781      OpFunctionEnd
2782 )";
2783   auto p = parser(test::Assemble(assembly));
2784   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2785   auto fe = p->function_emitter(100);
2786   fe.RegisterBasicBlocks();
2787   fe.ComputeBlockOrderAndPositions();
2788   fe.RegisterMerges();
2789   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder()) << p->error();
2790 }
2791 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_MultiBlockLoop_Good)2792 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_MultiBlockLoop_Good) {
2793   auto assembly = CommonTypes() + R"(
2794      %100 = OpFunction %void None %voidfn
2795 
2796      %10 = OpLabel
2797      OpBranch %20
2798 
2799      %20 = OpLabel
2800      OpLoopMerge %99 %30 None
2801      OpBranchConditional %cond %30 %99
2802 
2803      %30 = OpLabel
2804      OpBranch %20
2805 
2806      %99 = OpLabel
2807      OpReturn
2808 
2809      OpFunctionEnd
2810 )";
2811   auto p = parser(test::Assemble(assembly));
2812   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2813   auto fe = p->function_emitter(100);
2814   fe.RegisterBasicBlocks();
2815   fe.ComputeBlockOrderAndPositions();
2816   fe.RegisterMerges();
2817   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
2818 }
2819 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateMerge)2820 TEST_F(SpvParserCFGTest,
2821        VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateMerge) {
2822   auto assembly = CommonTypes() + R"(
2823      %100 = OpFunction %void None %voidfn
2824 
2825      %10 = OpLabel
2826      OpBranch %20
2827 
2828      %20 = OpLabel
2829      OpBranch %50
2830 
2831      %50 = OpLabel
2832      OpSelectionMerge %20 None ; this is backward
2833      OpBranchConditional %cond2 %60 %99
2834 
2835      %60 = OpLabel
2836      OpBranch %99
2837 
2838      %99 = OpLabel
2839      OpReturn
2840 
2841      OpFunctionEnd
2842 )";
2843   auto p = parser(test::Assemble(assembly));
2844   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2845   auto fe = p->function_emitter(100);
2846   fe.RegisterBasicBlocks();
2847   fe.ComputeBlockOrderAndPositions();
2848   fe.RegisterMerges();
2849   EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
2850   EXPECT_THAT(p->error(),
2851               Eq("Header 50 does not strictly dominate its merge block 20"))
2852       << *fe.GetBlockInfo(50) << std::endl
2853       << *fe.GetBlockInfo(20) << std::endl
2854       << Dump(fe.block_order());
2855 }
2856 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateContinueTarget)2857 TEST_F(
2858     SpvParserCFGTest,
2859     VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateContinueTarget) {  // NOLINT
2860   auto assembly = CommonTypes() + R"(
2861      %100 = OpFunction %void None %voidfn
2862 
2863      %10 = OpLabel
2864      OpBranch %20
2865 
2866      %20 = OpLabel
2867      OpBranch %50
2868 
2869      %50 = OpLabel
2870      OpLoopMerge %99 %20 None ; this is backward
2871      OpBranchConditional %cond %60 %99
2872 
2873      %60 = OpLabel
2874      OpBranch %50
2875 
2876      %99 = OpLabel
2877      OpReturn
2878 
2879      OpFunctionEnd
2880 )";
2881   auto p = parser(test::Assemble(assembly));
2882   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2883   auto fe = p->function_emitter(100);
2884   fe.RegisterBasicBlocks();
2885   fe.ComputeBlockOrderAndPositions();
2886   fe.RegisterMerges();
2887   EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
2888   EXPECT_THAT(p->error(),
2889               Eq("Loop header 50 does not dominate its continue target 20"))
2890       << *fe.GetBlockInfo(50) << std::endl
2891       << *fe.GetBlockInfo(20) << std::endl
2892       << Dump(fe.block_order());
2893 }
2894 
TEST_F(SpvParserCFGTest,VerifyHeaderContinueMergeOrder_MergeInsideContinueTarget)2895 TEST_F(SpvParserCFGTest,
2896        VerifyHeaderContinueMergeOrder_MergeInsideContinueTarget) {
2897   auto assembly = CommonTypes() + R"(
2898      %100 = OpFunction %void None %voidfn
2899 
2900      %10 = OpLabel
2901      OpBranch %50
2902 
2903      %50 = OpLabel
2904      OpLoopMerge %60 %70 None
2905      OpBranchConditional %cond %60 %99
2906 
2907      %60 = OpLabel
2908      OpBranch %70
2909 
2910      %70 = OpLabel
2911      OpBranch %50
2912 
2913      %99 = OpLabel
2914      OpReturn
2915 
2916      OpFunctionEnd
2917 )";
2918   auto p = parser(test::Assemble(assembly));
2919   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2920   auto fe = p->function_emitter(100);
2921   fe.RegisterBasicBlocks();
2922   fe.ComputeBlockOrderAndPositions();
2923   fe.RegisterMerges();
2924   EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
2925   EXPECT_THAT(p->error(),
2926               Eq("Merge block 60 for loop headed at block 50 appears at or "
2927                  "before the loop's continue construct headed by block 70"))
2928       << Dump(fe.block_order());
2929 }
2930 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_OuterConstructIsFunction_SingleBlock)2931 TEST_F(SpvParserCFGTest,
2932        LabelControlFlowConstructs_OuterConstructIsFunction_SingleBlock) {
2933   auto assembly = CommonTypes() + R"(
2934      %100 = OpFunction %void None %voidfn
2935 
2936      %10 = OpLabel
2937      OpReturn
2938 
2939      OpFunctionEnd
2940 )";
2941   auto p = parser(test::Assemble(assembly));
2942   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2943   auto fe = p->function_emitter(100);
2944   fe.RegisterBasicBlocks();
2945   fe.ComputeBlockOrderAndPositions();
2946   fe.RegisterMerges();
2947   EXPECT_TRUE(fe.LabelControlFlowConstructs());
2948   EXPECT_EQ(fe.constructs().size(), 1u);
2949   auto& c = fe.constructs().front();
2950   EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 "
2951                               "depth:0 parent:null }"));
2952   EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
2953 }
2954 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_OuterConstructIsFunction_MultiBlock)2955 TEST_F(SpvParserCFGTest,
2956        LabelControlFlowConstructs_OuterConstructIsFunction_MultiBlock) {
2957   auto assembly = CommonTypes() + R"(
2958      %100 = OpFunction %void None %voidfn
2959 
2960      %10 = OpLabel
2961      OpBranch %5
2962 
2963      %5 = OpLabel
2964      OpReturn
2965 
2966      OpFunctionEnd
2967 )";
2968   auto p = parser(test::Assemble(assembly));
2969   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
2970   auto fe = p->function_emitter(100);
2971   fe.RegisterBasicBlocks();
2972   fe.ComputeBlockOrderAndPositions();
2973   fe.RegisterMerges();
2974   EXPECT_TRUE(fe.LabelControlFlowConstructs());
2975   EXPECT_EQ(fe.constructs().size(), 1u);
2976   auto& c = fe.constructs().front();
2977   EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 "
2978                               "depth:0 parent:null }"));
2979   EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
2980   EXPECT_EQ(fe.GetBlockInfo(5)->construct, c.get());
2981 }
2982 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAndItsMerge)2983 TEST_F(SpvParserCFGTest,
2984        LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAndItsMerge) {
2985   auto assembly = CommonTypes() + R"(
2986      %100 = OpFunction %void None %voidfn
2987 
2988      %10 = OpLabel
2989      OpSelectionMerge %99 None
2990      OpBranchConditional %cond %20 %30
2991 
2992      %20 = OpLabel
2993      OpBranch %99
2994 
2995      %30 = OpLabel
2996      OpBranch %99
2997 
2998      %99 = OpLabel
2999      OpReturn
3000 
3001      OpFunctionEnd
3002 )";
3003   auto p = parser(test::Assemble(assembly));
3004   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3005   auto fe = p->function_emitter(100);
3006   fe.RegisterBasicBlocks();
3007   fe.ComputeBlockOrderAndPositions();
3008   fe.RegisterMerges();
3009   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3010   const auto& constructs = fe.constructs();
3011   EXPECT_EQ(constructs.size(), 2u);
3012   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3013   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
3014   Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
3015 })")) << constructs;
3016   // The block records the nearest enclosing construct.
3017   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3018   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3019   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
3020   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3021 }
3022 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_PaddingBlocksBeforeAndAfterStructuredConstruct)3023 TEST_F(
3024     SpvParserCFGTest,
3025     LabelControlFlowConstructs_PaddingBlocksBeforeAndAfterStructuredConstruct) {
3026   auto assembly = CommonTypes() + R"(
3027      %100 = OpFunction %void None %voidfn
3028 
3029      %5 = OpLabel
3030      OpBranch %10
3031 
3032      %10 = OpLabel
3033      OpSelectionMerge %99 None
3034      OpBranchConditional %cond %20 %30
3035 
3036      %20 = OpLabel
3037      OpBranch %99
3038 
3039      %30 = OpLabel
3040      OpBranch %99
3041 
3042      %99 = OpLabel
3043      OpBranch %200
3044 
3045      %200 = OpLabel
3046      OpReturn
3047 
3048      OpFunctionEnd
3049 )";
3050   auto p = parser(test::Assemble(assembly));
3051   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3052   auto fe = p->function_emitter(100);
3053   fe.RegisterBasicBlocks();
3054   fe.ComputeBlockOrderAndPositions();
3055   fe.RegisterMerges();
3056   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3057   const auto& constructs = fe.constructs();
3058   EXPECT_EQ(constructs.size(), 2u);
3059   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3060   Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
3061   Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
3062 })")) << constructs;
3063   // The block records the nearest enclosing construct.
3064   EXPECT_EQ(fe.GetBlockInfo(5)->construct, constructs[0].get());
3065   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3066   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3067   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
3068   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3069   EXPECT_EQ(fe.GetBlockInfo(200)->construct, constructs[0].get());
3070 }
3071 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_SwitchSelection)3072 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SwitchSelection) {
3073   auto assembly = CommonTypes() + R"(
3074      %100 = OpFunction %void None %voidfn
3075 
3076      %10 = OpLabel
3077      OpSelectionMerge %99 None
3078      OpSwitch %selector %40 20 %20 30 %30
3079 
3080      %20 = OpLabel
3081      OpBranch %99
3082 
3083      %30 = OpLabel
3084      OpBranch %99
3085 
3086      %40 = OpLabel
3087      OpBranch %99
3088 
3089      %99 = OpLabel
3090      OpReturn
3091 
3092      OpFunctionEnd
3093 )";
3094   auto p = parser(test::Assemble(assembly));
3095   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3096   auto fe = p->function_emitter(100);
3097   fe.RegisterBasicBlocks();
3098   fe.ComputeBlockOrderAndPositions();
3099   fe.RegisterMerges();
3100   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3101   const auto& constructs = fe.constructs();
3102   EXPECT_EQ(constructs.size(), 2u);
3103   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3104   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
3105   Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
3106 })")) << constructs;
3107   // The block records the nearest enclosing construct.
3108   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3109   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3110   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
3111   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
3112   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3113 }
3114 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_SingleBlockLoop)3115 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SingleBlockLoop) {
3116   auto assembly = CommonTypes() + R"(
3117      %100 = OpFunction %void None %voidfn
3118 
3119      %10 = OpLabel
3120      OpBranch %20
3121 
3122      %20 = OpLabel
3123      OpLoopMerge %99 %20 None
3124      OpBranchConditional %cond %20 %99
3125 
3126      %99 = OpLabel
3127      OpReturn
3128 
3129      OpFunctionEnd
3130 )";
3131   auto p = parser(test::Assemble(assembly));
3132   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3133   auto fe = p->function_emitter(100);
3134   fe.RegisterBasicBlocks();
3135   fe.ComputeBlockOrderAndPositions();
3136   fe.RegisterMerges();
3137   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3138   const auto& constructs = fe.constructs();
3139   EXPECT_EQ(constructs.size(), 2u);
3140   // A single-block loop consists *only* of a continue target with one block in
3141   // it.
3142   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3143   Construct{ Function [0,3) begin_id:10 end_id:0 depth:0 parent:null }
3144   Construct{ Continue [1,2) begin_id:20 end_id:99 depth:1 parent:Function@10 in-c:Continue@20 }
3145 })")) << constructs;
3146   // The block records the nearest enclosing construct.
3147   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3148   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3149   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3150 }
3151 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_MultiBlockLoop_HeaderIsNotContinue)3152 TEST_F(SpvParserCFGTest,
3153        LabelControlFlowConstructs_MultiBlockLoop_HeaderIsNotContinue) {
3154   // In this case, we have a continue construct and a non-empty loop construct.
3155   auto assembly = CommonTypes() + R"(
3156      %100 = OpFunction %void None %voidfn
3157 
3158      %10 = OpLabel
3159      OpBranch %20
3160 
3161      %20 = OpLabel
3162      OpLoopMerge %99 %40 None
3163      OpBranchConditional %cond %30 %99
3164 
3165      %30 = OpLabel
3166      OpBranch %40
3167 
3168      %40 = OpLabel
3169      OpBranch %50
3170 
3171      %50 = OpLabel
3172      OpBranch %20
3173 
3174      %99 = OpLabel
3175      OpReturn
3176 
3177      OpFunctionEnd
3178 )";
3179   auto p = parser(test::Assemble(assembly));
3180   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3181   auto fe = p->function_emitter(100);
3182   fe.RegisterBasicBlocks();
3183   fe.ComputeBlockOrderAndPositions();
3184   fe.RegisterMerges();
3185   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3186   const auto& constructs = fe.constructs();
3187   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3188   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
3189   Construct{ Continue [3,5) begin_id:40 end_id:99 depth:1 parent:Function@10 in-c:Continue@40 }
3190   Construct{ Loop [1,3) begin_id:20 end_id:40 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
3191 })")) << constructs;
3192   // The block records the nearest enclosing construct.
3193   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3194   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3195   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
3196   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
3197   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
3198   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3199 }
3200 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_MultiBlockLoop_HeaderIsContinue)3201 TEST_F(SpvParserCFGTest,
3202        LabelControlFlowConstructs_MultiBlockLoop_HeaderIsContinue) {
3203   // In this case, we have only a continue construct and no loop construct.
3204   auto assembly = CommonTypes() + R"(
3205      %100 = OpFunction %void None %voidfn
3206 
3207      %10 = OpLabel
3208      OpBranch %20
3209 
3210      %20 = OpLabel
3211      OpLoopMerge %99 %20 None
3212      OpBranch %30
3213 
3214      %30 = OpLabel
3215      OpBranch %40
3216 
3217      %40 = OpLabel
3218      OpBranch %50
3219 
3220      %50 = OpLabel
3221      OpBranchConditional %cond %20 %99
3222 
3223      %99 = OpLabel
3224      OpReturn
3225 
3226      OpFunctionEnd
3227 )";
3228   auto p = parser(test::Assemble(assembly));
3229   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3230   auto fe = p->function_emitter(100);
3231   fe.RegisterBasicBlocks();
3232   fe.ComputeBlockOrderAndPositions();
3233   fe.RegisterMerges();
3234   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3235   const auto& constructs = fe.constructs();
3236   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3237   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
3238   Construct{ Continue [1,5) begin_id:20 end_id:99 depth:1 parent:Function@10 in-c:Continue@20 }
3239 })")) << constructs;
3240   // The block records the nearest enclosing construct.
3241   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3242   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3243   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
3244   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
3245   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
3246   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3247 }
3248 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockLoop)3249 TEST_F(SpvParserCFGTest,
3250        LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockLoop) {
3251   auto assembly = CommonTypes() + R"(
3252      %100 = OpFunction %void None %voidfn
3253 
3254      %10 = OpLabel
3255      OpSelectionMerge %50 None
3256      OpBranchConditional %cond %20 %50
3257 
3258      %20 = OpLabel
3259      OpBranch %50
3260 
3261      ; %50 is the merge block for the selection starting at 10,
3262      ; and its own continue target.
3263      %50 = OpLabel
3264      OpLoopMerge %99 %50 None
3265      OpBranchConditional %cond %50 %99
3266 
3267      %99 = OpLabel
3268      OpReturn
3269 
3270      OpFunctionEnd
3271 )";
3272   auto p = parser(test::Assemble(assembly));
3273   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3274   auto fe = p->function_emitter(100);
3275   fe.RegisterBasicBlocks();
3276   fe.ComputeBlockOrderAndPositions();
3277   fe.RegisterMerges();
3278   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3279   const auto& constructs = fe.constructs();
3280   EXPECT_EQ(constructs.size(), 3u);
3281   // A single-block loop consists *only* of a continue target with one block in
3282   // it.
3283   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3284   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
3285   Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
3286   Construct{ Continue [2,3) begin_id:50 end_id:99 depth:1 parent:Function@10 in-c:Continue@50 }
3287 })")) << constructs;
3288   // The block records the nearest enclosing construct.
3289   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3290   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3291   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
3292   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3293 }
3294 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLoopHeader)3295 TEST_F(SpvParserCFGTest,
3296        LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLoopHeader) {
3297   auto assembly = CommonTypes() + R"(
3298      %100 = OpFunction %void None %voidfn
3299 
3300      %10 = OpLabel
3301      OpSelectionMerge %50 None
3302      OpBranchConditional %cond %20 %50
3303 
3304      %20 = OpLabel
3305      OpBranch %50
3306 
3307      ; %50 is the merge block for the selection starting at 10,
3308      ; and a loop block header but not its own continue target.
3309      %50 = OpLabel
3310      OpLoopMerge %99 %60 None
3311      OpBranchConditional %cond %60 %99
3312 
3313      %60 = OpLabel
3314      OpBranch %50
3315 
3316      %99 = OpLabel
3317      OpReturn
3318 
3319      OpFunctionEnd
3320 )";
3321   auto p = parser(test::Assemble(assembly));
3322   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3323   auto fe = p->function_emitter(100);
3324   fe.RegisterBasicBlocks();
3325   fe.ComputeBlockOrderAndPositions();
3326   fe.RegisterMerges();
3327   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3328   const auto& constructs = fe.constructs();
3329   EXPECT_EQ(constructs.size(), 4u);
3330   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3331   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
3332   Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
3333   Construct{ Continue [3,4) begin_id:60 end_id:99 depth:1 parent:Function@10 in-c:Continue@60 }
3334   Construct{ Loop [2,3) begin_id:50 end_id:60 depth:1 parent:Function@10 scope:[2,4) in-l:Loop@50 }
3335 })")) << constructs;
3336   // The block records the nearest enclosing construct.
3337   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3338   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
3339   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
3340   EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
3341   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3342 }
3343 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_If_If)3344 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_If) {
3345   auto assembly = CommonTypes() + R"(
3346      %100 = OpFunction %void None %voidfn
3347 
3348      %10 = OpLabel
3349      OpSelectionMerge %99 None
3350      OpBranchConditional %cond %20 %50
3351 
3352      %20 = OpLabel
3353      OpSelectionMerge %40 None
3354      OpBranchConditional %cond %30 %40 ;; true only
3355 
3356      %30 = OpLabel
3357      OpBranch %40
3358 
3359      %40 = OpLabel ; merge for first inner "if"
3360      OpBranch %49
3361 
3362      %49 = OpLabel ; an extra padding block
3363      OpBranch %99
3364 
3365      %50 = OpLabel
3366      OpSelectionMerge %89 None
3367      OpBranchConditional %cond %89 %60 ;; false only
3368 
3369      %60 = OpLabel
3370      OpBranch %89
3371 
3372      %89 = OpLabel
3373      OpBranch %99
3374 
3375      %99 = OpLabel
3376      OpReturn
3377 
3378      OpFunctionEnd
3379 )";
3380   auto p = parser(test::Assemble(assembly));
3381   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3382   auto fe = p->function_emitter(100);
3383   fe.RegisterBasicBlocks();
3384   fe.ComputeBlockOrderAndPositions();
3385   fe.RegisterMerges();
3386   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3387   const auto& constructs = fe.constructs();
3388   EXPECT_EQ(constructs.size(), 4u);
3389   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3390   Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
3391   Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
3392   Construct{ IfSelection [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 }
3393   Construct{ IfSelection [5,7) begin_id:50 end_id:89 depth:2 parent:IfSelection@10 }
3394 })")) << constructs;
3395   // The block records the nearest enclosing construct.
3396   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3397   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3398   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
3399   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
3400   EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
3401   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
3402   EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[3].get());
3403   EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
3404   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3405 }
3406 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_Switch_If)3407 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Switch_If) {
3408   auto assembly = CommonTypes() + R"(
3409      %100 = OpFunction %void None %voidfn
3410 
3411      %10 = OpLabel
3412      OpSelectionMerge %99 None
3413      OpSwitch %selector %99 20 %20 50 %50
3414 
3415      %20 = OpLabel ; if-then nested in case 20
3416      OpSelectionMerge %49 None
3417      OpBranchConditional %cond %30 %49
3418 
3419      %30 = OpLabel
3420      OpBranch %49
3421 
3422      %49 = OpLabel
3423      OpBranch %99
3424 
3425      %50 = OpLabel ; unles-then nested in case 50
3426      OpSelectionMerge %89 None
3427      OpBranchConditional %cond %89 %60
3428 
3429      %60 = OpLabel
3430      OpBranch %89
3431 
3432      %89 = OpLabel
3433      OpBranch %99
3434 
3435      %99 = OpLabel
3436      OpReturn
3437 
3438      OpFunctionEnd
3439 )";
3440   auto p = parser(test::Assemble(assembly));
3441   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3442   auto fe = p->function_emitter(100);
3443   fe.RegisterBasicBlocks();
3444   fe.ComputeBlockOrderAndPositions();
3445   fe.RegisterMerges();
3446   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3447   const auto& constructs = fe.constructs();
3448   EXPECT_EQ(constructs.size(), 4u);
3449   // The ordering among siblings depends on the computed block order.
3450   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3451   Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
3452   Construct{ SwitchSelection [0,7) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
3453   Construct{ IfSelection [1,3) begin_id:50 end_id:89 depth:2 parent:SwitchSelection@10 in-c-l-s:SwitchSelection@10 }
3454   Construct{ IfSelection [4,6) begin_id:20 end_id:49 depth:2 parent:SwitchSelection@10 in-c-l-s:SwitchSelection@10 }
3455 })")) << constructs;
3456   // The block records the nearest enclosing construct.
3457   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3458   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
3459   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3460   EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
3461   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
3462   EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
3463   EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
3464   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3465 }
3466 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_If_Switch)3467 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_Switch) {
3468   auto assembly = CommonTypes() + R"(
3469      %100 = OpFunction %void None %voidfn
3470 
3471      %10 = OpLabel
3472      OpSelectionMerge %99 None
3473      OpBranchConditional %cond %20 %99
3474 
3475      %20 = OpLabel
3476      OpSelectionMerge %89 None
3477      OpSwitch %selector %89 20 %30
3478 
3479      %30 = OpLabel
3480      OpBranch %89
3481 
3482      %89 = OpLabel
3483      OpBranch %99
3484 
3485      %99 = OpLabel
3486      OpReturn
3487 
3488      OpFunctionEnd
3489 )";
3490   auto p = parser(test::Assemble(assembly));
3491   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3492   auto fe = p->function_emitter(100);
3493   fe.RegisterBasicBlocks();
3494   fe.ComputeBlockOrderAndPositions();
3495   fe.RegisterMerges();
3496   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3497   const auto& constructs = fe.constructs();
3498   EXPECT_EQ(constructs.size(), 3u);
3499   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3500   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
3501   Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
3502   Construct{ SwitchSelection [1,3) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 in-c-l-s:SwitchSelection@20 }
3503 })")) << constructs;
3504   // The block records the nearest enclosing construct.
3505   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3506   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3507   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
3508   EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
3509   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3510 }
3511 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_Loop_Loop)3512 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_Loop) {
3513   auto assembly = CommonTypes() + R"(
3514      %100 = OpFunction %void None %voidfn
3515 
3516      %10 = OpLabel
3517      OpBranch %20
3518 
3519      %20 = OpLabel
3520      OpLoopMerge %89 %50 None
3521      OpBranchConditional %cond %30 %89
3522 
3523      %30 = OpLabel ; single block loop
3524      OpLoopMerge %40 %30 None
3525      OpBranchConditional %cond2 %30 %40
3526 
3527      %40 = OpLabel ; padding block
3528      OpBranch %50
3529 
3530      %50 = OpLabel ; outer continue target
3531      OpBranch %60
3532 
3533      %60 = OpLabel
3534      OpBranch %20
3535 
3536      %89 = OpLabel ; outer merge
3537      OpBranch %99
3538 
3539      %99 = OpLabel
3540      OpReturn
3541 
3542      OpFunctionEnd
3543 )";
3544   auto p = parser(test::Assemble(assembly));
3545   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3546   auto fe = p->function_emitter(100);
3547   fe.RegisterBasicBlocks();
3548   fe.ComputeBlockOrderAndPositions();
3549   fe.RegisterMerges();
3550   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3551   const auto& constructs = fe.constructs();
3552   EXPECT_EQ(constructs.size(), 4u);
3553   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3554   Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
3555   Construct{ Continue [4,6) begin_id:50 end_id:89 depth:1 parent:Function@10 in-c:Continue@50 }
3556   Construct{ Loop [1,4) begin_id:20 end_id:50 depth:1 parent:Function@10 scope:[1,6) in-l:Loop@20 }
3557   Construct{ Continue [2,3) begin_id:30 end_id:40 depth:2 parent:Loop@20 in-l:Loop@20 in-c:Continue@30 }
3558 })")) << constructs;
3559   // The block records the nearest enclosing construct.
3560   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3561   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3562   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3563   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
3564   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
3565   EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[1].get());
3566   EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[0].get());
3567   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3568 }
3569 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_Loop_If)3570 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_If) {
3571   auto assembly = CommonTypes() + R"(
3572      %100 = OpFunction %void None %voidfn
3573 
3574      %10 = OpLabel
3575      OpBranch %20
3576 
3577      %20 = OpLabel
3578      OpLoopMerge %99 %80 None
3579      OpBranchConditional %cond %30 %99
3580 
3581      %30 = OpLabel ; If, nested in the loop construct
3582      OpSelectionMerge %49 None
3583      OpBranchConditional %cond2 %40 %49
3584 
3585      %40 = OpLabel
3586      OpBranch %49
3587 
3588      %49 = OpLabel ; merge for inner if
3589      OpBranch %80
3590 
3591      %80 = OpLabel ; continue target
3592      OpBranch %20
3593 
3594      %99 = OpLabel
3595      OpReturn
3596 
3597      OpFunctionEnd
3598 )";
3599   auto p = parser(test::Assemble(assembly));
3600   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3601   auto fe = p->function_emitter(100);
3602   fe.RegisterBasicBlocks();
3603   fe.ComputeBlockOrderAndPositions();
3604   fe.RegisterMerges();
3605   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3606   const auto& constructs = fe.constructs();
3607   EXPECT_EQ(constructs.size(), 4u);
3608   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3609   Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
3610   Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
3611   Construct{ Loop [1,5) begin_id:20 end_id:80 depth:1 parent:Function@10 scope:[1,6) in-l:Loop@20 }
3612   Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Loop@20 in-l:Loop@20 }
3613 })")) << constructs;
3614   // The block records the nearest enclosing construct.
3615   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3616   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3617   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3618   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
3619   EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[2].get());
3620   EXPECT_EQ(fe.GetBlockInfo(80)->construct, constructs[1].get());
3621   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3622 }
3623 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_LoopContinue_If)3624 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_LoopContinue_If) {
3625   auto assembly = CommonTypes() + R"(
3626      %100 = OpFunction %void None %voidfn
3627 
3628      %10 = OpLabel
3629      OpBranch %20
3630 
3631      %20 = OpLabel
3632      OpLoopMerge %99 %30 None
3633      OpBranchConditional %cond %30 %99
3634 
3635      %30 = OpLabel ; If, nested at the top of the continue construct head
3636      OpSelectionMerge %49 None
3637      OpBranchConditional %cond2 %40 %49
3638 
3639      %40 = OpLabel
3640      OpBranch %49
3641 
3642      %49 = OpLabel ; merge for inner if, backedge
3643      OpBranch %20
3644 
3645      %99 = OpLabel
3646      OpReturn
3647 
3648      OpFunctionEnd
3649 )";
3650   auto p = parser(test::Assemble(assembly));
3651   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3652   auto fe = p->function_emitter(100);
3653   fe.RegisterBasicBlocks();
3654   fe.ComputeBlockOrderAndPositions();
3655   fe.RegisterMerges();
3656   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3657   const auto& constructs = fe.constructs();
3658   EXPECT_EQ(constructs.size(), 4u);
3659   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3660   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
3661   Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
3662   Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
3663   Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Continue@30 in-c:Continue@30 }
3664 })")) << constructs;
3665   // The block records the nearest enclosing construct.
3666   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3667   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3668   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3669   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
3670   EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
3671   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3672 }
3673 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_If_SingleBlockLoop)3674 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
3675   auto assembly = CommonTypes() + R"(
3676      %100 = OpFunction %void None %voidfn
3677 
3678      %10 = OpLabel
3679      OpSelectionMerge %99 None
3680      OpBranchConditional %cond %20 %99
3681 
3682      %20 = OpLabel
3683      OpLoopMerge %89 %20 None
3684      OpBranchConditional %cond %20 %89
3685 
3686      %89 = OpLabel
3687      OpBranch %99
3688 
3689      %99 = OpLabel
3690      OpReturn
3691 
3692      OpFunctionEnd
3693 )";
3694   auto p = parser(test::Assemble(assembly));
3695   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3696   auto fe = p->function_emitter(100);
3697   fe.RegisterBasicBlocks();
3698   fe.ComputeBlockOrderAndPositions();
3699   fe.RegisterMerges();
3700   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3701   const auto& constructs = fe.constructs();
3702   EXPECT_EQ(constructs.size(), 3u);
3703   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3704   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
3705   Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
3706   Construct{ Continue [1,2) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@20 }
3707 })")) << constructs;
3708   // The block records the nearest enclosing construct.
3709   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3710   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
3711   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3712 }
3713 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_Nest_If_MultiBlockLoop)3714 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
3715   auto assembly = CommonTypes() + R"(
3716      %100 = OpFunction %void None %voidfn
3717 
3718      %10 = OpLabel
3719      OpSelectionMerge %99 None
3720      OpBranchConditional %cond %20 %99
3721 
3722      %20 = OpLabel ; start loop body
3723      OpLoopMerge %89 %40 None
3724      OpBranchConditional %cond %30 %89
3725 
3726      %30 = OpLabel ; body block
3727      OpBranch %40
3728 
3729      %40 = OpLabel ; continue target
3730      OpBranch %50
3731 
3732      %50 = OpLabel ; backedge block
3733      OpBranch %20
3734 
3735      %89 = OpLabel ; merge for the loop
3736      OpBranch %99
3737 
3738      %99 = OpLabel ; merge for the if
3739      OpReturn
3740 
3741      OpFunctionEnd
3742 )";
3743   auto p = parser(test::Assemble(assembly));
3744   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3745   auto fe = p->function_emitter(100);
3746   fe.RegisterBasicBlocks();
3747   fe.ComputeBlockOrderAndPositions();
3748   fe.RegisterMerges();
3749   EXPECT_TRUE(fe.LabelControlFlowConstructs());
3750   const auto& constructs = fe.constructs();
3751   EXPECT_EQ(constructs.size(), 4u);
3752   EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
3753   Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
3754   Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
3755   Construct{ Continue [3,5) begin_id:40 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@40 }
3756   Construct{ Loop [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 scope:[1,5) in-l:Loop@20 }
3757 })")) << constructs;
3758   // The block records the nearest enclosing construct.
3759   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
3760   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
3761   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3762   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
3763   EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
3764   EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
3765   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3766 }
3767 
TEST_F(SpvParserCFGTest,LabelControlFlowConstructs_LoopInterallyDiverge)3768 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_LoopInterallyDiverge) {
3769   // In this case, insert a synthetic if-selection with the same blocks
3770   // as the loop construct.
3771   // crbug.com/tint/524
3772   auto assembly = CommonTypes() + R"(
3773      %100 = OpFunction %void None %voidfn
3774 
3775      %10 = OpLabel
3776      OpBranch %20
3777 
3778      %20 = OpLabel
3779      OpLoopMerge %99 %90 None
3780      OpBranchConditional %cond %30 %40 ; divergence to distinct targets in the body
3781 
3782        %30 = OpLabel
3783        OpBranch %90
3784 
3785        %40 = OpLabel
3786        OpBranch %90
3787 
3788      %90 = OpLabel ; continue target
3789      OpBranch %20
3790 
3791      %99 = OpLabel ; loop merge
3792      OpReturn
3793 
3794      OpFunctionEnd
3795 )";
3796   auto p = parser(test::Assemble(assembly));
3797   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3798   auto fe = p->function_emitter(100);
3799   ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
3800   const auto& constructs = fe.constructs();
3801   EXPECT_EQ(constructs.size(), 4u);
3802   ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{
3803   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
3804   Construct{ Continue [4,5) begin_id:90 end_id:99 depth:1 parent:Function@10 in-c:Continue@90 }
3805   Construct{ Loop [1,4) begin_id:20 end_id:90 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
3806   Construct{ IfSelection [1,4) begin_id:20 end_id:90 depth:2 parent:Loop@20 in-l:Loop@20 }
3807 })")) << constructs;
3808   // The block records the nearest enclosing construct.
3809   EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
3810   EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
3811   EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
3812   EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
3813   EXPECT_EQ(fe.GetBlockInfo(90)->construct, constructs[1].get());
3814   EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
3815 }
3816 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultIsLongRangeBackedge)3817 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsLongRangeBackedge) {
3818   auto assembly = CommonTypes() + R"(
3819      %100 = OpFunction %void None %voidfn
3820 
3821      %10 = OpLabel
3822      OpBranch %20
3823 
3824      %20 = OpLabel
3825      OpSelectionMerge %99 None
3826      OpSwitch %selector %10 30 %30
3827 
3828      %30 = OpLabel
3829      OpBranch %99
3830 
3831      %99 = OpLabel
3832      OpReturn
3833 
3834      OpFunctionEnd
3835 )";
3836   auto p = parser(test::Assemble(assembly));
3837   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3838   auto fe = p->function_emitter(100);
3839   fe.RegisterBasicBlocks();
3840   fe.ComputeBlockOrderAndPositions();
3841   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
3842   fe.RegisterMerges();
3843   fe.LabelControlFlowConstructs();
3844   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
3845   EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to default target "
3846                              "block 10 can't be a back-edge"));
3847 }
3848 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultIsSelfLoop)3849 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsSelfLoop) {
3850   auto assembly = CommonTypes() + R"(
3851      %100 = OpFunction %void None %voidfn
3852 
3853      %10 = OpLabel
3854      OpBranch %20
3855 
3856      %20 = OpLabel
3857      OpSelectionMerge %99 None
3858      OpSwitch %selector %20 30 %30
3859 
3860      %30 = OpLabel
3861      OpBranch %99
3862 
3863      %99 = OpLabel
3864      OpReturn
3865 
3866      OpFunctionEnd
3867 )";
3868   auto p = parser(test::Assemble(assembly));
3869   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3870   auto fe = p->function_emitter(100);
3871   fe.RegisterBasicBlocks();
3872   fe.ComputeBlockOrderAndPositions();
3873   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
3874   fe.RegisterMerges();
3875   fe.LabelControlFlowConstructs();
3876   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
3877   // Self-loop that isn't its own continue target is already rejected with a
3878   // different message.
3879   EXPECT_THAT(
3880       p->error(),
3881       Eq("Block 20 branches to itself but is not its own continue target"));
3882 }
3883 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultCantEscapeSwitch)3884 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultCantEscapeSwitch) {
3885   auto assembly = CommonTypes() + R"(
3886      %100 = OpFunction %void None %voidfn
3887 
3888      %10 = OpLabel
3889      OpSelectionMerge %50 None
3890      OpSwitch %selector %99 30 %30 ; default goes past the merge
3891 
3892      %30 = OpLabel
3893      OpBranch %50
3894 
3895      %50 = OpLabel ; merge
3896      OpBranch %99
3897 
3898      %99 = OpLabel
3899      OpReturn
3900 
3901      OpFunctionEnd
3902 )";
3903   auto p = parser(test::Assemble(assembly));
3904   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3905   auto fe = p->function_emitter(100);
3906   fe.RegisterBasicBlocks();
3907   fe.ComputeBlockOrderAndPositions();
3908   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
3909   fe.RegisterMerges();
3910   fe.LabelControlFlowConstructs();
3911   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
3912   EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to default block 99 "
3913                              "escapes the selection construct"));
3914 }
3915 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultForTwoSwitches_AsMerge)3916 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultForTwoSwitches_AsMerge) {
3917   auto assembly = CommonTypes() + R"(
3918      %100 = OpFunction %void None %voidfn
3919 
3920      %10 = OpLabel
3921      OpSelectionMerge %99 None
3922      OpSwitch %selector %89 20 %20
3923 
3924      %20 = OpLabel
3925      OpBranch %50
3926 
3927      %50 = OpLabel
3928      OpSelectionMerge %89 None
3929      OpSwitch %selector %89 60 %60
3930 
3931      %60 = OpLabel
3932      OpBranch %89
3933 
3934      %89 = OpLabel
3935      OpBranch %99
3936 
3937      %99 = OpLabel
3938      OpReturn
3939 
3940      OpFunctionEnd
3941 )";
3942   auto p = parser(test::Assemble(assembly));
3943   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3944   auto fe = p->function_emitter(100);
3945   fe.RegisterBasicBlocks();
3946   fe.ComputeBlockOrderAndPositions();
3947   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
3948   fe.RegisterMerges();
3949   fe.LabelControlFlowConstructs();
3950   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
3951   EXPECT_THAT(p->error(),
3952               Eq("Block 89 is the default block for switch-selection header 10 "
3953                  "and also the merge block for 50 (violates dominance rule)"));
3954 }
3955 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultForTwoSwitches_AsCaseClause)3956 TEST_F(SpvParserCFGTest,
3957        FindSwitchCaseHeaders_DefaultForTwoSwitches_AsCaseClause) {
3958   auto assembly = CommonTypes() + R"(
3959      %100 = OpFunction %void None %voidfn
3960 
3961      %10 = OpLabel
3962      OpSelectionMerge %99 None
3963      OpSwitch %selector %80 20 %20
3964 
3965      %20 = OpLabel
3966      OpBranch %50
3967 
3968      %50 = OpLabel
3969      OpSelectionMerge %89 None
3970      OpSwitch %selector %80 60 %60
3971 
3972      %60 = OpLabel
3973      OpBranch %89 ; fallthrough
3974 
3975      %80 = OpLabel ; default for both switches
3976      OpBranch %89
3977 
3978      %89 = OpLabel ; inner selection merge
3979      OpBranch %99
3980 
3981      %99 = OpLabel ; outer selection mege
3982      OpReturn
3983 
3984      OpFunctionEnd
3985 )";
3986   auto p = parser(test::Assemble(assembly));
3987   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
3988   auto fe = p->function_emitter(100);
3989   fe.RegisterBasicBlocks();
3990   fe.ComputeBlockOrderAndPositions();
3991   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
3992   fe.RegisterMerges();
3993   fe.LabelControlFlowConstructs();
3994   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
3995   EXPECT_THAT(p->error(), Eq("Block 80 is declared as the default target for "
3996                              "two OpSwitch instructions, at blocks 10 and 50"));
3997 }
3998 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseIsLongRangeBackedge)3999 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsLongRangeBackedge) {
4000   auto assembly = CommonTypes() + R"(
4001      %100 = OpFunction %void None %voidfn
4002 
4003      %10 = OpLabel
4004      OpBranch %20
4005 
4006      %20 = OpLabel
4007      OpSelectionMerge %99 None
4008      OpSwitch %selector %99 10 %10
4009 
4010      %99 = OpLabel
4011      OpReturn
4012 
4013      OpFunctionEnd
4014 )";
4015   auto p = parser(test::Assemble(assembly));
4016   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4017   auto fe = p->function_emitter(100);
4018   fe.RegisterBasicBlocks();
4019   fe.ComputeBlockOrderAndPositions();
4020   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4021   fe.RegisterMerges();
4022   fe.LabelControlFlowConstructs();
4023   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4024   EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target "
4025                              "block 10 can't be a back-edge"));
4026 }
4027 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseIsSelfLoop)4028 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsSelfLoop) {
4029   auto assembly = CommonTypes() + R"(
4030      %100 = OpFunction %void None %voidfn
4031 
4032      %10 = OpLabel
4033      OpBranch %20
4034 
4035      %20 = OpLabel
4036      OpSelectionMerge %99 None
4037      OpSwitch %selector %99 20 %20
4038 
4039      %99 = OpLabel
4040      OpReturn
4041 
4042      OpFunctionEnd
4043 )";
4044   auto p = parser(test::Assemble(assembly));
4045   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4046   auto fe = p->function_emitter(100);
4047   fe.RegisterBasicBlocks();
4048   fe.ComputeBlockOrderAndPositions();
4049   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4050   fe.RegisterMerges();
4051   fe.LabelControlFlowConstructs();
4052   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4053   // The error is caught earlier
4054   EXPECT_THAT(
4055       p->error(),
4056       Eq("Block 20 branches to itself but is not its own continue target"));
4057 }
4058 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseCanBeSwitchMerge)4059 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCanBeSwitchMerge) {
4060   auto assembly = CommonTypes() + R"(
4061      %100 = OpFunction %void None %voidfn
4062 
4063      %10 = OpLabel
4064      OpBranch %20
4065 
4066      %20 = OpLabel
4067      OpSelectionMerge %99 None
4068      OpSwitch %selector %99 20 %99
4069 
4070      %99 = OpLabel
4071      OpReturn
4072 
4073      OpFunctionEnd
4074 )";
4075   auto p = parser(test::Assemble(assembly));
4076   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4077   auto fe = p->function_emitter(100);
4078   fe.RegisterBasicBlocks();
4079   fe.ComputeBlockOrderAndPositions();
4080   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4081   fe.RegisterMerges();
4082   fe.LabelControlFlowConstructs();
4083   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4084 
4085   // TODO(crbug.com/tint/774) Re-enable after codegen bug fixed.
4086   p->DeliberatelyInvalidSpirv();
4087 }
4088 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseCantEscapeSwitch)4089 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCantEscapeSwitch) {
4090   auto assembly = CommonTypes() + R"(
4091      %100 = OpFunction %void None %voidfn
4092 
4093      %10 = OpLabel
4094      OpSelectionMerge %99 None ; force %99 to be very late in block order
4095      OpBranchConditional %cond %20 %99
4096 
4097      %20 = OpLabel
4098      OpSelectionMerge %89 None
4099      OpSwitch %selector %89 20 %99
4100 
4101      %89 = OpLabel
4102      OpBranch %99
4103 
4104      %99 = OpLabel
4105      OpReturn
4106 
4107      OpFunctionEnd
4108 )";
4109   auto p = parser(test::Assemble(assembly));
4110   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4111   auto fe = p->function_emitter(100);
4112   fe.RegisterBasicBlocks();
4113   fe.ComputeBlockOrderAndPositions();
4114   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4115   fe.RegisterMerges();
4116   fe.LabelControlFlowConstructs();
4117   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4118   EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target block "
4119                              "99 escapes the selection construct"));
4120 }
4121 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseForMoreThanOneSwitch)4122 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseForMoreThanOneSwitch) {
4123   auto assembly = CommonTypes() + R"(
4124      %100 = OpFunction %void None %voidfn
4125 
4126      %10 = OpLabel
4127      OpSelectionMerge %99 None
4128      OpSwitch %selector %99 20 %20 50 %50
4129 
4130      %20 = OpLabel
4131      OpSelectionMerge %89 None
4132      OpSwitch %selector %89 50 %50
4133 
4134      %50 = OpLabel
4135      OpBranch %89
4136 
4137      %89 = OpLabel
4138      OpBranch %99
4139 
4140      %99 = OpLabel
4141      OpReturn
4142 
4143      OpFunctionEnd
4144 )";
4145   auto p = parser(test::Assemble(assembly));
4146   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4147   auto fe = p->function_emitter(100);
4148   fe.RegisterBasicBlocks();
4149   fe.ComputeBlockOrderAndPositions();
4150   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4151   fe.RegisterMerges();
4152   fe.LabelControlFlowConstructs();
4153   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4154   EXPECT_THAT(p->error(),
4155               Eq("Block 50 is declared as the switch case target for two "
4156                  "OpSwitch instructions, at blocks 10 and 20"));
4157 }
4158 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseIsMergeForAnotherConstruct)4159 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsMergeForAnotherConstruct) {
4160   auto assembly = CommonTypes() + R"(
4161      %100 = OpFunction %void None %voidfn
4162 
4163      %10 = OpLabel
4164      OpSelectionMerge %49 None
4165      OpSwitch %selector %49 20 %20
4166 
4167      %20 = OpLabel
4168      OpBranch %49
4169 
4170      %49 = OpLabel
4171      OpBranch %50
4172 
4173      %50 = OpLabel
4174      OpSelectionMerge %20 None ; points back to the case.
4175      OpBranchConditional %cond %60 %99
4176 
4177      %60 = OpLabel
4178      OpBranch %99
4179 
4180      %99 = OpLabel
4181      OpReturn
4182 
4183      OpFunctionEnd
4184 )";
4185   auto p = parser(test::Assemble(assembly));
4186   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4187   auto fe = p->function_emitter(100);
4188   fe.RegisterBasicBlocks();
4189   fe.ComputeBlockOrderAndPositions();
4190   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4191   fe.RegisterMerges();
4192   fe.LabelControlFlowConstructs();
4193   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4194   EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to case target block "
4195                              "20 escapes the selection construct"));
4196 }
4197 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_NoSwitch)4198 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_NoSwitch) {
4199   auto assembly = CommonTypes() + R"(
4200      %100 = OpFunction %void None %voidfn
4201 
4202      %10 = OpLabel
4203      OpReturn
4204 
4205      OpFunctionEnd
4206 )";
4207   auto p = parser(test::Assemble(assembly));
4208   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4209   auto fe = p->function_emitter(100);
4210   fe.RegisterBasicBlocks();
4211   fe.ComputeBlockOrderAndPositions();
4212   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4213   fe.RegisterMerges();
4214   fe.LabelControlFlowConstructs();
4215   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4216 
4217   const auto* bi10 = fe.GetBlockInfo(10);
4218   ASSERT_NE(bi10, nullptr);
4219   EXPECT_EQ(bi10->case_head_for, nullptr);
4220   EXPECT_EQ(bi10->default_head_for, nullptr);
4221   EXPECT_FALSE(bi10->default_is_merge);
4222   EXPECT_EQ(bi10->case_values.get(), nullptr);
4223 }
4224 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultIsMerge)4225 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
4226   auto assembly = CommonTypes() + R"(
4227      %100 = OpFunction %void None %voidfn
4228 
4229      %10 = OpLabel
4230      OpSelectionMerge %99 None
4231      OpSwitch %selector %99 20 %20
4232 
4233      %20 = OpLabel
4234      OpBranch %99
4235 
4236      %99 = OpLabel
4237      OpReturn
4238 
4239      OpFunctionEnd
4240 )";
4241   auto p = parser(test::Assemble(assembly));
4242   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4243   auto fe = p->function_emitter(100);
4244   fe.RegisterBasicBlocks();
4245   fe.ComputeBlockOrderAndPositions();
4246   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4247   fe.RegisterMerges();
4248   fe.LabelControlFlowConstructs();
4249   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4250 
4251   const auto* bi99 = fe.GetBlockInfo(99);
4252   ASSERT_NE(bi99, nullptr);
4253   EXPECT_EQ(bi99->case_head_for, nullptr);
4254   ASSERT_NE(bi99->default_head_for, nullptr);
4255   EXPECT_EQ(bi99->default_head_for->begin_id, 10u);
4256   EXPECT_TRUE(bi99->default_is_merge);
4257   EXPECT_EQ(bi99->case_values.get(), nullptr);
4258 }
4259 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DefaultIsNotMerge)4260 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
4261   auto assembly = CommonTypes() + R"(
4262      %100 = OpFunction %void None %voidfn
4263 
4264      %10 = OpLabel
4265      OpSelectionMerge %99 None
4266      OpSwitch %selector %30 20 %20
4267 
4268      %20 = OpLabel
4269      OpBranch %99
4270 
4271      %30 = OpLabel
4272      OpBranch %99
4273 
4274      %99 = OpLabel
4275      OpReturn
4276 
4277      OpFunctionEnd
4278 )";
4279   auto p = parser(test::Assemble(assembly));
4280   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4281   auto fe = p->function_emitter(100);
4282   fe.RegisterBasicBlocks();
4283   fe.ComputeBlockOrderAndPositions();
4284   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4285   fe.RegisterMerges();
4286   fe.LabelControlFlowConstructs();
4287   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4288 
4289   const auto* bi30 = fe.GetBlockInfo(30);
4290   ASSERT_NE(bi30, nullptr);
4291   EXPECT_EQ(bi30->case_head_for, nullptr);
4292   ASSERT_NE(bi30->default_head_for, nullptr);
4293   EXPECT_EQ(bi30->default_head_for->begin_id, 10u);
4294   EXPECT_FALSE(bi30->default_is_merge);
4295   EXPECT_EQ(bi30->case_values.get(), nullptr);
4296 }
4297 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseIsNotDefault)4298 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
4299   auto assembly = CommonTypes() + R"(
4300      %100 = OpFunction %void None %voidfn
4301 
4302      %10 = OpLabel
4303      OpSelectionMerge %99 None
4304      OpSwitch %selector %30 200 %20
4305 
4306      %20 = OpLabel
4307      OpBranch %99
4308 
4309      %30 = OpLabel
4310      OpBranch %99
4311 
4312      %99 = OpLabel
4313      OpReturn
4314 
4315      OpFunctionEnd
4316 )";
4317   auto p = parser(test::Assemble(assembly));
4318   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4319   auto fe = p->function_emitter(100);
4320   fe.RegisterBasicBlocks();
4321   fe.ComputeBlockOrderAndPositions();
4322   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4323   fe.RegisterMerges();
4324   fe.LabelControlFlowConstructs();
4325   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4326 
4327   const auto* bi20 = fe.GetBlockInfo(20);
4328   ASSERT_NE(bi20, nullptr);
4329   ASSERT_NE(bi20->case_head_for, nullptr);
4330   EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
4331   EXPECT_EQ(bi20->default_head_for, nullptr);
4332   EXPECT_FALSE(bi20->default_is_merge);
4333   EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
4334 }
4335 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_CaseIsDefault)4336 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
4337   auto assembly = CommonTypes() + R"(
4338      %100 = OpFunction %void None %voidfn
4339 
4340      %10 = OpLabel
4341      OpSelectionMerge %99 None
4342      OpSwitch %selector %20 200 %20
4343 
4344      %20 = OpLabel
4345      OpBranch %99
4346 
4347      %99 = OpLabel
4348      OpReturn
4349 
4350      OpFunctionEnd
4351 )";
4352   auto p = parser(test::Assemble(assembly));
4353   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4354   auto fe = p->function_emitter(100);
4355   fe.RegisterBasicBlocks();
4356   fe.ComputeBlockOrderAndPositions();
4357   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4358   fe.RegisterMerges();
4359   fe.LabelControlFlowConstructs();
4360   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4361 
4362   const auto* bi20 = fe.GetBlockInfo(20);
4363   ASSERT_NE(bi20, nullptr);
4364   ASSERT_NE(bi20->case_head_for, nullptr);
4365   EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
4366   EXPECT_EQ(bi20->default_head_for, bi20->case_head_for);
4367   EXPECT_FALSE(bi20->default_is_merge);
4368   EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
4369 }
4370 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError)4371 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError) {
4372   auto assembly = CommonTypes() + R"(
4373      %100 = OpFunction %void None %voidfn
4374 
4375      %10 = OpLabel
4376      OpSelectionMerge %99 None
4377      OpSwitch %selector %99 200 %20 200 %30
4378 
4379      %20 = OpLabel
4380      OpBranch %99
4381 
4382      %30 = OpLabel
4383      OpBranch %99
4384 
4385      %99 = OpLabel
4386      OpReturn
4387 
4388      OpFunctionEnd
4389 )";
4390   auto p = parser(test::Assemble(assembly));
4391   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4392   auto fe = p->function_emitter(100);
4393   fe.RegisterBasicBlocks();
4394   fe.ComputeBlockOrderAndPositions();
4395   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4396   fe.RegisterMerges();
4397   fe.LabelControlFlowConstructs();
4398   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
4399 
4400   EXPECT_THAT(p->error(),
4401               Eq("Duplicate case value 200 in OpSwitch in block 10"));
4402 }
4403 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_ManyValuesWithSameCase)4404 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyValuesWithSameCase) {
4405   auto assembly = CommonTypes() + R"(
4406      %100 = OpFunction %void None %voidfn
4407 
4408      %10 = OpLabel
4409      OpSelectionMerge %99 None
4410      OpSwitch %selector %99 200 %20 300 %20
4411 
4412      %20 = OpLabel
4413      OpBranch %99
4414 
4415      %99 = OpLabel
4416      OpReturn
4417 
4418      OpFunctionEnd
4419 )";
4420   auto p = parser(test::Assemble(assembly));
4421   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4422   auto fe = p->function_emitter(100);
4423   fe.RegisterBasicBlocks();
4424   fe.ComputeBlockOrderAndPositions();
4425   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
4426   fe.RegisterMerges();
4427   fe.LabelControlFlowConstructs();
4428   EXPECT_TRUE(fe.FindSwitchCaseHeaders());
4429 
4430   const auto* bi20 = fe.GetBlockInfo(20);
4431   ASSERT_NE(bi20, nullptr);
4432   ASSERT_NE(bi20->case_head_for, nullptr);
4433   EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
4434   EXPECT_EQ(bi20->default_head_for, nullptr);
4435   EXPECT_FALSE(bi20->default_is_merge);
4436   EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200, 300));
4437 }
4438 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BranchEscapesIfConstruct)4439 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BranchEscapesIfConstruct) {
4440   auto assembly = CommonTypes() + R"(
4441      %100 = OpFunction %void None %voidfn
4442 
4443      %10 = OpLabel
4444      OpSelectionMerge %99 None
4445      OpBranchConditional %cond %20 %99
4446 
4447      %20 = OpLabel
4448      OpSelectionMerge %50 None
4449      OpBranchConditional %cond2 %30 %50
4450 
4451      %30 = OpLabel
4452      OpBranch %80   ; bad exit to %80
4453 
4454      %50 = OpLabel
4455      OpBranch %80
4456 
4457      %80 = OpLabel  ; bad target
4458      OpBranch %99
4459 
4460      %99 = OpLabel
4461      OpReturn
4462 
4463      OpFunctionEnd
4464 )";
4465   auto p = parser(test::Assemble(assembly));
4466   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4467   auto fe = p->function_emitter(100);
4468   EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
4469   // Some further processing
4470   EXPECT_THAT(
4471       p->error(),
4472       Eq("Branch from block 30 to block 80 is an invalid exit from construct "
4473          "starting at block 20; branch bypasses merge block 50"));
4474 }
4475 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_ReturnInContinueConstruct)4476 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_ReturnInContinueConstruct) {
4477   auto assembly = CommonTypes() + R"(
4478      %100 = OpFunction %void None %voidfn
4479 
4480      %10 = OpLabel
4481      OpBranch %20
4482 
4483      %20 = OpLabel
4484      OpLoopMerge %99 %50 None
4485      OpBranchConditional %cond %30 %99
4486 
4487      %30 = OpLabel ; body
4488      OpBranch %50
4489 
4490      %50 = OpLabel
4491      OpReturn
4492 
4493      %99 = OpLabel
4494      OpReturn
4495 
4496      OpFunctionEnd
4497 )";
4498   auto p = parser(test::Assemble(assembly));
4499   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4500   auto fe = p->function_emitter(100);
4501   EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
4502   EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
4503                              "construct starting at 50"));
4504 }
4505 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_KillInContinueConstruct)4506 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_KillInContinueConstruct) {
4507   auto assembly = CommonTypes() + R"(
4508      %100 = OpFunction %void None %voidfn
4509 
4510      %10 = OpLabel
4511      OpBranch %20
4512 
4513      %20 = OpLabel
4514      OpLoopMerge %99 %50 None
4515      OpBranchConditional %cond %30 %99
4516 
4517      %30 = OpLabel ; body
4518      OpBranch %50
4519 
4520      %50 = OpLabel
4521      OpKill
4522 
4523      %99 = OpLabel
4524      OpReturn
4525 
4526      OpFunctionEnd
4527 )";
4528   auto p = parser(test::Assemble(assembly));
4529   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4530   auto fe = p->function_emitter(100);
4531   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4532   EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
4533                              "construct starting at 50"));
4534 }
4535 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_UnreachableInContinueConstruct)4536 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_UnreachableInContinueConstruct) {
4537   auto assembly = CommonTypes() + R"(
4538      %100 = OpFunction %void None %voidfn
4539 
4540      %10 = OpLabel
4541      OpBranch %20
4542 
4543      %20 = OpLabel
4544      OpLoopMerge %99 %50 None
4545      OpBranchConditional %cond %30 %99
4546 
4547      %30 = OpLabel ; body
4548      OpBranch %50
4549 
4550      %50 = OpLabel
4551      OpUnreachable
4552 
4553      %99 = OpLabel
4554      OpReturn
4555 
4556      OpFunctionEnd
4557 )";
4558   auto p = parser(test::Assemble(assembly));
4559   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4560   auto fe = p->function_emitter(100);
4561   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4562   EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
4563                              "construct starting at 50"));
4564 }
4565 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_NotInContinueConstruct)4566 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_NotInContinueConstruct) {
4567   auto assembly = CommonTypes() + R"(
4568      %100 = OpFunction %void None %voidfn
4569 
4570      %10 = OpLabel
4571      OpBranch %20
4572 
4573      %20 = OpLabel
4574      OpLoopMerge %99 %50 None
4575      OpBranchConditional %cond %30 %99
4576 
4577      %30 = OpLabel ; body
4578      OpBranch %20  ; bad backedge
4579 
4580      %50 = OpLabel ; continue target
4581      OpBranch %99
4582 
4583      %99 = OpLabel
4584      OpReturn
4585 
4586      OpFunctionEnd
4587 )";
4588   auto p = parser(test::Assemble(assembly));
4589   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4590   auto fe = p->function_emitter(100);
4591   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4592   EXPECT_THAT(
4593       p->error(),
4594       Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
4595 }
4596 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_NotInLastBlockOfContinueConstruct)4597 TEST_F(SpvParserCFGTest,
4598        ClassifyCFGEdges_BackEdge_NotInLastBlockOfContinueConstruct) {
4599   auto assembly = CommonTypes() + R"(
4600      %100 = OpFunction %void None %voidfn
4601 
4602      %10 = OpLabel
4603      OpBranch %20
4604 
4605      %20 = OpLabel
4606      OpLoopMerge %99 %50 None
4607      OpBranchConditional %cond %30 %99
4608 
4609      %30 = OpLabel ; body
4610      OpBranch %50
4611 
4612      %50 = OpLabel ; continue target
4613      OpBranchConditional %cond %20 %60 ; bad branch to %20
4614 
4615      %60 = OpLabel ; end of continue construct
4616      OpBranch %20
4617 
4618      %99 = OpLabel
4619      OpReturn
4620 
4621      OpFunctionEnd
4622 )";
4623   auto p = parser(test::Assemble(assembly));
4624   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4625   auto fe = p->function_emitter(100);
4626   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4627   EXPECT_THAT(p->error(),
4628               Eq("Invalid exit (50->20) from continue construct: 50 is not the "
4629                  "last block in the continue construct starting at 50 "
4630                  "(violates post-dominance rule)"));
4631 }
4632 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_ToWrongHeader)4633 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_ToWrongHeader) {
4634   auto assembly = CommonTypes() + R"(
4635      %100 = OpFunction %void None %voidfn
4636 
4637      %10 = OpLabel
4638      OpSelectionMerge %99 None
4639      OpBranchConditional %cond %20 %99
4640 
4641      %20 = OpLabel
4642      OpLoopMerge %89 %50 None
4643      OpBranchConditional %cond %30 %89
4644 
4645      %30 = OpLabel ; loop body
4646      OpBranch %50
4647 
4648      %50 = OpLabel ; continue target
4649      OpBranch %10
4650 
4651      %89 = OpLabel ; inner merge
4652      OpBranch %99
4653 
4654      %99 = OpLabel ; outer merge
4655      OpReturn
4656 
4657      OpFunctionEnd
4658 )";
4659   auto p = parser(test::Assemble(assembly));
4660   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4661   auto fe = p->function_emitter(100);
4662   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4663   EXPECT_THAT(p->error(), Eq("Invalid backedge (50->10): does not branch to "
4664                              "the corresponding loop header, expected 20"));
4665 }
4666 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_SingleBlockLoop)4667 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_SingleBlockLoop) {
4668   auto assembly = CommonTypes() + R"(
4669      %100 = OpFunction %void None %voidfn
4670 
4671      %10 = OpLabel
4672      OpBranch %20
4673 
4674      %20 = OpLabel
4675      OpLoopMerge %99 %20 None
4676      OpBranchConditional %cond %20 %99
4677 
4678      %99 = OpLabel ; outer merge
4679      OpReturn
4680 
4681      OpFunctionEnd
4682 )";
4683   auto p = parser(test::Assemble(assembly));
4684   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4685   auto fe = p->function_emitter(100);
4686   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4687 
4688   auto* bi20 = fe.GetBlockInfo(20);
4689   ASSERT_NE(bi20, nullptr);
4690   EXPECT_EQ(bi20->succ_edge.count(20), 1u);
4691   EXPECT_EQ(bi20->succ_edge[20], EdgeKind::kBack);
4692 }
4693 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_MultiBlockLoop_SingleBlockContinueConstruct)4694 TEST_F(SpvParserCFGTest,
4695        ClassifyCFGEdges_BackEdge_MultiBlockLoop_SingleBlockContinueConstruct) {
4696   auto assembly = CommonTypes() + R"(
4697      %100 = OpFunction %void None %voidfn
4698 
4699      %10 = OpLabel
4700      OpBranch %20
4701 
4702      %20 = OpLabel
4703      OpLoopMerge %99 %40 None
4704      OpBranchConditional %cond %30 %99
4705 
4706      %30 = OpLabel
4707      OpBranch %40
4708 
4709      %40 = OpLabel ; continue target
4710      OpBranch %20  ; good back edge
4711 
4712      %99 = OpLabel ; outer merge
4713      OpReturn
4714 
4715      OpFunctionEnd
4716 )";
4717   auto p = parser(test::Assemble(assembly));
4718   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4719   auto fe = p->function_emitter(100);
4720   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4721 
4722   auto* bi40 = fe.GetBlockInfo(40);
4723   ASSERT_NE(bi40, nullptr);
4724   EXPECT_EQ(bi40->succ_edge.count(20), 1u);
4725   EXPECT_EQ(bi40->succ_edge[20], EdgeKind::kBack);
4726 }
4727 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsNotHeader)4728 TEST_F(
4729     SpvParserCFGTest,
4730     ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsNotHeader) {  // NOLINT
4731   auto assembly = CommonTypes() + R"(
4732      %100 = OpFunction %void None %voidfn
4733 
4734      %10 = OpLabel
4735      OpBranch %20
4736 
4737      %20 = OpLabel
4738      OpLoopMerge %99 %40 None
4739      OpBranchConditional %cond %30 %99
4740 
4741      %30 = OpLabel
4742      OpBranch %40
4743 
4744      %40 = OpLabel ; continue target
4745      OpBranch %50
4746 
4747      %50 = OpLabel
4748      OpBranch %20  ; good back edge
4749 
4750      %99 = OpLabel ; outer merge
4751      OpReturn
4752 
4753      OpFunctionEnd
4754 )";
4755   auto p = parser(test::Assemble(assembly));
4756   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4757   auto fe = p->function_emitter(100);
4758   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4759 
4760   auto* bi50 = fe.GetBlockInfo(50);
4761   ASSERT_NE(bi50, nullptr);
4762   EXPECT_EQ(bi50->succ_edge.count(20), 1u);
4763   EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
4764 }
4765 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsHeader)4766 TEST_F(
4767     SpvParserCFGTest,
4768     ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsHeader) {  // NOLINT
4769   auto assembly = CommonTypes() + R"(
4770      %100 = OpFunction %void None %voidfn
4771 
4772      %10 = OpLabel
4773      OpBranch %20
4774 
4775      %20 = OpLabel
4776      OpLoopMerge %99 %20 None ; continue target
4777      OpBranch %30
4778 
4779      %30 = OpLabel
4780      OpBranch %40
4781 
4782      %40 = OpLabel
4783      OpBranch %50
4784 
4785      %50 = OpLabel
4786      OpBranchConditional %cond %20 %99 ; good back edge
4787 
4788      %99 = OpLabel ; outer merge
4789      OpReturn
4790 
4791      OpFunctionEnd
4792 )";
4793   auto p = parser(test::Assemble(assembly));
4794   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4795   auto fe = p->function_emitter(100);
4796   EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
4797 
4798   auto* bi50 = fe.GetBlockInfo(50);
4799   ASSERT_NE(bi50, nullptr);
4800   EXPECT_EQ(bi50->succ_edge.count(20), 1u);
4801   EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
4802 }
4803 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_PrematureExitFromContinueConstruct)4804 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_PrematureExitFromContinueConstruct) {
4805   auto assembly = CommonTypes() + R"(
4806      %100 = OpFunction %void None %voidfn
4807 
4808      %10 = OpLabel
4809      OpBranch %20
4810 
4811      %20 = OpLabel
4812      OpLoopMerge %99 %40 None
4813      OpBranchConditional %cond %30 %99
4814 
4815      %30 = OpLabel
4816      OpBranch %40
4817 
4818      %40 = OpLabel ; continue construct
4819      OpBranchConditional %cond2 %99 %50 ; invalid early exit
4820 
4821      %50 = OpLabel
4822      OpBranch %20  ; back edge
4823 
4824      %99 = OpLabel ; outer merge
4825      OpReturn
4826 
4827      OpFunctionEnd
4828 )";
4829   auto p = parser(test::Assemble(assembly));
4830   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4831   auto fe = p->function_emitter(100);
4832   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
4833   EXPECT_THAT(p->error(),
4834               Eq("Invalid exit (40->99) from continue construct: 40 is not the "
4835                  "last block in the continue construct starting at 40 "
4836                  "(violates post-dominance rule)"));
4837 }
4838 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_TrueBranch)4839 TEST_F(SpvParserCFGTest,
4840        ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_TrueBranch) {
4841   auto assembly = CommonTypes() + R"(
4842      %100 = OpFunction %void None %voidfn
4843 
4844      %10 = OpLabel
4845      OpBranch %20
4846 
4847      %20 = OpLabel    ; single block loop
4848      OpLoopMerge %99 %20 None
4849      OpBranchConditional %cond %99 %20
4850 
4851      %99 = OpLabel ; outer merge
4852      OpReturn
4853 
4854      OpFunctionEnd
4855 )";
4856   auto p = parser(test::Assemble(assembly));
4857   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4858   auto fe = p->function_emitter(100);
4859   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4860 
4861   auto* bi = fe.GetBlockInfo(20);
4862   ASSERT_NE(bi, nullptr);
4863   EXPECT_EQ(bi->succ_edge.count(99), 1u);
4864   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
4865   EXPECT_EQ(bi->succ_edge.count(20), 1u);
4866   EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
4867 }
4868 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_FalseBranch)4869 TEST_F(SpvParserCFGTest,
4870        ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_FalseBranch) {
4871   auto assembly = CommonTypes() + R"(
4872      %100 = OpFunction %void None %voidfn
4873 
4874      %10 = OpLabel
4875      OpBranch %20
4876 
4877      %20 = OpLabel    ; single block loop
4878      OpLoopMerge %99 %20 None
4879      OpBranchConditional %cond %20 %99
4880 
4881      %99 = OpLabel ; outer merge
4882      OpReturn
4883 
4884      OpFunctionEnd
4885 )";
4886   auto p = parser(test::Assemble(assembly));
4887   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4888   auto fe = p->function_emitter(100);
4889   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4890 
4891   auto* bi = fe.GetBlockInfo(20);
4892   ASSERT_NE(bi, nullptr);
4893   EXPECT_EQ(bi->succ_edge.count(99), 1u);
4894   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
4895   EXPECT_EQ(bi->succ_edge.count(20), 1u);
4896   EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
4897 }
4898 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopHeader_MultiBlockLoop)4899 TEST_F(SpvParserCFGTest,
4900        ClassifyCFGEdges_LoopBreak_FromLoopHeader_MultiBlockLoop) {
4901   auto assembly = CommonTypes() + R"(
4902      %100 = OpFunction %void None %voidfn
4903 
4904      %10 = OpLabel
4905      OpBranch %20
4906 
4907      %20 = OpLabel
4908      OpLoopMerge %99 %30 None
4909      OpBranchConditional %cond %30 %99
4910 
4911      %30 = OpLabel
4912      OpBranch %20
4913 
4914      %99 = OpLabel
4915      OpReturn
4916 
4917      OpFunctionEnd
4918 )";
4919   auto p = parser(test::Assemble(assembly));
4920   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4921   auto fe = p->function_emitter(100);
4922   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4923 
4924   auto* bi = fe.GetBlockInfo(20);
4925   ASSERT_NE(bi, nullptr);
4926   EXPECT_EQ(bi->succ_edge.count(99), 1u);
4927   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
4928 }
4929 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromContinueConstructHeader)4930 TEST_F(SpvParserCFGTest,
4931        ClassifyCFGEdges_LoopBreak_FromContinueConstructHeader) {
4932   auto assembly = CommonTypes() + R"(
4933      %100 = OpFunction %void None %voidfn
4934 
4935      %10 = OpLabel
4936      OpBranch %20
4937 
4938      %20 = OpLabel
4939      OpLoopMerge %99 %30 None
4940      OpBranchConditional %cond %30 %99
4941 
4942      %30 = OpLabel ; Single block continue construct
4943      OpBranchConditional %cond2 %20 %99
4944 
4945      %99 = OpLabel
4946      OpReturn
4947 
4948      OpFunctionEnd
4949 )";
4950   auto p = parser(test::Assemble(assembly));
4951   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4952   auto fe = p->function_emitter(100);
4953   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4954 
4955   auto* bi = fe.GetBlockInfo(30);
4956   ASSERT_NE(bi, nullptr);
4957   EXPECT_EQ(bi->succ_edge.count(99), 1u);
4958   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
4959 }
4960 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_FromIfHeader)4961 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromIfHeader) {
4962   auto assembly = CommonTypes() + R"(
4963      %100 = OpFunction %void None %voidfn
4964 
4965      %10 = OpLabel
4966      OpSelectionMerge %99 None
4967      OpBranchConditional %cond %20 %99
4968 
4969      %20 = OpLabel
4970      OpBranch %99
4971 
4972      %99 = OpLabel
4973      OpReturn
4974 
4975      OpFunctionEnd
4976 )";
4977   auto p = parser(test::Assemble(assembly));
4978   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
4979   auto fe = p->function_emitter(100);
4980   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
4981 
4982   auto* bi = fe.GetBlockInfo(20);
4983   ASSERT_NE(bi, nullptr);
4984   EXPECT_EQ(bi->succ_edge.count(99), 1u);
4985   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kIfBreak);
4986 }
4987 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_FromIfThenElse)4988 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromIfThenElse) {
4989   auto assembly = CommonTypes() + R"(
4990      %100 = OpFunction %void None %voidfn
4991 
4992      %10 = OpLabel
4993      OpSelectionMerge %99 None
4994      OpBranchConditional %cond %20 %50
4995 
4996      %20 = OpLabel
4997      OpBranch %99
4998 
4999      %50 = OpLabel
5000      OpBranch %99
5001 
5002      %99 = OpLabel
5003      OpReturn
5004 
5005      OpFunctionEnd
5006 )";
5007   auto p = parser(test::Assemble(assembly));
5008   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5009   auto fe = p->function_emitter(100);
5010   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5011 
5012   // Then clause
5013   auto* bi20 = fe.GetBlockInfo(20);
5014   ASSERT_NE(bi20, nullptr);
5015   EXPECT_EQ(bi20->succ_edge.count(99), 1u);
5016   EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
5017 
5018   // Else clause
5019   auto* bi50 = fe.GetBlockInfo(50);
5020   ASSERT_NE(bi50, nullptr);
5021   EXPECT_EQ(bi50->succ_edge.count(99), 1u);
5022   EXPECT_EQ(bi50->succ_edge[99], EdgeKind::kIfBreak);
5023 }
5024 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_BypassesMerge_IsError)5025 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_BypassesMerge_IsError) {
5026   auto assembly = CommonTypes() + R"(
5027      %100 = OpFunction %void None %voidfn
5028 
5029      %10 = OpLabel
5030      OpSelectionMerge %50 None
5031      OpBranchConditional %cond %20 %50
5032 
5033      %20 = OpLabel
5034      OpBranch %99
5035 
5036      %50 = OpLabel ; merge
5037      OpBranch %99
5038 
5039      %99 = OpLabel
5040      OpReturn
5041 
5042      OpFunctionEnd
5043 )";
5044   auto p = parser(test::Assemble(assembly));
5045   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5046   auto fe = p->function_emitter(100);
5047   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5048   EXPECT_THAT(
5049       p->error(),
5050       Eq("Branch from block 20 to block 99 is an invalid exit from "
5051          "construct starting at block 10; branch bypasses merge block 50"));
5052 }
5053 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_EscapeSwitchCase_IsError)5054 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_EscapeSwitchCase_IsError) {
5055   // Code generation assumes that you can't have kCaseFallThrough and kIfBreak
5056   // from the same OpBranchConditional.
5057   // This checks one direction of that, where the IfBreak is shown it can't
5058   // escape a switch case.
5059   auto assembly = CommonTypes() + R"(
5060      %100 = OpFunction %void None %voidfn
5061 
5062      %10 = OpLabel
5063      OpSelectionMerge %99 None ; Set up if-break to %99
5064      OpBranchConditional %cond %20 %99
5065 
5066      %20 = OpLabel
5067      OpSelectionMerge %80 None ; switch-selection
5068      OpSwitch %selector %80 30 %30 40 %40
5069 
5070      %30 = OpLabel ; first case
5071         ; branch to %99 would be an if-break, but it bypasess the switch merge
5072         ; Also has case fall-through
5073      OpBranchConditional %cond2 %99 %40
5074 
5075      %40 = OpLabel ; second case
5076      OpBranch %80
5077 
5078      %80 = OpLabel ; switch-selection's merge
5079      OpBranch %99
5080 
5081      %99 = OpLabel ; if-selection's merge
5082      OpReturn
5083 
5084      OpFunctionEnd
5085 )";
5086   auto p = parser(test::Assemble(assembly));
5087   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5088   auto fe = p->function_emitter(100);
5089   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5090   EXPECT_THAT(
5091       p->error(),
5092       Eq("Branch from block 30 to block 99 is an invalid exit from "
5093          "construct starting at block 20; branch bypasses merge block 80"));
5094 }
5095 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromSwitchCaseDirect)5096 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchCaseDirect) {
5097   auto assembly = CommonTypes() + R"(
5098      %100 = OpFunction %void None %voidfn
5099 
5100      %10 = OpLabel
5101      OpSelectionMerge %99 None
5102      OpSwitch %selector %30 20 %99 ; directly to merge
5103 
5104      %30 = OpLabel
5105      OpBranch %99
5106 
5107      %99 = OpLabel
5108      OpReturn
5109 
5110      OpFunctionEnd
5111 )";
5112   auto p = parser(test::Assemble(assembly));
5113   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5114   auto fe = p->function_emitter(100);
5115   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5116 
5117   auto* bi = fe.GetBlockInfo(10);
5118   ASSERT_NE(bi, nullptr);
5119   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5120   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5121 }
5122 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromSwitchCaseBody)5123 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchCaseBody) {
5124   auto assembly = CommonTypes() + R"(
5125      %100 = OpFunction %void None %voidfn
5126 
5127      %10 = OpLabel
5128      OpSelectionMerge %99 None
5129      OpSwitch %selector %99 20 %20
5130 
5131      %20 = OpLabel
5132      OpBranch %99
5133 
5134      %99 = OpLabel
5135      OpReturn
5136 
5137      OpFunctionEnd
5138 )";
5139   auto p = parser(test::Assemble(assembly));
5140   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5141   auto fe = p->function_emitter(100);
5142   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5143 
5144   auto* bi = fe.GetBlockInfo(20);
5145   ASSERT_NE(bi, nullptr);
5146   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5147   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5148 }
5149 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultBody)5150 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultBody) {
5151   auto assembly = CommonTypes() + R"(
5152      %100 = OpFunction %void None %voidfn
5153 
5154      %10 = OpLabel
5155      OpSelectionMerge %99 None
5156      OpSwitch %selector %30 20 %20
5157 
5158      %20 = OpLabel
5159      OpBranch %99
5160 
5161      %30 = OpLabel
5162      OpBranch %99
5163 
5164      %99 = OpLabel
5165      OpReturn
5166 
5167      OpFunctionEnd
5168 )";
5169   auto p = parser(test::Assemble(assembly));
5170   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5171   auto fe = p->function_emitter(100);
5172   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5173 
5174   auto* bi = fe.GetBlockInfo(30);
5175   ASSERT_NE(bi, nullptr);
5176   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5177   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5178 }
5179 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultIsMerge)5180 TEST_F(SpvParserCFGTest,
5181        ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultIsMerge) {
5182   auto assembly = CommonTypes() + R"(
5183      %100 = OpFunction %void None %voidfn
5184 
5185      %10 = OpLabel
5186      OpSelectionMerge %99 None
5187      OpSwitch %selector %99 20 %20
5188 
5189      %20 = OpLabel
5190      OpBranch %99
5191 
5192      %99 = OpLabel
5193      OpReturn
5194 
5195      OpFunctionEnd
5196 )";
5197   auto p = parser(test::Assemble(assembly));
5198   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5199   auto fe = p->function_emitter(100);
5200   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5201 
5202   auto* bi = fe.GetBlockInfo(10);
5203   ASSERT_NE(bi, nullptr);
5204   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5205   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5206 }
5207 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromNestedIf_Unconditional)5208 TEST_F(SpvParserCFGTest,
5209        ClassifyCFGEdges_SwitchBreak_FromNestedIf_Unconditional) {
5210   auto assembly = CommonTypes() + R"(
5211      %100 = OpFunction %void None %voidfn
5212 
5213      %10 = OpLabel
5214      OpSelectionMerge %99 None
5215      OpSwitch %selector %99 20 %20
5216 
5217      %20 = OpLabel
5218      OpSelectionMerge %80 None
5219      OpBranchConditional %cond %30 %80
5220 
5221      %30 = OpLabel
5222      OpBranch %99
5223 
5224      %80 = OpLabel ; inner merge
5225      OpBranch %99
5226 
5227      %99 = OpLabel ; outer merge
5228      OpReturn
5229 
5230      OpFunctionEnd
5231 )";
5232   auto p = parser(test::Assemble(assembly));
5233   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5234   auto fe = p->function_emitter(100);
5235   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5236 
5237   auto* bi = fe.GetBlockInfo(30);
5238   ASSERT_NE(bi, nullptr);
5239   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5240   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5241 }
5242 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromNestedIf_Conditional)5243 TEST_F(SpvParserCFGTest,
5244        ClassifyCFGEdges_SwitchBreak_FromNestedIf_Conditional) {
5245   auto assembly = CommonTypes() + R"(
5246      %100 = OpFunction %void None %voidfn
5247 
5248      %10 = OpLabel
5249      OpSelectionMerge %99 None
5250      OpSwitch %selector %99 20 %20
5251 
5252      %20 = OpLabel
5253      OpSelectionMerge %80 None
5254      OpBranchConditional %cond %30 %80
5255 
5256      %30 = OpLabel
5257      OpBranchConditional %cond2 %99 %80 ; break-if
5258 
5259      %80 = OpLabel ; inner merge
5260      OpBranch %99
5261 
5262      %99 = OpLabel ; outer merge
5263      OpReturn
5264 
5265      OpFunctionEnd
5266 )";
5267   auto p = parser(test::Assemble(assembly));
5268   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5269   auto fe = p->function_emitter(100);
5270   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5271 
5272   auto* bi = fe.GetBlockInfo(30);
5273   ASSERT_NE(bi, nullptr);
5274   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5275   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
5276 }
5277 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_BypassesMerge_IsError)5278 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_BypassesMerge_IsError) {
5279   auto assembly = CommonTypes() + R"(
5280      %100 = OpFunction %void None %voidfn
5281 
5282      %10 = OpLabel
5283      OpSelectionMerge %50 None
5284      OpSwitch %selector %50 20 %20
5285 
5286      %20 = OpLabel
5287      OpBranch %99 ; invalid exit
5288 
5289      %50 = OpLabel ; switch merge
5290      OpBranch %99
5291 
5292      %99 = OpLabel
5293      OpReturn
5294 
5295      OpFunctionEnd
5296 )";
5297   auto p = parser(test::Assemble(assembly));
5298   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5299   auto fe = p->function_emitter(100);
5300   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5301   EXPECT_THAT(
5302       p->error(),
5303       Eq("Branch from block 20 to block 99 is an invalid exit from "
5304          "construct starting at block 10; branch bypasses merge block 50"));
5305 }
5306 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromNestedLoop_IsError)5307 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromNestedLoop_IsError) {
5308   // It's an error because the break can only go as far as the loop.
5309   auto assembly = CommonTypes() + R"(
5310      %100 = OpFunction %void None %voidfn
5311 
5312      %10 = OpLabel
5313      OpSelectionMerge %99 None
5314      OpSwitch %selector %99 20 %20
5315 
5316      %20 = OpLabel
5317      OpLoopMerge %80 %70 None
5318      OpBranchConditional %cond %30 %80
5319 
5320      %30 = OpLabel ; in loop construct
5321      OpBranch %99 ; break
5322 
5323      %70 = OpLabel
5324      OpBranch %20
5325 
5326      %80 = OpLabel
5327      OpBranch %99
5328 
5329      %99 = OpLabel ; outer merge
5330      OpReturn
5331 
5332      OpFunctionEnd
5333 )";
5334   auto p = parser(test::Assemble(assembly));
5335   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5336   auto fe = p->function_emitter(100);
5337   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5338   EXPECT_THAT(
5339       p->error(),
5340       Eq("Branch from block 30 to block 99 is an invalid exit from "
5341          "construct starting at block 20; branch bypasses merge block 80"));
5342 }
5343 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_SwitchBreak_FromNestedSwitch_IsError)5344 TEST_F(SpvParserCFGTest,
5345        ClassifyCFGEdges_SwitchBreak_FromNestedSwitch_IsError) {
5346   // It's an error because the break can only go as far as inner switch
5347   auto assembly = CommonTypes() + R"(
5348      %100 = OpFunction %void None %voidfn
5349 
5350      %10 = OpLabel
5351      OpSelectionMerge %99 None
5352      OpSwitch %selector %99 20 %20
5353 
5354      %20 = OpLabel
5355      OpSelectionMerge %80 None
5356      OpSwitch %selector %80 30 %30
5357 
5358      %30 = OpLabel
5359      OpBranch %99 ; break
5360 
5361      %80 = OpLabel
5362      OpBranch %99
5363 
5364      %99 = OpLabel ; outer merge
5365      OpReturn
5366 
5367      OpFunctionEnd
5368 )";
5369   auto p = parser(test::Assemble(assembly));
5370   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5371   auto fe = p->function_emitter(100);
5372   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5373   EXPECT_THAT(
5374       p->error(),
5375       Eq("Branch from block 30 to block 99 is an invalid exit from "
5376          "construct starting at block 20; branch bypasses merge block 80"));
5377 }
5378 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopBody)5379 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBody) {
5380   auto assembly = CommonTypes() + R"(
5381      %100 = OpFunction %void None %voidfn
5382 
5383      %10 = OpLabel
5384      OpBranch %20
5385 
5386      %20 = OpLabel
5387      OpLoopMerge %99 %50 None
5388      OpBranchConditional %cond %30 %99
5389 
5390      %30 = OpLabel
5391      OpBranchConditional %cond2 %50 %99 ; break-unless
5392 
5393      %50 = OpLabel
5394      OpBranch %20
5395 
5396      %99 = OpLabel
5397      OpReturn
5398 
5399      OpFunctionEnd
5400 )";
5401   auto p = parser(test::Assemble(assembly));
5402   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5403   auto fe = p->function_emitter(100);
5404   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5405 
5406   auto* bi = fe.GetBlockInfo(30);
5407   ASSERT_NE(bi, nullptr);
5408   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5409   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
5410 }
5411 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromContinueConstructTail)5412 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromContinueConstructTail) {
5413   auto assembly = CommonTypes() + R"(
5414      %100 = OpFunction %void None %voidfn
5415 
5416      %10 = OpLabel
5417      OpBranch %20
5418 
5419      %20 = OpLabel
5420      OpLoopMerge %99 %50 None
5421      OpBranchConditional %cond %30 %99
5422 
5423      %30 = OpLabel
5424      OpBranch %50
5425 
5426      %50 = OpLabel ; continue target
5427      OpBranch %60
5428 
5429      %60 = OpLabel ; continue construct tail
5430      OpBranchConditional %cond2 %20 %99
5431 
5432      %99 = OpLabel
5433      OpReturn
5434 
5435      OpFunctionEnd
5436 )";
5437   auto p = parser(test::Assemble(assembly));
5438   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5439   auto fe = p->function_emitter(100);
5440   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5441 
5442   auto* bi = fe.GetBlockInfo(60);
5443   ASSERT_NE(bi, nullptr);
5444   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5445   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
5446 }
5447 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopBodyDirect)5448 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBodyDirect) {
5449   auto assembly = CommonTypes() + R"(
5450      %100 = OpFunction %void None %voidfn
5451 
5452      %10 = OpLabel
5453      OpBranch %20
5454 
5455      %20 = OpLabel
5456      OpLoopMerge %99 %50 None
5457      OpBranchConditional %cond %30 %99
5458 
5459      %30 = OpLabel
5460      OpBranch %99  ; unconditional break
5461 
5462      %50 = OpLabel
5463      OpBranch %20
5464 
5465      %99 = OpLabel
5466      OpReturn
5467 
5468      OpFunctionEnd
5469 )";
5470   auto p = parser(test::Assemble(assembly));
5471   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5472   auto fe = p->function_emitter(100);
5473   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5474 
5475   auto* bi = fe.GetBlockInfo(30);
5476   ASSERT_NE(bi, nullptr);
5477   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5478   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
5479 }
5480 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Unconditional)5481 TEST_F(SpvParserCFGTest,
5482        ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Unconditional) {
5483   auto assembly = CommonTypes() + R"(
5484      %100 = OpFunction %void None %voidfn
5485 
5486      %10 = OpLabel
5487      OpBranch %20
5488 
5489      %20 = OpLabel
5490      OpLoopMerge %99 %80 None
5491      OpBranchConditional %cond %30 %99
5492 
5493      %30 = OpLabel
5494      OpSelectionMerge %50 None
5495      OpBranchConditional %cond2 %40 %50
5496 
5497      %40 = OpLabel
5498      OpBranch %99 ; deeply nested break
5499 
5500      %50 = OpLabel ; inner merge
5501      OpBranch %80
5502 
5503      %80 = OpLabel
5504      OpBranch %20  ; backedge
5505 
5506      %99 = OpLabel
5507      OpReturn
5508 
5509      OpFunctionEnd
5510 )";
5511   auto p = parser(test::Assemble(assembly));
5512   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5513   auto fe = p->function_emitter(100);
5514   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5515 
5516   auto* bi = fe.GetBlockInfo(40);
5517   ASSERT_NE(bi, nullptr);
5518   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5519   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
5520 }
5521 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Conditional)5522 TEST_F(SpvParserCFGTest,
5523        ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Conditional) {
5524   auto assembly = CommonTypes() + R"(
5525      %100 = OpFunction %void None %voidfn
5526 
5527      %10 = OpLabel
5528      OpBranch %20
5529 
5530      %20 = OpLabel
5531      OpLoopMerge %99 %80 None
5532      OpBranchConditional %cond %30 %99
5533 
5534      %30 = OpLabel
5535      OpSelectionMerge %50 None
5536      OpBranchConditional %cond2 %40 %50
5537 
5538      %40 = OpLabel
5539      OpBranchConditional %cond3 %99 %50 ; break-if
5540 
5541      %50 = OpLabel ; inner merge
5542      OpBranch %80
5543 
5544      %80 = OpLabel
5545      OpBranch %20  ; backedge
5546 
5547      %99 = OpLabel
5548      OpReturn
5549 
5550      OpFunctionEnd
5551 )";
5552   auto p = parser(test::Assemble(assembly));
5553   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5554   auto fe = p->function_emitter(100);
5555   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5556 
5557   auto* bi = fe.GetBlockInfo(40);
5558   ASSERT_NE(bi, nullptr);
5559   EXPECT_EQ(bi->succ_edge.count(99), 1u);
5560   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
5561 }
5562 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromContinueConstructNestedFlow_IsError)5563 TEST_F(SpvParserCFGTest,
5564        ClassifyCFGEdges_LoopBreak_FromContinueConstructNestedFlow_IsError) {
5565   auto assembly = CommonTypes() + R"(
5566      %100 = OpFunction %void None %voidfn
5567 
5568      %10 = OpLabel
5569      OpBranch %20
5570 
5571      %20 = OpLabel
5572      OpLoopMerge %99 %40 None
5573      OpBranchConditional %cond %30 %99
5574 
5575      %30 = OpLabel
5576      OpBranch %40
5577 
5578      %40 = OpLabel ; continue construct
5579      OpSelectionMerge %79 None
5580      OpBranchConditional %cond2 %50 %79
5581 
5582      %50 = OpLabel
5583      OpBranchConditional %cond3 %99 %79 ; attempt to break to 99 should fail
5584 
5585      %79 = OpLabel
5586      OpBranch %80  ; inner merge
5587 
5588      %80 = OpLabel
5589      OpBranch %20  ; backedge
5590 
5591      %99 = OpLabel
5592      OpReturn
5593 
5594      OpFunctionEnd
5595 )";
5596   auto p = parser(test::Assemble(assembly));
5597   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5598   auto fe = p->function_emitter(100);
5599   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5600   EXPECT_THAT(p->error(),
5601               Eq("Invalid exit (50->99) from continue construct: 50 is not the "
5602                  "last block in the continue construct starting at 40 "
5603                  "(violates post-dominance rule)"));
5604 }
5605 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromLoopBypassesMerge_IsError)5606 TEST_F(SpvParserCFGTest,
5607        ClassifyCFGEdges_LoopBreak_FromLoopBypassesMerge_IsError) {
5608   auto assembly = CommonTypes() + R"(
5609      %100 = OpFunction %void None %voidfn
5610 
5611      %10 = OpLabel
5612      OpBranch %20
5613 
5614      %20 = OpLabel
5615      OpLoopMerge %50 %40 None
5616      OpBranchConditional %cond %30 %50
5617 
5618      %30 = OpLabel
5619      OpBranch %99 ; bad exit
5620 
5621      %40 = OpLabel ; continue construct
5622      OpBranch %20
5623 
5624      %50 = OpLabel
5625      OpBranch %99
5626 
5627      %99 = OpLabel
5628      OpReturn
5629 
5630      OpFunctionEnd
5631 )";
5632   auto p = parser(test::Assemble(assembly));
5633   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5634   auto fe = p->function_emitter(100);
5635   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5636   EXPECT_THAT(
5637       p->error(),
5638       Eq("Branch from block 30 to block 99 is an invalid exit from "
5639          "construct starting at block 20; branch bypasses merge block 50"));
5640 }
5641 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopBreak_FromContinueBypassesMerge_IsError)5642 TEST_F(SpvParserCFGTest,
5643        ClassifyCFGEdges_LoopBreak_FromContinueBypassesMerge_IsError) {
5644   auto assembly = CommonTypes() + R"(
5645      %100 = OpFunction %void None %voidfn
5646 
5647      %10 = OpLabel
5648      OpBranch %20
5649 
5650      %20 = OpLabel
5651      OpLoopMerge %50 %40 None
5652      OpBranchConditional %cond %30 %50
5653 
5654      %30 = OpLabel
5655      OpBranch %40
5656 
5657      %40 = OpLabel ; continue construct
5658      OpBranch %45
5659 
5660      %45 = OpLabel
5661      OpBranchConditional %cond2 %20 %99 ; branch to %99 is bad exit
5662 
5663      %50 = OpLabel
5664      OpBranch %99
5665 
5666      %99 = OpLabel
5667      OpReturn
5668 
5669      OpFunctionEnd
5670 )";
5671   auto p = parser(test::Assemble(assembly));
5672   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5673   auto fe = p->function_emitter(100);
5674   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
5675   EXPECT_THAT(
5676       p->error(),
5677       Eq("Branch from block 45 to block 99 is an invalid exit from "
5678          "construct starting at block 40; branch bypasses merge block 50"));
5679 }
5680 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_LoopBodyToContinue)5681 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_LoopBodyToContinue) {
5682   auto assembly = CommonTypes() + R"(
5683      %100 = OpFunction %void None %voidfn
5684 
5685      %10 = OpLabel
5686      OpBranch %20
5687 
5688      %20 = OpLabel
5689      OpLoopMerge %99 %80 None
5690      OpBranchConditional %cond %30 %99
5691 
5692      %30 = OpLabel
5693      OpBranch %80 ; a forward edge
5694 
5695      %80 = OpLabel
5696      OpBranch %20
5697 
5698      %99 = OpLabel
5699      OpReturn
5700 
5701      OpFunctionEnd
5702 )";
5703   auto p = parser(test::Assemble(assembly));
5704   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5705   auto fe = p->function_emitter(100);
5706   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5707 
5708   auto* bi = fe.GetBlockInfo(30);
5709   ASSERT_NE(bi, nullptr);
5710   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5711   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5712 }
5713 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedIf)5714 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedIf) {
5715   auto assembly = CommonTypes() + R"(
5716      %100 = OpFunction %void None %voidfn
5717 
5718      %10 = OpLabel
5719      OpBranch %20
5720 
5721      %20 = OpLabel
5722      OpLoopMerge %99 %80 None
5723      OpBranchConditional %cond %30 %99
5724 
5725      %30 = OpLabel
5726      OpSelectionMerge %79 None
5727      OpBranchConditional %cond2 %40 %79
5728 
5729      %40 = OpLabel
5730      OpBranch %80 ; continue
5731 
5732      %79 = OpLabel ; inner merge
5733      OpBranch %80
5734 
5735      %80 = OpLabel ; continue target
5736      OpBranch %20
5737 
5738      %99 = OpLabel
5739      OpReturn
5740 
5741      OpFunctionEnd
5742 )";
5743   auto p = parser(test::Assemble(assembly));
5744   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5745   auto fe = p->function_emitter(100);
5746   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5747 
5748   auto* bi = fe.GetBlockInfo(40);
5749   ASSERT_NE(bi, nullptr);
5750   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5751   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5752 }
5753 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_ConditionalFromNestedIf)5754 TEST_F(SpvParserCFGTest,
5755        ClassifyCFGEdges_LoopContinue_ConditionalFromNestedIf) {
5756   auto assembly = CommonTypes() + R"(
5757      %100 = OpFunction %void None %voidfn
5758 
5759      %10 = OpLabel
5760      OpBranch %20
5761 
5762      %20 = OpLabel
5763      OpLoopMerge %99 %80 None
5764      OpBranchConditional %cond %30 %99
5765 
5766      %30 = OpLabel
5767      OpSelectionMerge %79 None
5768      OpBranchConditional %cond2 %40 %79
5769 
5770      %40 = OpLabel
5771      OpBranchConditional %cond2 %80 %79 ; continue-if
5772 
5773      %79 = OpLabel ; inner merge
5774      OpBranch %80
5775 
5776      %80 = OpLabel ; continue target
5777      OpBranch %20
5778 
5779      %99 = OpLabel
5780      OpReturn
5781 
5782      OpFunctionEnd
5783 )";
5784   auto p = parser(test::Assemble(assembly));
5785   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5786   auto fe = p->function_emitter(100);
5787   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5788 
5789   auto* bi = fe.GetBlockInfo(40);
5790   ASSERT_NE(bi, nullptr);
5791   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5792   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5793 }
5794 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseBody_Unconditional)5795 TEST_F(SpvParserCFGTest,
5796        ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseBody_Unconditional) {
5797   auto assembly = CommonTypes() + R"(
5798      %100 = OpFunction %void None %voidfn
5799 
5800      %10 = OpLabel
5801      OpBranch %20
5802 
5803      %20 = OpLabel
5804      OpLoopMerge %99 %80 None
5805      OpBranchConditional %cond %30 %99
5806 
5807      %30 = OpLabel
5808      OpSelectionMerge %79 None
5809      OpSwitch %selector %79 40 %40
5810 
5811      %40 = OpLabel
5812      OpBranch %80
5813 
5814      %79 = OpLabel ; inner merge
5815      OpBranch %80
5816 
5817      %80 = OpLabel ; continue target
5818      OpBranch %20
5819 
5820      %99 = OpLabel
5821      OpReturn
5822 
5823      OpFunctionEnd
5824 )";
5825   auto p = parser(test::Assemble(assembly));
5826   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5827   auto fe = p->function_emitter(100);
5828   EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
5829 
5830   auto* bi = fe.GetBlockInfo(40);
5831   ASSERT_NE(bi, nullptr);
5832   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5833   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5834 }
5835 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseDirect_IsError)5836 TEST_F(SpvParserCFGTest,
5837        ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseDirect_IsError) {
5838   auto assembly = CommonTypes() + R"(
5839      %100 = OpFunction %void None %voidfn
5840 
5841      %10 = OpLabel
5842      OpBranch %20
5843 
5844      %20 = OpLabel
5845      OpLoopMerge %99 %80 None
5846      OpBranchConditional %cond %30 %99
5847 
5848      %30 = OpLabel
5849      OpSelectionMerge %79 None
5850      OpSwitch %selector %79 40 %80 ; continue here
5851 
5852      %79 = OpLabel ; inner merge
5853      OpBranch %80
5854 
5855      %80 = OpLabel ; continue target
5856      OpBranch %20
5857 
5858      %99 = OpLabel
5859      OpReturn
5860 
5861      OpFunctionEnd
5862 )";
5863   auto p = parser(test::Assemble(assembly));
5864   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5865   auto fe = p->function_emitter(100);
5866   fe.RegisterBasicBlocks();
5867   fe.ComputeBlockOrderAndPositions();
5868   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
5869   EXPECT_TRUE(fe.RegisterMerges());
5870   EXPECT_TRUE(fe.LabelControlFlowConstructs());
5871   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
5872   EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to case target block "
5873                              "80 escapes the selection construct"));
5874 }
5875 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultDirect_IsError)5876 TEST_F(SpvParserCFGTest,
5877        ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultDirect_IsError) {
5878   auto assembly = CommonTypes() + R"(
5879      %100 = OpFunction %void None %voidfn
5880 
5881      %10 = OpLabel
5882      OpBranch %20
5883 
5884      %20 = OpLabel
5885      OpLoopMerge %99 %80 None
5886      OpBranchConditional %cond %30 %99
5887 
5888      %30 = OpLabel
5889      OpSelectionMerge %79 None
5890      OpSwitch %selector %80 40 %79 ; continue here
5891 
5892      %79 = OpLabel ; inner merge
5893      OpBranch %80
5894 
5895      %80 = OpLabel ; continue target
5896      OpBranch %20
5897 
5898      %99 = OpLabel
5899      OpReturn
5900 
5901      OpFunctionEnd
5902 )";
5903   auto p = parser(test::Assemble(assembly));
5904   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5905   auto fe = p->function_emitter(100);
5906   fe.RegisterBasicBlocks();
5907   fe.ComputeBlockOrderAndPositions();
5908   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
5909   EXPECT_TRUE(fe.RegisterMerges());
5910   EXPECT_TRUE(fe.LabelControlFlowConstructs());
5911   EXPECT_FALSE(fe.FindSwitchCaseHeaders());
5912   EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to default block 80 "
5913                              "escapes the selection construct"));
5914 }
5915 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Conditional)5916 TEST_F(SpvParserCFGTest,
5917        ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Conditional) {
5918   auto assembly = CommonTypes() + R"(
5919      %100 = OpFunction %void None %voidfn
5920 
5921      %10 = OpLabel
5922      OpBranch %20
5923 
5924      %20 = OpLabel
5925      OpLoopMerge %99 %80 None
5926      OpBranchConditional %cond %30 %99
5927 
5928      %30 = OpLabel
5929      OpSelectionMerge %79 None
5930      OpSwitch %selector %40 79 %79
5931 
5932      %40 = OpLabel
5933      OpBranchConditional %cond2 %80 %79
5934 
5935      %79 = OpLabel ; inner merge
5936      OpBranch %80
5937 
5938      %80 = OpLabel ; continue target
5939      OpBranch %20
5940 
5941      %99 = OpLabel
5942      OpReturn
5943 
5944      OpFunctionEnd
5945 )";
5946   auto p = parser(test::Assemble(assembly));
5947   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5948   auto fe = p->function_emitter(100);
5949   EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
5950 
5951   auto* bi = fe.GetBlockInfo(40);
5952   ASSERT_NE(bi, nullptr);
5953   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5954   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5955 }
5956 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Unconditional)5957 TEST_F(
5958     SpvParserCFGTest,
5959     ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Unconditional) {
5960   auto assembly = CommonTypes() + R"(
5961      %100 = OpFunction %void None %voidfn
5962 
5963      %10 = OpLabel
5964      OpBranch %20
5965 
5966      %20 = OpLabel
5967      OpLoopMerge %99 %80 None
5968      OpBranchConditional %cond %30 %99
5969 
5970      %30 = OpLabel
5971      OpSelectionMerge %79 None
5972      OpSwitch %selector %40 79 %79
5973 
5974      %40 = OpLabel
5975      OpBranch %80
5976 
5977      %79 = OpLabel ; inner merge
5978      OpBranch %80
5979 
5980      %80 = OpLabel ; continue target
5981      OpBranch %20
5982 
5983      %99 = OpLabel
5984      OpReturn
5985 
5986      OpFunctionEnd
5987 )";
5988   auto p = parser(test::Assemble(assembly));
5989   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
5990   auto fe = p->function_emitter(100);
5991   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
5992 
5993   auto* bi = fe.GetBlockInfo(40);
5994   ASSERT_NE(bi, nullptr);
5995   EXPECT_EQ(bi->succ_edge.count(80), 1u);
5996   EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
5997 }
5998 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError)5999 TEST_F(SpvParserCFGTest,
6000        ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError) {
6001   // Inner loop header tries to do continue to outer loop continue target.
6002   // This is disallowed by the rule:
6003   //    "a continue block is valid only for the innermost loop it is nested
6004   //    inside of"
6005   auto assembly = CommonTypes() + R"(
6006      %100 = OpFunction %void None %voidfn
6007 
6008      %10 = OpLabel
6009      OpBranch %20
6010 
6011      %20 = OpLabel
6012      OpStore %var %uint_1
6013      OpLoopMerge %99 %80 None
6014      OpBranchConditional %cond %30 %99
6015 
6016      %30 = OpLabel ; inner loop.
6017      OpStore %var %uint_1
6018      OpLoopMerge %59 %50 None
6019      OpBranchConditional %cond %59 %80  ; break and outer continue
6020 
6021      %50 = OpLabel
6022      OpStore %var %uint_2
6023      OpBranch %30 ; inner backedge
6024 
6025      %59 = OpLabel ; inner merge
6026      OpStore %var %uint_3
6027      OpBranch %80
6028 
6029      %80 = OpLabel ; outer continue
6030      OpStore %var %uint_4
6031      OpBranch %20 ; outer backedge
6032 
6033      %99 = OpLabel
6034      OpStore %var %uint_5
6035      OpReturn
6036 
6037      OpFunctionEnd
6038   )";
6039   auto p = parser(test::Assemble(assembly));
6040   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6041   auto fe = p->function_emitter(100);
6042   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6043   EXPECT_THAT(
6044       p->error(),
6045       Eq("Branch from block 30 to block 80 is an invalid exit from construct "
6046          "starting at block 30; branch bypasses merge block 59"));
6047 }
6048 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_CaseTailToCase)6049 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_CaseTailToCase) {
6050   auto assembly = CommonTypes() + R"(
6051      %100 = OpFunction %void None %voidfn
6052 
6053      %10 = OpLabel
6054      OpSelectionMerge %99 None
6055      OpSwitch %selector %99 20 %20 40 %40
6056 
6057      %20 = OpLabel ; case 20
6058      OpBranch %30
6059 
6060      %30 = OpLabel
6061      OpBranch %40 ; fallthrough
6062 
6063      %40 = OpLabel ; case 40
6064      OpBranch %99
6065 
6066      %99 = OpLabel
6067      OpReturn
6068 
6069      OpFunctionEnd
6070 )";
6071   auto p = parser(test::Assemble(assembly));
6072   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6073   auto fe = p->function_emitter(100);
6074   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6075 
6076   auto* bi = fe.GetBlockInfo(30);
6077   ASSERT_NE(bi, nullptr);
6078   EXPECT_EQ(bi->succ_edge.count(40), 1u);
6079   EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
6080 }
6081 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_CaseTailToDefaultNotMerge)6082 TEST_F(SpvParserCFGTest,
6083        ClassifyCFGEdges_Fallthrough_CaseTailToDefaultNotMerge) {
6084   auto assembly = CommonTypes() + R"(
6085      %100 = OpFunction %void None %voidfn
6086 
6087      %10 = OpLabel
6088      OpSelectionMerge %99 None
6089      OpSwitch %selector %40 20 %20
6090 
6091      %20 = OpLabel ; case 20
6092      OpBranch %30
6093 
6094      %30 = OpLabel
6095      OpBranch %40 ; fallthrough
6096 
6097      %40 = OpLabel ; case 40
6098      OpBranch %99
6099 
6100      %99 = OpLabel
6101      OpReturn
6102 
6103      OpFunctionEnd
6104 )";
6105   auto p = parser(test::Assemble(assembly));
6106   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6107   auto fe = p->function_emitter(100);
6108   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6109 
6110   auto* bi = fe.GetBlockInfo(30);
6111   ASSERT_NE(bi, nullptr);
6112   EXPECT_EQ(bi->succ_edge.count(40), 1u);
6113   EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
6114 }
6115 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_DefaultToCase)6116 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_DefaultToCase) {
6117   auto assembly = CommonTypes() + R"(
6118      %100 = OpFunction %void None %voidfn
6119 
6120      %10 = OpLabel
6121      OpSelectionMerge %99 None
6122      OpSwitch %selector %20 40 %40
6123 
6124      %20 = OpLabel ; default
6125      OpBranch %30
6126 
6127      %30 = OpLabel
6128      OpBranch %40 ; fallthrough
6129 
6130      %40 = OpLabel ; case 40
6131      OpBranch %99
6132 
6133      %99 = OpLabel
6134      OpReturn
6135 
6136      OpFunctionEnd
6137 )";
6138   auto p = parser(test::Assemble(assembly));
6139   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6140   auto fe = p->function_emitter(100);
6141   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6142 
6143   auto* bi = fe.GetBlockInfo(30);
6144   ASSERT_NE(bi, nullptr);
6145   EXPECT_EQ(bi->succ_edge.count(40), 1u);
6146   EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
6147 }
6148 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_BranchConditionalWith_IfBreak_IsError)6149 TEST_F(SpvParserCFGTest,
6150        ClassifyCFGEdges_Fallthrough_BranchConditionalWith_IfBreak_IsError) {
6151   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6152   // with kIfBreak.
6153   auto assembly = CommonTypes() + R"(
6154      %100 = OpFunction %void None %voidfn
6155 
6156      %10 = OpLabel
6157      OpSelectionMerge %99 None ; Set up if-break to %99
6158      OpBranchConditional %cond %20 %99
6159 
6160      %20 = OpLabel
6161      OpSelectionMerge %80 None ; switch-selection
6162      OpSwitch %selector %80 30 %30 40 %40
6163 
6164      %30 = OpLabel ; first case
6165         ; branch to %99 would be an if-break, but it bypasess the switch merge
6166         ; Also has case fall-through
6167      OpBranchConditional %cond2 %99 %40
6168 
6169      %40 = OpLabel ; second case
6170      OpBranch %80
6171 
6172      %80 = OpLabel ; switch-selection's merge
6173      OpBranch %99
6174 
6175      %99 = OpLabel ; if-selection's merge
6176      OpReturn
6177 
6178      OpFunctionEnd
6179 )";
6180   auto p = parser(test::Assemble(assembly));
6181   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6182   auto fe = p->function_emitter(100);
6183   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6184   EXPECT_THAT(
6185       p->error(),
6186       Eq("Branch from block 30 to block 99 is an invalid exit from "
6187          "construct starting at block 20; branch bypasses merge block 80"));
6188 }
6189 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError)6190 TEST_F(SpvParserCFGTest,
6191        ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError) {
6192   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6193   // with kForward.
6194   auto assembly = CommonTypes() + R"(
6195      %100 = OpFunction %void None %voidfn
6196 
6197      %10 = OpLabel
6198      OpSelectionMerge %99 None ; switch-selection
6199      OpSwitch %selector %99 20 %20 30 %30
6200 
6201      ; Try to make branch to 35 a kForward branch
6202      %20 = OpLabel ; first case
6203      OpBranchConditional %cond2 %25 %30
6204 
6205      %25 = OpLabel
6206      OpBranch %99
6207 
6208      %30 = OpLabel ; second case
6209      OpBranch %99
6210 
6211      %99 = OpLabel ; if-selection's merge
6212      OpReturn
6213 
6214      OpFunctionEnd
6215 )";
6216   auto p = parser(test::Assemble(assembly));
6217   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6218   auto fe = p->function_emitter(100);
6219   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6220   EXPECT_THAT(p->error(),
6221               Eq("Control flow diverges at block 20 (to 25, 30) but it is not "
6222                  "a structured header (it has no merge instruction)"));
6223 }
6224 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnOutside_IsError)6225 TEST_F(
6226     SpvParserCFGTest,
6227     ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnOutside_IsError) {  // NOLINT
6228   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6229   // with kBack.
6230   //
6231   // This test has the loop on the outside. The backedge coming from a case
6232   // clause means the switch is inside the continue construct, and the nesting
6233   // of the switch's merge means the backedge is coming from a block that is not
6234   // at the end of the continue construct.
6235   auto assembly = CommonTypes() + R"(
6236      %100 = OpFunction %void None %voidfn
6237 
6238      %10 = OpLabel
6239      OpBranch %20
6240 
6241      %20 = OpLabel
6242      OpLoopMerge %99 %30 None
6243      OpBranch %30
6244 
6245      %30 = OpLabel  ; continue target and
6246      OpSelectionMerge %80 None ; switch-selection
6247      OpSwitch %selector %80 40 %40 50 %50
6248 
6249      ; try to make a back edge with a fallthrough
6250      %40 = OpLabel ; first case
6251      OpBranchConditional %cond2 %20 %50
6252 
6253      %50 = OpLabel ; second case
6254      OpBranch %80
6255 
6256      %80 = OpLabel ; switch merge
6257      OpBranch %20  ; also backedge
6258 
6259      %99 = OpLabel ; loop merge
6260      OpReturn
6261 
6262      OpFunctionEnd
6263 )";
6264   auto p = parser(test::Assemble(assembly));
6265   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6266   auto fe = p->function_emitter(100);
6267   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6268   EXPECT_THAT(p->error(),
6269               Eq("Invalid exit (40->20) from continue construct: 40 is not the "
6270                  "last block in the continue construct starting at 30 "
6271                  "(violates post-dominance rule)"));
6272 }
6273 
TEST_F(SpvParserCFGTest,FindSwitchCaseSelectionHeaders_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsMerge_IsError)6274 TEST_F(
6275     SpvParserCFGTest,
6276     FindSwitchCaseSelectionHeaders_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsMerge_IsError) {  // NOLINT
6277   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6278   // with kBack.
6279   //
6280   // This test has the loop on the inside. The merge block is also the
6281   // fallthrough target.
6282   auto assembly = CommonTypes() + R"(
6283      %100 = OpFunction %void None %voidfn
6284 
6285      %10 = OpLabel  ; continue target and
6286      OpSelectionMerge %99 None ; switch-selection
6287      OpSwitch %selector %99 20 %20 50 %50
6288 
6289      %20 = OpLabel ; first case, and loop header
6290      OpLoopMerge %50 %40 None
6291      OpBranch %40
6292 
6293      ; try to make a back edge with a fallthrough
6294      %40 = OpLabel
6295      OpBranchConditional %cond2 %20 %50
6296 
6297      %50 = OpLabel ; second case.  also the loop merge ; header must dominate its merge block !
6298      OpBranch %99
6299 
6300      %99 = OpLabel ; switch merge
6301      OpReturn
6302 
6303      OpFunctionEnd
6304 )";
6305   auto p = parser(test::Assemble(assembly));
6306   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6307   auto fe = p->function_emitter(100);
6308   EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
6309   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 99));
6310   EXPECT_THAT(p->error(),
6311               Eq("Block 50 is a case block for switch-selection header 10 and "
6312                  "also the merge block for 20 (violates dominance rule)"));
6313 }
6314 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsNotMerge_IsError)6315 TEST_F(
6316     SpvParserCFGTest,
6317     ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsNotMerge_IsError) {  // NOLINT
6318   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6319   // with kBack.
6320   //
6321   // This test has the loop on the inside. The merge block is not the merge
6322   // target But the block order gets messed up because of the weird
6323   // connectivity.
6324   auto assembly = CommonTypes() + R"(
6325      %100 = OpFunction %void None %voidfn
6326 
6327      %10 = OpLabel  ; continue target and
6328      OpSelectionMerge %99 None ; switch-selection
6329      OpSwitch %selector %99 20 %20 50 %50
6330 
6331      %20 = OpLabel ; first case, and loop header
6332      OpLoopMerge %45 %40 None  ; move the merge to an unreachable block
6333      OpBranch %40
6334 
6335      ; try to make a back edge with a fallthrough
6336      %40 = OpLabel
6337      OpBranchConditional %cond2 %20 %50
6338 
6339      %45 = OpLabel ; merge for the loop
6340      OpUnreachable
6341 
6342      %50 = OpLabel ; second case. target of fallthrough
6343      OpBranch %99
6344 
6345      %99 = OpLabel ; switch merge
6346      OpReturn
6347 
6348      OpFunctionEnd
6349 )";
6350   auto p = parser(test::Assemble(assembly));
6351   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6352   auto fe = p->function_emitter(100);
6353   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6354   EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
6355                              "(dominance rule violated)"));
6356 }
6357 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_NestedMerge_IsError)6358 TEST_F(
6359     SpvParserCFGTest,
6360     ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_NestedMerge_IsError) {  // NOLINT
6361   // Code generation assumes OpBranchConditional can't have kCaseFallThrough
6362   // with kBack.
6363   //
6364   // This test has the loop on the inside. The fallthrough is an invalid exit
6365   // from the loop. However, the block order gets all messed up because going
6366   // from 40 to 50 ends up pulling in 99
6367   auto assembly = CommonTypes() + R"(
6368      %100 = OpFunction %void None %voidfn
6369 
6370      %10 = OpLabel  ; continue target and
6371      OpSelectionMerge %99 None ; switch-selection
6372      OpSwitch %selector %99 20 %20 50 %50
6373 
6374        %20 = OpLabel ; first case, and loop header
6375        OpLoopMerge %49 %40 None
6376        OpBranch %40
6377 
6378        ; try to make a back edge with a fallthrough
6379        %40 = OpLabel
6380        OpBranchConditional %cond2 %20 %50
6381 
6382        %49 = OpLabel ; loop merge
6383        OpBranch %99
6384 
6385      %50 = OpLabel ; second case
6386      OpBranch %99
6387 
6388      %99 = OpLabel ; switch merge
6389      OpReturn
6390 
6391      OpFunctionEnd
6392 )";
6393   auto p = parser(test::Assemble(assembly));
6394   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6395   auto fe = p->function_emitter(100);
6396   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6397   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 49, 99));
6398   EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
6399                              "(dominance rule violated)"));
6400 }
6401 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_TrueBranch)6402 TEST_F(SpvParserCFGTest,
6403        ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_TrueBranch) {
6404   // This is an unusual one, and is an error. Structurally it looks like this:
6405   //   switch (val) {
6406   //   case 0: {
6407   //        if (cond) {
6408   //          fallthrough;
6409   //        }
6410   //        something = 1;
6411   //      }
6412   //   case 1: { }
6413   //   }
6414   auto assembly = CommonTypes() + R"(
6415      %100 = OpFunction %void None %voidfn
6416 
6417      %10 = OpLabel
6418      OpSelectionMerge %99 None
6419      OpSwitch %selector %99 20 %20 50 %50
6420 
6421      %20 = OpLabel
6422      OpSelectionMerge %49 None
6423      OpBranchConditional %cond %30 %49
6424 
6425      %30 = OpLabel
6426      OpBranch %50 ; attempt to fallthrough
6427 
6428      %49 = OpLabel
6429      OpBranch %99
6430 
6431      %50 = OpLabel
6432      OpBranch %99
6433 
6434      %99 = OpLabel
6435      OpReturn
6436 
6437      OpFunctionEnd
6438 )";
6439   auto p = parser(test::Assemble(assembly));
6440   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6441   auto fe = p->function_emitter(100);
6442   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6443   EXPECT_THAT(
6444       p->error(),
6445       Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
6446 }
6447 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_FalseBranch)6448 TEST_F(SpvParserCFGTest,
6449        ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_FalseBranch) {
6450   // Like previous test, but taking the false branch.
6451 
6452   // This is an unusual one, and is an error. Structurally it looks like this:
6453   //   switch (val) {
6454   //   case 0: {
6455   //        if (cond) {
6456   //          fallthrough;
6457   //        }
6458   //        something = 1;
6459   //      }
6460   //   case 1: { }
6461   //   }
6462   auto assembly = CommonTypes() + R"(
6463      %100 = OpFunction %void None %voidfn
6464 
6465      %10 = OpLabel
6466      OpSelectionMerge %99 None
6467      OpSwitch %selector %99 20 %20 50 %50
6468 
6469      %20 = OpLabel
6470      OpSelectionMerge %49 None
6471      OpBranchConditional %cond %49 %30 ;; this is the difference
6472 
6473      %30 = OpLabel
6474      OpBranch %50 ; attempt to fallthrough
6475 
6476      %49 = OpLabel
6477      OpBranch %99
6478 
6479      %50 = OpLabel
6480      OpBranch %99
6481 
6482      %99 = OpLabel
6483      OpReturn
6484 
6485      OpFunctionEnd
6486 )";
6487   auto p = parser(test::Assemble(assembly));
6488   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6489   auto fe = p->function_emitter(100);
6490   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6491   EXPECT_THAT(
6492       p->error(),
6493       Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
6494 }
6495 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Forward_IfToThen)6496 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_IfToThen) {
6497   auto assembly = CommonTypes() + R"(
6498      %100 = OpFunction %void None %voidfn
6499 
6500      %10 = OpLabel
6501      OpSelectionMerge %99 None
6502      OpBranchConditional %cond %20 %99
6503 
6504      %20 = OpLabel
6505      OpBranch %99
6506 
6507      %99 = OpLabel
6508      OpReturn
6509 
6510      OpFunctionEnd
6511 )";
6512   auto p = parser(test::Assemble(assembly));
6513   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6514   auto fe = p->function_emitter(100);
6515   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6516 
6517   auto* bi = fe.GetBlockInfo(10);
6518   ASSERT_NE(bi, nullptr);
6519   EXPECT_EQ(bi->succ_edge.count(20), 1u);
6520   EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
6521 }
6522 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Forward_IfToElse)6523 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_IfToElse) {
6524   auto assembly = CommonTypes() + R"(
6525      %100 = OpFunction %void None %voidfn
6526 
6527      %10 = OpLabel
6528      OpSelectionMerge %99 None
6529      OpBranchConditional %cond %99 %30
6530 
6531      %30 = OpLabel
6532      OpBranch %99
6533 
6534      %99 = OpLabel
6535      OpReturn
6536 
6537      OpFunctionEnd
6538 )";
6539   auto p = parser(test::Assemble(assembly));
6540   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6541   auto fe = p->function_emitter(100);
6542   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6543 
6544   auto* bi = fe.GetBlockInfo(10);
6545   ASSERT_NE(bi, nullptr);
6546   EXPECT_EQ(bi->succ_edge.count(30), 1u);
6547   EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
6548 }
6549 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Forward_SwitchToCase)6550 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_SwitchToCase) {
6551   auto assembly = CommonTypes() + R"(
6552      %100 = OpFunction %void None %voidfn
6553 
6554      %10 = OpLabel
6555      OpSelectionMerge %99 None
6556      OpSwitch %selector %99 20 %20
6557 
6558      %20 = OpLabel
6559      OpBranch %99
6560 
6561      %99 = OpLabel
6562      OpReturn
6563 
6564      OpFunctionEnd
6565 )";
6566   auto p = parser(test::Assemble(assembly));
6567   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6568   auto fe = p->function_emitter(100);
6569   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6570 
6571   auto* bi = fe.GetBlockInfo(10);
6572   ASSERT_NE(bi, nullptr);
6573   EXPECT_EQ(bi->succ_edge.count(20), 1u);
6574   EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
6575 }
6576 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Forward_SwitchToDefaultNotMerge)6577 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_SwitchToDefaultNotMerge) {
6578   auto assembly = CommonTypes() + R"(
6579      %100 = OpFunction %void None %voidfn
6580 
6581      %10 = OpLabel
6582      OpSelectionMerge %99 None
6583      OpSwitch %selector %30 20 %20
6584 
6585      %20 = OpLabel
6586      OpBranch %99
6587 
6588      %30 = OpLabel
6589      OpBranch %99
6590 
6591      %99 = OpLabel
6592      OpReturn
6593 
6594      OpFunctionEnd
6595 )";
6596   auto p = parser(test::Assemble(assembly));
6597   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6598   auto fe = p->function_emitter(100);
6599   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6600 
6601   auto* bi = fe.GetBlockInfo(10);
6602   ASSERT_NE(bi, nullptr);
6603   EXPECT_EQ(bi->succ_edge.count(30), 1u);
6604   EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
6605 }
6606 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Forward_LoopHeadToBody)6607 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_LoopHeadToBody) {
6608   auto assembly = CommonTypes() + R"(
6609      %100 = OpFunction %void None %voidfn
6610 
6611      %10 = OpLabel
6612      OpBranch %20
6613 
6614      %20 = OpLabel
6615      OpLoopMerge %99 %80 None
6616      OpBranchConditional %cond %30 %99
6617 
6618      %30 = OpLabel
6619      OpBranch %80
6620 
6621      %80 = OpLabel
6622      OpBranch %20
6623 
6624      %99 = OpLabel
6625      OpReturn
6626 
6627      OpFunctionEnd
6628 )";
6629   auto p = parser(test::Assemble(assembly));
6630   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6631   auto fe = p->function_emitter(100);
6632   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
6633 
6634   auto* bi = fe.GetBlockInfo(20);
6635   ASSERT_NE(bi, nullptr);
6636   EXPECT_EQ(bi->succ_edge.count(30), 1u);
6637   EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
6638 }
6639 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_BeforeIfToSelectionInterior)6640 TEST_F(SpvParserCFGTest,
6641        ClassifyCFGEdges_DomViolation_BeforeIfToSelectionInterior) {
6642   auto assembly = CommonTypes() + R"(
6643      %100 = OpFunction %void None %voidfn
6644 
6645      %10 = OpLabel
6646      OpSelectionMerge %99 None
6647      OpBranchConditional %cond %20 %50 ;%50 is a bad branch
6648 
6649      %20 = OpLabel
6650      OpSelectionMerge %89 None
6651      OpBranchConditional %cond %50 %89
6652 
6653      %50 = OpLabel
6654      OpBranch %89
6655 
6656      %89 = OpLabel
6657      OpBranch %99
6658 
6659      %99 = OpLabel
6660      OpReturn
6661 
6662      OpFunctionEnd
6663 )";
6664   auto p = parser(test::Assemble(assembly));
6665   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6666   auto fe = p->function_emitter(100);
6667   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6668   EXPECT_THAT(
6669       p->error(),
6670       Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
6671 }
6672 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_BeforeSwitchToSelectionInterior)6673 TEST_F(SpvParserCFGTest,
6674        ClassifyCFGEdges_DomViolation_BeforeSwitchToSelectionInterior) {
6675   auto assembly = CommonTypes() + R"(
6676      %100 = OpFunction %void None %voidfn
6677 
6678      %10 = OpLabel
6679      OpSelectionMerge %99 None
6680      OpBranchConditional %cond %20 %50 ;%50 is a bad branch
6681 
6682      %20 = OpLabel
6683      OpSelectionMerge %89 None
6684      OpSwitch %selector %89 50 %50
6685 
6686      %50 = OpLabel
6687      OpBranch %89
6688 
6689      %89 = OpLabel
6690      OpBranch %99
6691 
6692      %99 = OpLabel
6693      OpReturn
6694 
6695      OpFunctionEnd
6696 )";
6697   auto p = parser(test::Assemble(assembly));
6698   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6699   auto fe = p->function_emitter(100);
6700   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6701   EXPECT_THAT(
6702       p->error(),
6703       Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
6704 }
6705 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_BeforeLoopToLoopBodyInterior)6706 TEST_F(SpvParserCFGTest,
6707        ClassifyCFGEdges_DomViolation_BeforeLoopToLoopBodyInterior) {
6708   auto assembly = CommonTypes() + R"(
6709      %100 = OpFunction %void None %voidfn
6710 
6711      %10 = OpLabel
6712      OpSelectionMerge %99 None
6713      OpBranchConditional %cond %20 %50 ;%50 is a bad branch
6714 
6715      %20 = OpLabel
6716      OpLoopMerge %89 %80 None
6717      OpBranchConditional %cond %50 %89
6718 
6719      %50 = OpLabel
6720      OpBranch %89
6721 
6722      %80 = OpLabel
6723      OpBranch %20
6724 
6725      %89 = OpLabel
6726      OpBranch %99
6727 
6728      %99 = OpLabel
6729      OpReturn
6730 
6731      OpFunctionEnd
6732 )";
6733   auto p = parser(test::Assemble(assembly));
6734   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6735   auto fe = p->function_emitter(100);
6736   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6737   EXPECT_THAT(p->error(),
6738               // Weird error, but still we caught it.
6739               // Preferred: Eq("Branch from 10 to 50 bypasses header 20
6740               // (dominance rule violated)"))
6741               Eq("Branch from 10 to 50 bypasses continue target 80 (dominance "
6742                  "rule violated)"))
6743       << Dump(fe.block_order());
6744 }
6745 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_BeforeContinueToContinueInterior)6746 TEST_F(SpvParserCFGTest,
6747        ClassifyCFGEdges_DomViolation_BeforeContinueToContinueInterior) {
6748   auto assembly = CommonTypes() + R"(
6749      %100 = OpFunction %void None %voidfn
6750 
6751      %10 = OpLabel
6752      OpBranch %20
6753 
6754      %20 = OpLabel
6755      OpLoopMerge %99 %50 None
6756      OpBranchConditional %cond %30 %99
6757 
6758      %30 = OpLabel
6759      OpBranch %60
6760 
6761      %50 = OpLabel ; continue target
6762      OpBranch %60
6763 
6764      %60 = OpLabel
6765      OpBranch %20
6766 
6767      %89 = OpLabel
6768      OpBranch %99
6769 
6770      %99 = OpLabel
6771      OpReturn
6772 
6773      OpFunctionEnd
6774 )";
6775   auto p = parser(test::Assemble(assembly));
6776   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6777   auto fe = p->function_emitter(100);
6778   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6779   EXPECT_THAT(
6780       p->error(),
6781       Eq("Branch from block 30 to block 60 is an invalid exit from "
6782          "construct starting at block 20; branch bypasses continue target 50"));
6783 }
6784 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_AfterContinueToContinueInterior)6785 TEST_F(SpvParserCFGTest,
6786        ClassifyCFGEdges_DomViolation_AfterContinueToContinueInterior) {
6787   auto assembly = CommonTypes() + R"(
6788      %100 = OpFunction %void None %voidfn
6789 
6790      %10 = OpLabel
6791      OpBranch %20
6792 
6793      %20 = OpLabel
6794      OpLoopMerge %80 %50 None
6795      OpBranchConditional %cond %30 %80
6796 
6797      %30 = OpLabel
6798      OpBranch %50
6799 
6800      %50 = OpLabel
6801      OpBranch %60
6802 
6803      %60 = OpLabel
6804      OpBranch %20
6805 
6806      %80 = OpLabel
6807      OpBranch %60 ; bad branch
6808 )";
6809   auto p = parser(test::Assemble(assembly));
6810   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6811   auto fe = p->function_emitter(100);
6812   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6813   EXPECT_THAT(
6814       p->error(),
6815       Eq("Branch from block 50 to block 60 is an invalid exit from "
6816          "construct starting at block 50; branch bypasses merge block 80"));
6817 }
6818 
TEST_F(SpvParserCFGTest,FindSwitchCaseHeaders_DomViolation_SwitchCase_CantBeMergeForOtherConstruct)6819 TEST_F(
6820     SpvParserCFGTest,
6821     FindSwitchCaseHeaders_DomViolation_SwitchCase_CantBeMergeForOtherConstruct) {  // NOLINT
6822   auto assembly = CommonTypes() + R"(
6823      %100 = OpFunction %void None %voidfn
6824 
6825      %10 = OpLabel
6826      OpSelectionMerge %99 None
6827      OpSwitch %selector %99 20 %20 50 %50
6828 
6829      %20 = OpLabel
6830      OpSelectionMerge %50 None
6831      OpBranchConditional %cond %30 %50
6832 
6833      %30 = OpLabel
6834      OpBranch %50
6835 
6836      %50 = OpLabel ; case and merge block. Error
6837      OpBranch %99
6838 
6839      %99 = OpLabel
6840      OpReturn
6841 
6842      OpFunctionEnd
6843 )";
6844   auto p = parser(test::Assemble(assembly));
6845   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6846   auto fe = p->function_emitter(100);
6847   EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
6848   EXPECT_THAT(p->error(),
6849               Eq("Block 50 is a case block for switch-selection header 10 and "
6850                  "also the merge block for 20 (violates dominance rule)"));
6851 }
6852 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_DomViolation_SwitchDefault_CantBeMergeForOtherConstruct)6853 TEST_F(
6854     SpvParserCFGTest,
6855     ClassifyCFGEdges_DomViolation_SwitchDefault_CantBeMergeForOtherConstruct) {
6856   auto assembly = CommonTypes() + R"(
6857      %100 = OpFunction %void None %voidfn
6858 
6859      %10 = OpLabel
6860      OpSelectionMerge %99 None
6861      OpSwitch %selector %50 20 %20
6862 
6863      %20 = OpLabel
6864      OpSelectionMerge %50 None
6865      OpBranchConditional %cond %30 %50
6866 
6867      %30 = OpLabel
6868      OpBranch %50
6869 
6870      %50 = OpLabel ; default-case and merge block. Error
6871      OpBranch %99
6872 
6873      %99 = OpLabel
6874      OpReturn
6875 
6876      OpFunctionEnd
6877 )";
6878   auto p = parser(test::Assemble(assembly));
6879   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6880   auto fe = p->function_emitter(100);
6881   EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
6882   EXPECT_THAT(p->error(),
6883               Eq("Block 50 is the default block for switch-selection header 10 "
6884                  "and also the merge block for 20 (violates dominance rule)"));
6885 }
6886 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_TooManyBackedges)6887 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_TooManyBackedges) {
6888   auto assembly = CommonTypes() + R"(
6889      %100 = OpFunction %void None %voidfn
6890 
6891      %10 = OpLabel
6892      OpBranch %20
6893 
6894      %20 = OpLabel
6895      OpLoopMerge %99 %50 None
6896      OpBranchConditional %cond %30 %99
6897 
6898      %30 = OpLabel
6899      OpBranchConditional %cond2 %20 %50
6900 
6901      %50 = OpLabel
6902      OpBranch %20
6903 
6904      %99 = OpLabel
6905      OpReturn
6906 
6907      OpFunctionEnd
6908 )";
6909   auto p = parser(test::Assemble(assembly));
6910   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6911   auto fe = p->function_emitter(100);
6912   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6913   EXPECT_THAT(
6914       p->error(),
6915       Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
6916 }
6917 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_NeededMerge_BranchConditional)6918 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_NeededMerge_BranchConditional) {
6919   auto assembly = CommonTypes() + R"(
6920      %100 = OpFunction %void None %voidfn
6921 
6922      %20 = OpLabel
6923      OpBranchConditional %cond %30 %40
6924 
6925      %30 = OpLabel
6926      OpBranch %99
6927 
6928      %40 = OpLabel
6929      OpBranch %99
6930 
6931      %99 = OpLabel
6932      OpReturn
6933 
6934      OpFunctionEnd
6935 )";
6936   auto p = parser(test::Assemble(assembly));
6937   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6938   auto fe = p->function_emitter(100);
6939   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6940   EXPECT_THAT(p->error(),
6941               Eq("Control flow diverges at block 20 (to 30, 40) but it is not "
6942                  "a structured header (it has no merge instruction)"));
6943 }
6944 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_NeededMerge_Switch)6945 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_NeededMerge_Switch) {
6946   auto assembly = CommonTypes() + R"(
6947      %100 = OpFunction %void None %voidfn
6948 
6949      %10 = OpLabel
6950      OpSwitch %selector %99 20 %20 30 %30
6951 
6952      %20 = OpLabel
6953      OpBranch %99
6954 
6955      %30 = OpLabel
6956      OpBranch %99
6957 
6958      %99 = OpLabel
6959      OpReturn
6960 
6961      OpFunctionEnd
6962 )";
6963   auto p = parser(test::Assemble(assembly));
6964   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
6965   auto fe = p->function_emitter(100);
6966   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
6967   EXPECT_THAT(p->error(),
6968               Eq("Control flow diverges at block 10 (to 99, 20) but it is not "
6969                  "a structured header (it has no merge instruction)"));
6970 }
6971 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Pathological_Forward_LoopHeadSplitBody)6972 TEST_F(SpvParserCFGTest,
6973        ClassifyCFGEdges_Pathological_Forward_LoopHeadSplitBody) {
6974   // In this case the branch-conditional in the loop header is really also a
6975   // selection header.
6976   auto assembly = CommonTypes() + R"(
6977      %100 = OpFunction %void None %voidfn
6978 
6979      %10 = OpLabel
6980      OpBranch %20
6981 
6982      %20 = OpLabel
6983      OpLoopMerge %99 %80 None
6984      OpBranchConditional %cond %30 %50 ; what to make of this?
6985 
6986      %30 = OpLabel
6987      OpBranch %99
6988 
6989      %50 = OpLabel
6990      OpBranch %99
6991 
6992      %80 = OpLabel
6993      OpBranch %20
6994 
6995      %99 = OpLabel
6996      OpReturn
6997 
6998      OpFunctionEnd
6999 )";
7000   auto p = parser(test::Assemble(assembly));
7001   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7002   auto fe = p->function_emitter(100);
7003   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7004 
7005   auto* bi = fe.GetBlockInfo(20);
7006   ASSERT_NE(bi, nullptr);
7007   EXPECT_EQ(bi->succ_edge.count(30), 1u);
7008   EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
7009   EXPECT_EQ(bi->succ_edge.count(50), 1u);
7010   EXPECT_EQ(bi->succ_edge[50], EdgeKind::kForward);
7011 }
7012 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Pathological_Forward_Premerge)7013 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Pathological_Forward_Premerge) {
7014   // Two arms of an if-selection converge early, before the merge block
7015   auto assembly = CommonTypes() + R"(
7016      %100 = OpFunction %void None %voidfn
7017 
7018      %10 = OpLabel
7019      OpSelectionMerge %99 None
7020      OpBranchConditional %cond %20 %30
7021 
7022      %20 = OpLabel
7023      OpBranch %50
7024 
7025      %30 = OpLabel
7026      OpBranch %50
7027 
7028      %50 = OpLabel ; this is an early merge!
7029      OpBranch %60
7030 
7031      %60 = OpLabel ; still early merge
7032      OpBranch %99
7033 
7034      %99 = OpLabel
7035      OpReturn
7036 
7037      OpFunctionEnd
7038 )";
7039   auto p = parser(test::Assemble(assembly));
7040   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7041   auto fe = p->function_emitter(100);
7042   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7043 
7044   auto* bi20 = fe.GetBlockInfo(20);
7045   ASSERT_NE(bi20, nullptr);
7046   EXPECT_EQ(bi20->succ_edge.count(50), 1u);
7047   EXPECT_EQ(bi20->succ_edge[50], EdgeKind::kForward);
7048 
7049   auto* bi30 = fe.GetBlockInfo(30);
7050   ASSERT_NE(bi30, nullptr);
7051   EXPECT_EQ(bi30->succ_edge.count(50), 1u);
7052   EXPECT_EQ(bi30->succ_edge[50], EdgeKind::kForward);
7053 
7054   auto* bi50 = fe.GetBlockInfo(50);
7055   ASSERT_NE(bi50, nullptr);
7056   EXPECT_EQ(bi50->succ_edge.count(60), 1u);
7057   EXPECT_EQ(bi50->succ_edge[60], EdgeKind::kForward);
7058 
7059   auto* bi60 = fe.GetBlockInfo(60);
7060   ASSERT_NE(bi60, nullptr);
7061   EXPECT_EQ(bi60->succ_edge.count(99), 1u);
7062   EXPECT_EQ(bi60->succ_edge[99], EdgeKind::kIfBreak);
7063 }
7064 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_Pathological_Forward_Regardless)7065 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Pathological_Forward_Regardless) {
7066   // Both arms of an OpBranchConditional go to the same target.
7067   auto assembly = CommonTypes() + R"(
7068      %100 = OpFunction %void None %voidfn
7069 
7070      %10 = OpLabel
7071      OpSelectionMerge %99 None
7072      OpBranchConditional %cond %20 %20 ; same target!
7073 
7074      %20 = OpLabel
7075      OpBranch %99
7076 
7077      %99 = OpLabel
7078      OpReturn
7079 
7080      OpFunctionEnd
7081 )";
7082   auto p = parser(test::Assemble(assembly));
7083   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7084   auto fe = p->function_emitter(100);
7085   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7086 
7087   auto* bi10 = fe.GetBlockInfo(10);
7088   ASSERT_NE(bi10, nullptr);
7089   EXPECT_EQ(bi10->succ_edge.count(20), 1u);
7090   EXPECT_EQ(bi10->succ_edge[20], EdgeKind::kForward);
7091 
7092   auto* bi20 = fe.GetBlockInfo(20);
7093   ASSERT_NE(bi20, nullptr);
7094   EXPECT_EQ(bi20->succ_edge.count(99), 1u);
7095   EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
7096 }
7097 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_NoIf)7098 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_NoIf) {
7099   auto assembly = CommonTypes() + R"(
7100      %100 = OpFunction %void None %voidfn
7101 
7102      %10 = OpLabel
7103      OpReturn
7104 
7105      OpFunctionEnd
7106 )";
7107   auto p = parser(test::Assemble(assembly));
7108   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7109   auto fe = p->function_emitter(100);
7110   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7111 
7112   auto* bi = fe.GetBlockInfo(10);
7113   ASSERT_NE(bi, nullptr);
7114   EXPECT_EQ(bi->true_head, 0u);
7115   EXPECT_EQ(bi->false_head, 0u);
7116   EXPECT_EQ(bi->premerge_head, 0u);
7117 }
7118 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_ThenElse)7119 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_ThenElse) {
7120   auto assembly = CommonTypes() + R"(
7121      %100 = OpFunction %void None %voidfn
7122 
7123      %10 = OpLabel
7124      OpSelectionMerge %99 None
7125      OpBranchConditional %cond %20 %30
7126 
7127      %20 = OpLabel
7128      OpBranch %99
7129 
7130      %30 = OpLabel
7131      OpBranch %99
7132 
7133      %99 = OpLabel
7134      OpReturn
7135 
7136      OpFunctionEnd
7137 )";
7138   auto p = parser(test::Assemble(assembly));
7139   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7140   auto fe = p->function_emitter(100);
7141   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7142 
7143   auto* bi10 = fe.GetBlockInfo(10);
7144   ASSERT_NE(bi10, nullptr);
7145   EXPECT_EQ(bi10->true_head, 20u);
7146   EXPECT_EQ(bi10->false_head, 30u);
7147   EXPECT_EQ(bi10->premerge_head, 0u);
7148 
7149   auto* bi20 = fe.GetBlockInfo(20);
7150   ASSERT_NE(bi20, nullptr);
7151   EXPECT_EQ(bi20->true_head, 0u);
7152   EXPECT_EQ(bi20->false_head, 0u);
7153   EXPECT_EQ(bi20->premerge_head, 0u);
7154 
7155   auto* bi30 = fe.GetBlockInfo(30);
7156   ASSERT_NE(bi30, nullptr);
7157   EXPECT_EQ(bi30->true_head, 0u);
7158   EXPECT_EQ(bi30->false_head, 0u);
7159   EXPECT_EQ(bi30->premerge_head, 0u);
7160 
7161   auto* bi99 = fe.GetBlockInfo(99);
7162   ASSERT_NE(bi99, nullptr);
7163   EXPECT_EQ(bi99->true_head, 0u);
7164   EXPECT_EQ(bi99->false_head, 0u);
7165   EXPECT_EQ(bi99->premerge_head, 0u);
7166 }
7167 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_IfOnly)7168 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_IfOnly) {
7169   auto assembly = CommonTypes() + R"(
7170      %100 = OpFunction %void None %voidfn
7171 
7172      %10 = OpLabel
7173      OpSelectionMerge %99 None
7174      OpBranchConditional %cond %30 %99
7175 
7176      %30 = OpLabel
7177      OpBranch %99
7178 
7179      %99 = OpLabel
7180      OpReturn
7181 
7182      OpFunctionEnd
7183 )";
7184   auto p = parser(test::Assemble(assembly));
7185   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7186   auto fe = p->function_emitter(100);
7187   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7188 
7189   auto* bi10 = fe.GetBlockInfo(10);
7190   ASSERT_NE(bi10, nullptr);
7191   EXPECT_EQ(bi10->true_head, 30u);
7192   EXPECT_EQ(bi10->false_head, 0u);
7193   EXPECT_EQ(bi10->premerge_head, 0u);
7194 
7195   auto* bi30 = fe.GetBlockInfo(30);
7196   ASSERT_NE(bi30, nullptr);
7197   EXPECT_EQ(bi30->true_head, 0u);
7198   EXPECT_EQ(bi30->false_head, 0u);
7199   EXPECT_EQ(bi30->premerge_head, 0u);
7200 
7201   auto* bi99 = fe.GetBlockInfo(99);
7202   ASSERT_NE(bi99, nullptr);
7203   EXPECT_EQ(bi99->true_head, 0u);
7204   EXPECT_EQ(bi99->false_head, 0u);
7205   EXPECT_EQ(bi99->premerge_head, 0u);
7206 }
7207 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_ElseOnly)7208 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_ElseOnly) {
7209   auto assembly = CommonTypes() + R"(
7210      %100 = OpFunction %void None %voidfn
7211 
7212      %10 = OpLabel
7213      OpSelectionMerge %99 None
7214      OpBranchConditional %cond %99 %30
7215 
7216      %30 = OpLabel
7217      OpBranch %99
7218 
7219      %99 = OpLabel
7220      OpReturn
7221 
7222      OpFunctionEnd
7223 )";
7224   auto p = parser(test::Assemble(assembly));
7225   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7226   auto fe = p->function_emitter(100);
7227   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7228 
7229   auto* bi10 = fe.GetBlockInfo(10);
7230   ASSERT_NE(bi10, nullptr);
7231   EXPECT_EQ(bi10->true_head, 0u);
7232   EXPECT_EQ(bi10->false_head, 30u);
7233   EXPECT_EQ(bi10->premerge_head, 0u);
7234 
7235   auto* bi30 = fe.GetBlockInfo(30);
7236   ASSERT_NE(bi30, nullptr);
7237   EXPECT_EQ(bi30->true_head, 0u);
7238   EXPECT_EQ(bi30->false_head, 0u);
7239   EXPECT_EQ(bi30->premerge_head, 0u);
7240 
7241   auto* bi99 = fe.GetBlockInfo(99);
7242   ASSERT_NE(bi99, nullptr);
7243   EXPECT_EQ(bi99->true_head, 0u);
7244   EXPECT_EQ(bi99->false_head, 0u);
7245   EXPECT_EQ(bi99->premerge_head, 0u);
7246 }
7247 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_Regardless)7248 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Regardless) {
7249   auto assembly = CommonTypes() + R"(
7250      %100 = OpFunction %void None %voidfn
7251 
7252      %10 = OpLabel
7253      OpSelectionMerge %99 None
7254      OpBranchConditional %cond %20 %20 ; same target
7255 
7256      %20 = OpLabel
7257      OpBranch %80
7258 
7259      %80 = OpLabel
7260      OpBranch %99
7261 
7262      %99 = OpLabel
7263      OpReturn
7264 
7265      OpFunctionEnd
7266 )";
7267   auto p = parser(test::Assemble(assembly));
7268   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7269   auto fe = p->function_emitter(100);
7270   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7271 
7272   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
7273 
7274   auto* bi10 = fe.GetBlockInfo(10);
7275   ASSERT_NE(bi10, nullptr);
7276   EXPECT_EQ(bi10->true_head, 20u);
7277   EXPECT_EQ(bi10->false_head, 20u);
7278   EXPECT_EQ(bi10->premerge_head, 0u);
7279 }
7280 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_Premerge_Simple)7281 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Premerge_Simple) {
7282   auto assembly = CommonTypes() + R"(
7283      %100 = OpFunction %void None %voidfn
7284 
7285      %10 = OpLabel
7286      OpSelectionMerge %99 None
7287      OpBranchConditional %cond %20 %30
7288 
7289      %20 = OpLabel
7290      OpBranch %80
7291 
7292      %30 = OpLabel
7293      OpBranch %80
7294 
7295      %80 = OpLabel ; premerge node
7296      OpBranch %99
7297 
7298      %99 = OpLabel
7299      OpReturn
7300 
7301      OpFunctionEnd
7302 )";
7303   auto p = parser(test::Assemble(assembly));
7304   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7305   auto fe = p->function_emitter(100);
7306   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7307 
7308   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
7309 
7310   auto* bi10 = fe.GetBlockInfo(10);
7311   ASSERT_NE(bi10, nullptr);
7312   EXPECT_EQ(bi10->true_head, 20u);
7313   EXPECT_EQ(bi10->false_head, 30u);
7314   EXPECT_EQ(bi10->premerge_head, 80u);
7315 }
7316 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_Premerge_ThenDirectToElse)7317 TEST_F(SpvParserCFGTest,
7318        FindIfSelectionInternalHeaders_Premerge_ThenDirectToElse) {
7319   auto assembly = CommonTypes() + R"(
7320      %100 = OpFunction %void None %voidfn
7321 
7322      %10 = OpLabel
7323      OpSelectionMerge %99 None
7324      OpBranchConditional %cond %20 %30
7325 
7326      %20 = OpLabel
7327      OpBranch %30
7328 
7329      %30 = OpLabel
7330      OpBranch %80
7331 
7332      %80 = OpLabel ; premerge node
7333      OpBranch %99
7334 
7335      %99 = OpLabel
7336      OpReturn
7337 
7338      OpFunctionEnd
7339 )";
7340   auto p = parser(test::Assemble(assembly));
7341   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7342   auto fe = p->function_emitter(100);
7343   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7344 
7345   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
7346 
7347   auto* bi10 = fe.GetBlockInfo(10);
7348   ASSERT_NE(bi10, nullptr);
7349   EXPECT_EQ(bi10->true_head, 20u);
7350   EXPECT_EQ(bi10->false_head, 30u);
7351   EXPECT_EQ(bi10->premerge_head, 30u);
7352 }
7353 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_Premerge_ElseDirectToThen)7354 TEST_F(SpvParserCFGTest,
7355        FindIfSelectionInternalHeaders_Premerge_ElseDirectToThen) {
7356   auto assembly = CommonTypes() + R"(
7357      %100 = OpFunction %void None %voidfn
7358 
7359      %10 = OpLabel
7360      OpSelectionMerge %99 None
7361      OpBranchConditional %cond %20 %30
7362 
7363      %20 = OpLabel
7364      OpBranch %80 ; branches to premerge
7365 
7366      %30 = OpLabel ; else
7367      OpBranch %20  ; branches to then
7368 
7369      %80 = OpLabel ; premerge node
7370      OpBranch %99
7371 
7372      %99 = OpLabel
7373      OpReturn
7374 
7375      OpFunctionEnd
7376 )";
7377   auto p = parser(test::Assemble(assembly));
7378   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7379   auto fe = p->function_emitter(100);
7380   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7381 
7382   EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
7383 
7384   auto* bi10 = fe.GetBlockInfo(10);
7385   ASSERT_NE(bi10, nullptr);
7386   EXPECT_EQ(bi10->true_head, 20u);
7387   EXPECT_EQ(bi10->false_head, 30u);
7388   EXPECT_EQ(bi10->premerge_head, 20u);
7389 }
7390 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_Premerge_MultiCandidate_IsError)7391 TEST_F(SpvParserCFGTest,
7392        FindIfSelectionInternalHeaders_Premerge_MultiCandidate_IsError) {
7393   auto assembly = CommonTypes() + R"(
7394      %100 = OpFunction %void None %voidfn
7395 
7396      %10 = OpLabel
7397      OpSelectionMerge %99 None
7398      OpBranchConditional %cond %20 %30
7399 
7400      %20 = OpLabel
7401      ; Try to force several branches down into "else" territory,
7402      ; but we error out earlier in the flow due to lack of merge
7403      ; instruction.
7404      OpBranchConditional %cond2  %70 %80
7405 
7406      %30 = OpLabel
7407      OpBranch %70
7408 
7409      %70 = OpLabel ; candidate premerge
7410      OpBranch %80
7411 
7412      %80 = OpLabel ; canddiate premerge
7413      OpBranch %99
7414 
7415      %99 = OpLabel
7416      OpReturn
7417 
7418      OpFunctionEnd
7419 )";
7420   auto p = parser(test::Assemble(assembly));
7421   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7422   auto fe = p->function_emitter(100);
7423   // Error out sooner in the flow
7424   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
7425   EXPECT_THAT(p->error(),
7426               Eq("Control flow diverges at block 20 (to 70, 80) but it is not "
7427                  "a structured header (it has no merge instruction)"));
7428 }
7429 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_FromThen_ForwardWithinThen)7430 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromThen_ForwardWithinThen) {
7431   // SPIR-V allows this unusual configuration.
7432   auto assembly = CommonTypes() + R"(
7433      %100 = OpFunction %void None %voidfn
7434 
7435      %10 = OpLabel
7436      OpSelectionMerge %99 None
7437      OpBranchConditional %cond %20 %99
7438 
7439      %20 = OpLabel
7440      OpBranchConditional %cond2 %99 %80 ; break with forward edge
7441 
7442      %80 = OpLabel ; still in then clause
7443      OpBranch %99
7444 
7445      %99 = OpLabel
7446      OpReturn
7447      OpFunctionEnd
7448 )";
7449   auto p = parser(test::Assemble(assembly));
7450   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7451   auto fe = p->function_emitter(100);
7452   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7453   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
7454 
7455   auto* bi20 = fe.GetBlockInfo(20);
7456   ASSERT_NE(bi20, nullptr);
7457   EXPECT_EQ(bi20->succ_edge.count(80), 1u);
7458   EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
7459   EXPECT_EQ(bi20->succ_edge.count(99), 1u);
7460   EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
7461 
7462   EXPECT_THAT(p->error(), Eq(""));
7463 }
7464 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_FromElse_ForwardWithinElse)7465 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromElse_ForwardWithinElse) {
7466   // SPIR-V allows this unusual configuration.
7467   auto assembly = CommonTypes() + R"(
7468      %100 = OpFunction %void None %voidfn
7469 
7470      %10 = OpLabel
7471      OpSelectionMerge %99 None
7472      OpBranchConditional %cond %20 %30
7473 
7474      %20 = OpLabel
7475      OpBranch %99
7476 
7477      %30 = OpLabel ; else clause
7478      OpBranchConditional %cond2 %99 %80 ; break with forward edge
7479 
7480      %80 = OpLabel ; still in then clause
7481      OpBranch %99
7482 
7483      %99 = OpLabel
7484      OpReturn
7485      OpFunctionEnd
7486 )";
7487   auto p = parser(test::Assemble(assembly));
7488   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7489   auto fe = p->function_emitter(100);
7490   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7491   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
7492 
7493   auto* bi30 = fe.GetBlockInfo(30);
7494   ASSERT_NE(bi30, nullptr);
7495   EXPECT_EQ(bi30->succ_edge.count(80), 1u);
7496   EXPECT_EQ(bi30->succ_edge[80], EdgeKind::kForward);
7497   EXPECT_EQ(bi30->succ_edge.count(99), 1u);
7498   EXPECT_EQ(bi30->succ_edge[99], EdgeKind::kIfBreak);
7499 
7500   EXPECT_THAT(p->error(), Eq(""));
7501 }
7502 
TEST_F(SpvParserCFGTest,ClassifyCFGEdges_IfBreak_WithForwardToPremerge)7503 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_WithForwardToPremerge) {
7504   auto assembly = CommonTypes() + R"(
7505      %100 = OpFunction %void None %voidfn
7506 
7507      %10 = OpLabel
7508      OpSelectionMerge %99 None
7509      OpBranchConditional %cond %20 %30
7510 
7511      %20 = OpLabel ; then
7512      OpBranchConditional %cond2 %99 %80 ; break with forward to premerge
7513 
7514      %30 = OpLabel ; else
7515      OpBranch %80
7516 
7517      %80 = OpLabel ; premerge node
7518      OpBranch %99
7519 
7520      %99 = OpLabel
7521      OpReturn
7522      OpFunctionEnd
7523 )";
7524   auto p = parser(test::Assemble(assembly));
7525   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7526   auto fe = p->function_emitter(100);
7527   EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
7528   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
7529 
7530   auto* bi20 = fe.GetBlockInfo(20);
7531   ASSERT_NE(bi20, nullptr);
7532   EXPECT_EQ(bi20->succ_edge.count(80), 1u);
7533   EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
7534   EXPECT_EQ(bi20->succ_edge.count(99), 1u);
7535   EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
7536 
7537   EXPECT_THAT(p->error(), Eq(""));
7538 
7539   // TODO(crbug.com/tint/775): The SPIR-V reader errors out on this case.
7540   // Remove this when it's fixed.
7541   p->DeliberatelyInvalidSpirv();
7542 }
7543 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeTrueHeader)7544 TEST_F(
7545     SpvParserCFGTest,
7546     FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeTrueHeader) {  // NOLINT - line length
7547   auto assembly = CommonTypes() + R"(
7548      %100 = OpFunction %void None %voidfn
7549 
7550      %10 = OpLabel
7551      OpSelectionMerge %99 None
7552      OpBranchConditional %cond %40 %20
7553 
7554      %20 = OpLabel
7555      OpSelectionMerge %40 None
7556      OpBranchConditional %cond2 %30 %40
7557 
7558      %30 = OpLabel
7559      OpBranch %40
7560 
7561      %40 = OpLabel ; inner merge, and true-head for outer if-selection
7562      OpBranch %99
7563 
7564      %99 = OpLabel ; outer merge
7565      OpReturn
7566 
7567      OpFunctionEnd
7568 )";
7569   auto p = parser(test::Assemble(assembly));
7570   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7571   auto fe = p->function_emitter(100);
7572   EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
7573   EXPECT_THAT(
7574       p->error(),
7575       Eq("Block 40 is the true branch for if-selection header 10 and also the "
7576          "merge block for header block 20 (violates dominance rule)"));
7577 }
7578 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeFalseHeader)7579 TEST_F(
7580     SpvParserCFGTest,
7581     FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeFalseHeader) {  // NOLINT - line length
7582   auto assembly = CommonTypes() + R"(
7583      %100 = OpFunction %void None %voidfn
7584 
7585      %10 = OpLabel
7586      OpSelectionMerge %99 None
7587      OpBranchConditional %cond %20 %40
7588 
7589      %20 = OpLabel
7590      OpSelectionMerge %40 None
7591      OpBranchConditional %cond %30 %40
7592 
7593      %30 = OpLabel
7594      OpBranch %40
7595 
7596      %40 = OpLabel ; inner merge, and true-head for outer if-selection
7597      OpBranch %99
7598 
7599      %99 = OpLabel ; outer merge
7600      OpReturn
7601 
7602      OpFunctionEnd
7603 )";
7604   auto p = parser(test::Assemble(assembly));
7605   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7606   auto fe = p->function_emitter(100);
7607   EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
7608   EXPECT_THAT(
7609       p->error(),
7610       Eq("Block 40 is the false branch for if-selection header 10 and also the "
7611          "merge block for header block 20 (violates dominance rule)"));
7612 }
7613 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBePremerge)7614 TEST_F(
7615     SpvParserCFGTest,
7616     FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBePremerge) {
7617   auto assembly = CommonTypes() + R"(
7618      %100 = OpFunction %void None %voidfn
7619 
7620      %10 = OpLabel ; outer if-header
7621      OpSelectionMerge %99 None
7622      OpBranchConditional %cond %20 %50
7623 
7624      %20 = OpLabel
7625      OpBranch %70
7626 
7627      %50 = OpLabel ; inner if-header
7628      OpSelectionMerge %70 None
7629      OpBranchConditional %cond %60 %70
7630 
7631      %60 = OpLabel
7632      OpBranch %70
7633 
7634      %70 = OpLabel ; inner merge, and premerge for outer if-selection
7635      OpBranch %80
7636 
7637      %80 = OpLabel
7638      OpBranch %99
7639 
7640      %99 = OpLabel ; outer merge
7641      OpReturn
7642 
7643      OpFunctionEnd
7644 )";
7645   auto p = parser(test::Assemble(assembly));
7646   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7647   auto fe = p->function_emitter(100);
7648   EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
7649   EXPECT_THAT(p->error(),
7650               Eq("Block 70 is the merge block for 50 but has alternate paths "
7651                  "reaching it, starting from blocks 20 and 50 which are the "
7652                  "true and false branches for the if-selection header block 10 "
7653                  "(violates dominance rule)"));
7654 }
7655 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_TrueBranch_LoopBreak_Ok)7656 TEST_F(SpvParserCFGTest,
7657        FindIfSelectionInternalHeaders_TrueBranch_LoopBreak_Ok) {
7658   // crbug.com/tint/243
7659   auto assembly = CommonTypes() + R"(
7660      %100 = OpFunction %void None %voidfn
7661 
7662      %5 = OpLabel
7663      OpBranch %10
7664 
7665      %10 = OpLabel
7666      OpLoopMerge %99 %90 None
7667      OpBranch %20
7668 
7669      %20 = OpLabel
7670      OpSelectionMerge %40 None
7671      OpBranchConditional %cond %99 %30 ; true branch breaking is ok
7672 
7673      %30 = OpLabel
7674      OpBranch %40
7675 
7676      %40 = OpLabel ; selection merge
7677      OpBranch %90
7678 
7679      %90 = OpLabel ; continue target
7680      OpBranch %10 ; backedge
7681 
7682      %99 = OpLabel ; loop merge
7683      OpReturn
7684 
7685      OpFunctionEnd
7686 )";
7687   auto p = parser(test::Assemble(assembly));
7688   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7689   auto fe = p->function_emitter(100);
7690   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7691   EXPECT_THAT(p->error(), Eq(""));
7692 }
7693 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_TrueBranch_LoopContinue_Ok)7694 TEST_F(SpvParserCFGTest,
7695        FindIfSelectionInternalHeaders_TrueBranch_LoopContinue_Ok) {
7696   // crbug.com/tint/243
7697   auto assembly = CommonTypes() + R"(
7698      %100 = OpFunction %void None %voidfn
7699 
7700      %5 = OpLabel
7701      OpBranch %10
7702 
7703      %10 = OpLabel
7704      OpLoopMerge %99 %90 None
7705      OpBranch %20
7706 
7707      %20 = OpLabel
7708      OpSelectionMerge %40 None
7709      OpBranchConditional %cond %90 %30 ; true branch continue is ok
7710 
7711      %30 = OpLabel
7712      OpBranch %40
7713 
7714      %40 = OpLabel ; selection merge
7715      OpBranch %90
7716 
7717      %90 = OpLabel ; continue target
7718      OpBranch %10 ; backedge
7719 
7720      %99 = OpLabel ; loop merge
7721      OpReturn
7722 
7723      OpFunctionEnd
7724 )";
7725   auto p = parser(test::Assemble(assembly));
7726   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7727   auto fe = p->function_emitter(100);
7728   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7729   EXPECT_THAT(p->error(), Eq(""));
7730 }
7731 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_TrueBranch_SwitchBreak_Ok)7732 TEST_F(SpvParserCFGTest,
7733        FindIfSelectionInternalHeaders_TrueBranch_SwitchBreak_Ok) {
7734   // crbug.com/tint/243
7735   auto assembly = CommonTypes() + R"(
7736      %100 = OpFunction %void None %voidfn
7737 
7738      %10 = OpLabel
7739      OpSelectionMerge %99 None
7740      OpSwitch %uint_20 %99 20 %20
7741 
7742      %20 = OpLabel
7743      OpSelectionMerge %40 None
7744      OpBranchConditional %cond %99 %30 ; true branch switch break is ok
7745 
7746      %30 = OpLabel
7747      OpBranch %40
7748 
7749      %40 = OpLabel ; if-selection merge
7750      OpBranch %99
7751 
7752      %99 = OpLabel ; switch merge
7753      OpReturn
7754 
7755      OpFunctionEnd
7756 )";
7757   auto p = parser(test::Assemble(assembly));
7758   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7759   auto fe = p->function_emitter(100);
7760   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7761   EXPECT_THAT(p->error(), Eq(""));
7762 }
7763 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_FalseBranch_LoopBreak_Ok)7764 TEST_F(SpvParserCFGTest,
7765        FindIfSelectionInternalHeaders_FalseBranch_LoopBreak_Ok) {
7766   // crbug.com/tint/243
7767   auto assembly = CommonTypes() + R"(
7768      %100 = OpFunction %void None %voidfn
7769 
7770      %5 = OpLabel
7771      OpBranch %10
7772 
7773      %10 = OpLabel
7774      OpLoopMerge %99 %90 None
7775      OpBranch %20
7776 
7777      %20 = OpLabel
7778      OpSelectionMerge %40 None
7779      OpBranchConditional %cond %30 %99 ; false branch breaking is ok
7780 
7781      %30 = OpLabel
7782      OpBranch %40
7783 
7784      %40 = OpLabel ; selection merge
7785      OpBranch %90
7786 
7787      %90 = OpLabel ; continue target
7788      OpBranch %10 ; backedge
7789 
7790      %99 = OpLabel ; loop merge
7791      OpReturn
7792 
7793      OpFunctionEnd
7794 )";
7795   auto p = parser(test::Assemble(assembly));
7796   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7797   auto fe = p->function_emitter(100);
7798   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7799   EXPECT_THAT(p->error(), Eq(""));
7800 }
7801 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_FalseBranch_LoopContinue_Ok)7802 TEST_F(SpvParserCFGTest,
7803        FindIfSelectionInternalHeaders_FalseBranch_LoopContinue_Ok) {
7804   // crbug.com/tint/243
7805   auto assembly = CommonTypes() + R"(
7806      %100 = OpFunction %void None %voidfn
7807 
7808      %5 = OpLabel
7809      OpBranch %10
7810 
7811      %10 = OpLabel
7812      OpLoopMerge %99 %90 None
7813      OpBranch %20
7814 
7815      %20 = OpLabel
7816      OpSelectionMerge %40 None
7817      OpBranchConditional %cond %30 %90 ; false branch continue is ok
7818 
7819      %30 = OpLabel
7820      OpBranch %40
7821 
7822      %40 = OpLabel ; selection merge
7823      OpBranch %90
7824 
7825      %90 = OpLabel ; continue target
7826      OpBranch %10 ; backedge
7827 
7828      %99 = OpLabel ; loop merge
7829      OpReturn
7830 
7831      OpFunctionEnd
7832 )";
7833   auto p = parser(test::Assemble(assembly));
7834   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7835   auto fe = p->function_emitter(100);
7836   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7837   EXPECT_THAT(p->error(), Eq(""));
7838 }
7839 
TEST_F(SpvParserCFGTest,FindIfSelectionInternalHeaders_FalseBranch_SwitchBreak_Ok)7840 TEST_F(SpvParserCFGTest,
7841        FindIfSelectionInternalHeaders_FalseBranch_SwitchBreak_Ok) {
7842   // crbug.com/tint/243
7843   auto assembly = CommonTypes() + R"(
7844      %100 = OpFunction %void None %voidfn
7845 
7846      %10 = OpLabel
7847      OpSelectionMerge %99 None
7848      OpSwitch %uint_20 %99 20 %20
7849 
7850      %20 = OpLabel
7851      OpSelectionMerge %40 None
7852      OpBranchConditional %cond %30 %99 ; false branch switch break is ok
7853 
7854      %30 = OpLabel
7855      OpBranch %40
7856 
7857      %40 = OpLabel ; if-selection merge
7858      OpBranch %99
7859 
7860      %99 = OpLabel ; switch merge
7861      OpReturn
7862 
7863      OpFunctionEnd
7864 )";
7865   auto p = parser(test::Assemble(assembly));
7866   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7867   auto fe = p->function_emitter(100);
7868   EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
7869   EXPECT_THAT(p->error(), Eq(""));
7870 }
7871 
TEST_F(SpvParserCFGTest,EmitBody_IfBreak_FromThen_ForwardWithinThen)7872 TEST_F(SpvParserCFGTest, EmitBody_IfBreak_FromThen_ForwardWithinThen) {
7873   // Exercises the hard case where we a single OpBranchConditional has both
7874   // IfBreak and Forward edges, within the true-branch clause.
7875   auto assembly = CommonTypes() + R"(
7876      %100 = OpFunction %void None %voidfn
7877 
7878      %10 = OpLabel
7879      OpStore %var %uint_1
7880      OpSelectionMerge %99 None
7881      OpBranchConditional %cond %20 %50
7882 
7883      %20 = OpLabel
7884      OpStore %var %uint_2
7885      OpBranchConditional %cond2 %99 %30 ; kIfBreak with kForward
7886 
7887      %30 = OpLabel ; still in then clause
7888      OpStore %var %uint_3
7889      OpBranch %99
7890 
7891      %50 = OpLabel ; else clause
7892      OpStore %var %uint_4
7893      OpBranch %99
7894 
7895      %99 = OpLabel
7896      OpStore %var %uint_5
7897      OpReturn
7898      OpFunctionEnd
7899 )";
7900   auto p = parser(test::Assemble(assembly));
7901   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7902   auto fe = p->function_emitter(100);
7903   EXPECT_TRUE(fe.EmitBody()) << p->error();
7904   auto ast_body = fe.ast_body();
7905   auto got = test::ToString(p->program(), ast_body);
7906   auto* expect = R"(var_1 = 1u;
7907 var guard10 : bool = true;
7908 if (false) {
7909   var_1 = 2u;
7910   if (true) {
7911     guard10 = false;
7912   }
7913   if (guard10) {
7914     var_1 = 3u;
7915     guard10 = false;
7916   }
7917 } else {
7918   if (guard10) {
7919     var_1 = 4u;
7920     guard10 = false;
7921   }
7922 }
7923 var_1 = 5u;
7924 return;
7925 )";
7926   ASSERT_EQ(expect, got);
7927 }
7928 
TEST_F(SpvParserCFGTest,EmitBody_IfBreak_FromElse_ForwardWithinElse)7929 TEST_F(SpvParserCFGTest, EmitBody_IfBreak_FromElse_ForwardWithinElse) {
7930   // Exercises the hard case where we a single OpBranchConditional has both
7931   // IfBreak and Forward edges, within the false-branch clause.
7932   auto assembly = CommonTypes() + R"(
7933      %100 = OpFunction %void None %voidfn
7934 
7935      %10 = OpLabel
7936      OpStore %var %uint_1
7937      OpSelectionMerge %99 None
7938      OpBranchConditional %cond %20 %50
7939 
7940      %20 = OpLabel
7941      OpStore %var %uint_2
7942      OpBranch %99
7943 
7944      %50 = OpLabel ; else clause
7945      OpStore %var %uint_3
7946      OpBranchConditional %cond2 %99 %80 ; kIfBreak with kForward
7947 
7948      %80 = OpLabel ; still in then clause
7949      OpStore %var %uint_4
7950      OpBranch %99
7951 
7952      %99 = OpLabel
7953      OpStore %var %uint_5
7954      OpReturn
7955      OpFunctionEnd
7956 )";
7957   auto p = parser(test::Assemble(assembly));
7958   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
7959   auto fe = p->function_emitter(100);
7960   EXPECT_TRUE(fe.EmitBody()) << p->error();
7961   auto ast_body = fe.ast_body();
7962   auto got = test::ToString(p->program(), ast_body);
7963   auto* expect = R"(var_1 = 1u;
7964 var guard10 : bool = true;
7965 if (false) {
7966   var_1 = 2u;
7967   guard10 = false;
7968 } else {
7969   if (guard10) {
7970     var_1 = 3u;
7971     if (true) {
7972       guard10 = false;
7973     }
7974     if (guard10) {
7975       var_1 = 4u;
7976       guard10 = false;
7977     }
7978   }
7979 }
7980 var_1 = 5u;
7981 return;
7982 )";
7983   ASSERT_EQ(expect, got);
7984 }
7985 
TEST_F(SpvParserCFGTest,EmitBody_IfBreak_FromThenWithForward_FromElseWithForward_AlsoPremerge)7986 TEST_F(SpvParserCFGTest,
7987        EmitBody_IfBreak_FromThenWithForward_FromElseWithForward_AlsoPremerge) {
7988   // This is a combination of the previous two, but also adding a premerge.
7989   // We have IfBreak and Forward edges from the same OpBranchConditional, and
7990   // this occurs in the true-branch clause, the false-branch clause, and within
7991   // the premerge clause.  Flow guards have to be sprinkled in lots of places.
7992   auto assembly = CommonTypes() + R"(
7993      %100 = OpFunction %void None %voidfn
7994 
7995      %10 = OpLabel
7996      OpStore %var %uint_1
7997      OpSelectionMerge %99 None
7998      OpBranchConditional %cond %20 %50
7999 
8000      %20 = OpLabel ; then
8001      OpStore %var %uint_2
8002      OpBranchConditional %cond2 %21 %99 ; kForward and kIfBreak
8003 
8004      %21 = OpLabel ; still in then clause
8005      OpStore %var %uint_3
8006      OpBranch %80 ; to premerge
8007 
8008      %50 = OpLabel ; else clause
8009      OpStore %var %uint_4
8010      OpBranchConditional %cond2 %99 %51 ; kIfBreak with kForward
8011 
8012      %51 = OpLabel ; still in else clause
8013      OpStore %var %uint_5
8014      OpBranch %80 ; to premerge
8015 
8016      %80 = OpLabel ; premerge
8017      OpStore %var %uint_6
8018      OpBranchConditional %cond3 %81 %99
8019 
8020      %81 = OpLabel ; premerge
8021      OpStore %var %uint_7
8022      OpBranch %99
8023 
8024      %99 = OpLabel
8025      OpStore %var %uint_8
8026      OpReturn
8027      OpFunctionEnd
8028 )";
8029   auto p = parser(test::Assemble(assembly));
8030   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8031   auto fe = p->function_emitter(100);
8032   EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
8033   auto ast_body = fe.ast_body();
8034   auto got = test::ToString(p->program(), ast_body);
8035   auto* expect = R"(var_1 = 1u;
8036 var guard10 : bool = true;
8037 if (false) {
8038   var_1 = 2u;
8039   if (true) {
8040   } else {
8041     guard10 = false;
8042   }
8043   if (guard10) {
8044     var_1 = 3u;
8045   }
8046 } else {
8047   if (guard10) {
8048     var_1 = 4u;
8049     if (true) {
8050       guard10 = false;
8051     }
8052     if (guard10) {
8053       var_1 = 5u;
8054     }
8055   }
8056 }
8057 if (guard10) {
8058   var_1 = 6u;
8059   if (false) {
8060   } else {
8061     guard10 = false;
8062   }
8063   if (guard10) {
8064     var_1 = 7u;
8065     guard10 = false;
8066   }
8067 }
8068 var_1 = 8u;
8069 return;
8070 )";
8071   ASSERT_EQ(expect, got);
8072 }
8073 
TEST_F(SpvParserCFGTest,BlockIsContinueForMoreThanOneHeader)8074 TEST_F(SpvParserCFGTest, BlockIsContinueForMoreThanOneHeader) {
8075   // This is disallowed by the rule:
8076   //    "a continue block is valid only for the innermost loop it is nested
8077   //    inside of"
8078   auto assembly = CommonTypes() + R"(
8079      %100 = OpFunction %void None %voidfn
8080 
8081      %10 = OpLabel
8082      OpBranch %20
8083 
8084      %20 = OpLabel ; outer loop
8085      OpLoopMerge %99 %50 None
8086      OpBranchConditional %cond %50 %99
8087 
8088      %50 = OpLabel ; continue target, but also single-block loop
8089      OpLoopMerge %80 %50 None
8090      OpBranchConditional %cond2 %50 %80
8091 
8092      %80 = OpLabel
8093      OpBranch %20 ; backedge for outer loop
8094 
8095      %99 = OpLabel
8096      OpReturn
8097      OpFunctionEnd
8098 )";
8099   auto p = parser(test::Assemble(assembly));
8100   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8101   auto fe = p->function_emitter(100);
8102   fe.RegisterBasicBlocks();
8103   fe.ComputeBlockOrderAndPositions();
8104   EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
8105   EXPECT_FALSE(fe.RegisterMerges());
8106   EXPECT_THAT(p->error(), Eq("Block 50 declared as continue target for more "
8107                              "than one header: 20, 50"));
8108 }
8109 
TEST_F(SpvParserCFGTest,EmitBody_If_Empty)8110 TEST_F(SpvParserCFGTest, EmitBody_If_Empty) {
8111   auto p = parser(test::Assemble(CommonTypes() + R"(
8112      %100 = OpFunction %void None %voidfn
8113 
8114      %10 = OpLabel
8115      OpSelectionMerge %99 None
8116      OpBranchConditional %cond %99 %99
8117 
8118      %99 = OpLabel
8119      OpReturn
8120      OpFunctionEnd
8121   )"));
8122   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8123   auto fe = p->function_emitter(100);
8124   EXPECT_TRUE(fe.EmitBody()) << p->error();
8125 
8126   auto ast_body = fe.ast_body();
8127   auto got = test::ToString(p->program(), ast_body);
8128   auto* expect = R"(if (false) {
8129 }
8130 return;
8131 )";
8132   ASSERT_EQ(expect, got);
8133 }
8134 
TEST_F(SpvParserCFGTest,EmitBody_If_Then_NoElse)8135 TEST_F(SpvParserCFGTest, EmitBody_If_Then_NoElse) {
8136   auto p = parser(test::Assemble(CommonTypes() + R"(
8137      %100 = OpFunction %void None %voidfn
8138 
8139      %10 = OpLabel
8140      OpStore %var %uint_0
8141      OpSelectionMerge %99 None
8142      OpBranchConditional %cond %30 %99
8143 
8144      %99 = OpLabel
8145      OpStore %var %999
8146      OpReturn
8147 
8148      %30 = OpLabel
8149      OpStore %var %uint_1
8150      OpBranch %99
8151 
8152      OpFunctionEnd
8153   )"));
8154   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8155   auto fe = p->function_emitter(100);
8156   EXPECT_TRUE(fe.EmitBody()) << p->error();
8157 
8158   auto ast_body = fe.ast_body();
8159   auto got = test::ToString(p->program(), ast_body);
8160   auto* expect = R"(var_1 = 0u;
8161 if (false) {
8162   var_1 = 1u;
8163 }
8164 var_1 = 999u;
8165 return;
8166 )";
8167   ASSERT_EQ(expect, got);
8168 }
8169 
TEST_F(SpvParserCFGTest,EmitBody_If_NoThen_Else)8170 TEST_F(SpvParserCFGTest, EmitBody_If_NoThen_Else) {
8171   auto p = parser(test::Assemble(CommonTypes() + R"(
8172      %100 = OpFunction %void None %voidfn
8173 
8174      %10 = OpLabel
8175      OpStore %var %uint_0
8176      OpSelectionMerge %99 None
8177      OpBranchConditional %cond %99 %30
8178 
8179      %99 = OpLabel
8180      OpStore %var %999
8181      OpReturn
8182 
8183      %30 = OpLabel
8184      OpStore %var %uint_1
8185      OpBranch %99
8186 
8187      OpFunctionEnd
8188   )"));
8189   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8190   auto fe = p->function_emitter(100);
8191   EXPECT_TRUE(fe.EmitBody()) << p->error();
8192 
8193   auto ast_body = fe.ast_body();
8194   auto got = test::ToString(p->program(), ast_body);
8195   auto* expect = R"(var_1 = 0u;
8196 if (false) {
8197 } else {
8198   var_1 = 1u;
8199 }
8200 var_1 = 999u;
8201 return;
8202 )";
8203   ASSERT_EQ(expect, got);
8204 }
8205 
TEST_F(SpvParserCFGTest,EmitBody_If_Then_Else)8206 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Else) {
8207   auto p = parser(test::Assemble(CommonTypes() + R"(
8208      %100 = OpFunction %void None %voidfn
8209 
8210      %10 = OpLabel
8211      OpStore %var %uint_0
8212      OpSelectionMerge %99 None
8213      OpBranchConditional %cond %30 %40
8214 
8215      %99 = OpLabel
8216      OpStore %var %999
8217      OpReturn
8218 
8219      %30 = OpLabel
8220      OpStore %var %uint_1
8221      OpBranch %99
8222 
8223      %40 = OpLabel
8224      OpStore %var %uint_2
8225      OpBranch %99
8226 
8227      OpFunctionEnd
8228   )"));
8229   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8230   auto fe = p->function_emitter(100);
8231   EXPECT_TRUE(fe.EmitBody()) << p->error();
8232 
8233   auto ast_body = fe.ast_body();
8234   auto got = test::ToString(p->program(), ast_body);
8235   auto* expect = R"(var_1 = 0u;
8236 if (false) {
8237   var_1 = 1u;
8238 } else {
8239   var_1 = 2u;
8240 }
8241 var_1 = 999u;
8242 return;
8243 )";
8244   ASSERT_EQ(expect, got);
8245 }
8246 
TEST_F(SpvParserCFGTest,EmitBody_If_Then_Else_Premerge)8247 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Else_Premerge) {
8248   // TODO(dneto): This should get an extra if(true) around
8249   // the premerge code.
8250   // See https://bugs.chromium.org/p/tint/issues/detail?id=82
8251   auto p = parser(test::Assemble(CommonTypes() + R"(
8252      %100 = OpFunction %void None %voidfn
8253 
8254      %10 = OpLabel
8255      OpStore %var %uint_0
8256      OpSelectionMerge %99 None
8257      OpBranchConditional %cond %30 %40
8258 
8259      %80 = OpLabel ; premerge
8260      OpStore %var %uint_3
8261      OpBranch %99
8262 
8263      %99 = OpLabel
8264      OpStore %var %999
8265      OpReturn
8266 
8267      %30 = OpLabel
8268      OpStore %var %uint_1
8269      OpBranch %80
8270 
8271      %40 = OpLabel
8272      OpStore %var %uint_2
8273      OpBranch %80
8274 
8275      OpFunctionEnd
8276   )"));
8277   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8278   auto fe = p->function_emitter(100);
8279   EXPECT_TRUE(fe.EmitBody()) << p->error();
8280 
8281   auto ast_body = fe.ast_body();
8282   auto got = test::ToString(p->program(), ast_body);
8283   auto* expect = R"(var_1 = 0u;
8284 if (false) {
8285   var_1 = 1u;
8286 } else {
8287   var_1 = 2u;
8288 }
8289 if (true) {
8290   var_1 = 3u;
8291 }
8292 var_1 = 999u;
8293 return;
8294 )";
8295   ASSERT_EQ(expect, got);
8296 }
8297 
TEST_F(SpvParserCFGTest,EmitBody_If_Then_Premerge)8298 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Premerge) {
8299   // The premerge *is* the else.
8300   auto p = parser(test::Assemble(CommonTypes() + R"(
8301      %100 = OpFunction %void None %voidfn
8302 
8303      %10 = OpLabel
8304      OpStore %var %uint_0
8305      OpSelectionMerge %99 None
8306      OpBranchConditional %cond %30 %80
8307 
8308      %80 = OpLabel ; premerge
8309      OpStore %var %uint_3
8310      OpBranch %99
8311 
8312      %99 = OpLabel
8313      OpStore %var %999
8314      OpReturn
8315 
8316      %30 = OpLabel
8317      OpStore %var %uint_1
8318      OpBranch %80
8319 
8320      OpFunctionEnd
8321   )"));
8322   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8323   auto fe = p->function_emitter(100);
8324   EXPECT_TRUE(fe.EmitBody()) << p->error();
8325 
8326   auto ast_body = fe.ast_body();
8327   auto got = test::ToString(p->program(), ast_body);
8328   auto* expect = R"(var_1 = 0u;
8329 if (false) {
8330   var_1 = 1u;
8331 }
8332 if (true) {
8333   var_1 = 3u;
8334 }
8335 var_1 = 999u;
8336 return;
8337 )";
8338   ASSERT_EQ(expect, got);
8339 }
8340 
TEST_F(SpvParserCFGTest,EmitBody_If_Else_Premerge)8341 TEST_F(SpvParserCFGTest, EmitBody_If_Else_Premerge) {
8342   // The premerge *is* the then-clause.
8343   auto p = parser(test::Assemble(CommonTypes() + R"(
8344      %100 = OpFunction %void None %voidfn
8345 
8346      %10 = OpLabel
8347      OpStore %var %uint_0
8348      OpSelectionMerge %99 None
8349      OpBranchConditional %cond %80 %30
8350 
8351      %80 = OpLabel ; premerge
8352      OpStore %var %uint_3
8353      OpBranch %99
8354 
8355      %99 = OpLabel
8356      OpStore %var %999
8357      OpReturn
8358 
8359      %30 = OpLabel
8360      OpStore %var %uint_1
8361      OpBranch %80
8362 
8363      OpFunctionEnd
8364   )"));
8365   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8366   auto fe = p->function_emitter(100);
8367   EXPECT_TRUE(fe.EmitBody()) << p->error();
8368 
8369   auto ast_body = fe.ast_body();
8370   auto got = test::ToString(p->program(), ast_body);
8371   auto* expect = R"(var_1 = 0u;
8372 if (false) {
8373 } else {
8374   var_1 = 1u;
8375 }
8376 if (true) {
8377   var_1 = 3u;
8378 }
8379 var_1 = 999u;
8380 return;
8381 )";
8382   ASSERT_EQ(expect, got);
8383 }
8384 
TEST_F(SpvParserCFGTest,EmitBody_If_Nest_If)8385 TEST_F(SpvParserCFGTest, EmitBody_If_Nest_If) {
8386   auto p = parser(test::Assemble(CommonTypes() + R"(
8387      %100 = OpFunction %void None %voidfn
8388 
8389      %10 = OpLabel
8390      OpStore %var %uint_0
8391      OpSelectionMerge %99 None
8392      OpBranchConditional %cond %30 %40
8393 
8394      %30 = OpLabel ;; inner if #1
8395      OpStore %var %uint_1
8396      OpSelectionMerge %39 None
8397      OpBranchConditional %cond2 %33 %39
8398 
8399      %33 = OpLabel
8400      OpStore %var %uint_2
8401      OpBranch %39
8402 
8403      %39 = OpLabel ;; inner merge
8404      OpStore %var %uint_3
8405      OpBranch %99
8406 
8407      %40 = OpLabel ;; inner if #2
8408      OpStore %var %uint_4
8409      OpSelectionMerge %49 None
8410      OpBranchConditional %cond2 %49 %43
8411 
8412      %43 = OpLabel
8413      OpStore %var %uint_5
8414      OpBranch %49
8415 
8416      %49 = OpLabel ;; 2nd inner merge
8417      OpStore %var %uint_6
8418      OpBranch %99
8419 
8420      %99 = OpLabel
8421      OpStore %var %999
8422      OpReturn
8423 
8424      OpFunctionEnd
8425   )"));
8426   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8427   auto fe = p->function_emitter(100);
8428   EXPECT_TRUE(fe.EmitBody()) << p->error();
8429 
8430   auto ast_body = fe.ast_body();
8431   auto got = test::ToString(p->program(), ast_body);
8432   auto* expect = R"(var_1 = 0u;
8433 if (false) {
8434   var_1 = 1u;
8435   if (true) {
8436     var_1 = 2u;
8437   }
8438   var_1 = 3u;
8439 } else {
8440   var_1 = 4u;
8441   if (true) {
8442   } else {
8443     var_1 = 5u;
8444   }
8445   var_1 = 6u;
8446 }
8447 var_1 = 999u;
8448 return;
8449 )";
8450   ASSERT_EQ(expect, got);
8451 }
8452 
TEST_F(SpvParserCFGTest,EmitBody_Loop_SingleBlock_TrueBackedge)8453 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_TrueBackedge) {
8454   auto p = parser(test::Assemble(CommonTypes() + R"(
8455      %100 = OpFunction %void None %voidfn
8456 
8457      %10 = OpLabel
8458      OpStore %var %uint_0
8459      OpBranch %20
8460 
8461      %20 = OpLabel
8462      OpStore %var %uint_1
8463      OpLoopMerge %99 %20 None
8464      OpBranchConditional %cond %20 %99
8465 
8466      %99 = OpLabel
8467      OpStore %var %999
8468      OpReturn
8469 
8470      OpFunctionEnd
8471   )"));
8472   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8473   auto fe = p->function_emitter(100);
8474   EXPECT_TRUE(fe.EmitBody()) << p->error();
8475 
8476   auto ast_body = fe.ast_body();
8477   auto got = test::ToString(p->program(), ast_body);
8478   auto* expect = R"(var_1 = 0u;
8479 loop {
8480   var_1 = 1u;
8481   if (false) {
8482   } else {
8483     break;
8484   }
8485 }
8486 var_1 = 999u;
8487 return;
8488 )";
8489   ASSERT_EQ(expect, got);
8490 }
8491 
TEST_F(SpvParserCFGTest,EmitBody_Loop_SingleBlock_FalseBackedge)8492 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_FalseBackedge) {
8493   auto p = parser(test::Assemble(CommonTypes() + R"(
8494      %100 = OpFunction %void None %voidfn
8495 
8496      %10 = OpLabel
8497      OpStore %var %uint_0
8498      OpBranch %20
8499 
8500      %20 = OpLabel
8501      OpStore %var %uint_1
8502      OpLoopMerge %99 %20 None
8503      OpBranchConditional %cond %99 %20
8504 
8505      %99 = OpLabel
8506      OpStore %var %999
8507      OpReturn
8508 
8509      OpFunctionEnd
8510   )"));
8511   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8512   auto fe = p->function_emitter(100);
8513   EXPECT_TRUE(fe.EmitBody()) << p->error();
8514 
8515   auto ast_body = fe.ast_body();
8516   auto got = test::ToString(p->program(), ast_body);
8517   auto* expect = R"(var_1 = 0u;
8518 loop {
8519   var_1 = 1u;
8520   if (false) {
8521     break;
8522   }
8523 }
8524 var_1 = 999u;
8525 return;
8526 )";
8527   ASSERT_EQ(expect, got);
8528 }
8529 
TEST_F(SpvParserCFGTest,EmitBody_Loop_SingleBlock_BothBackedge)8530 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_BothBackedge) {
8531   auto p = parser(test::Assemble(CommonTypes() + R"(
8532      %100 = OpFunction %void None %voidfn
8533 
8534      %10 = OpLabel
8535      OpStore %var %uint_0
8536      OpBranch %20
8537 
8538      %20 = OpLabel
8539      OpStore %var %uint_1
8540      OpLoopMerge %99 %20 None
8541      OpBranchConditional %cond %20 %20
8542 
8543      %99 = OpLabel
8544      OpStore %var %999
8545      OpReturn
8546 
8547      OpFunctionEnd
8548   )"));
8549   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8550   auto fe = p->function_emitter(100);
8551   EXPECT_TRUE(fe.EmitBody()) << p->error();
8552 
8553   auto ast_body = fe.ast_body();
8554   auto got = test::ToString(p->program(), ast_body);
8555   auto* expect = R"(var_1 = 0u;
8556 loop {
8557   var_1 = 1u;
8558 }
8559 var_1 = 999u;
8560 return;
8561 )";
8562   ASSERT_EQ(expect, got);
8563 }
8564 
TEST_F(SpvParserCFGTest,EmitBody_Loop_SingleBlock_UnconditionalBackege)8565 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_UnconditionalBackege) {
8566   auto p = parser(test::Assemble(CommonTypes() + R"(
8567      %100 = OpFunction %void None %voidfn
8568 
8569      %10 = OpLabel
8570      OpStore %var %uint_0
8571      OpBranch %20
8572 
8573      %20 = OpLabel
8574      OpStore %var %uint_1
8575      OpLoopMerge %99 %20 None
8576      OpBranch %20
8577 
8578      %99 = OpLabel
8579      OpStore %var %999
8580      OpReturn
8581 
8582      OpFunctionEnd
8583   )"));
8584   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8585   auto fe = p->function_emitter(100);
8586   EXPECT_TRUE(fe.EmitBody()) << p->error();
8587 
8588   auto ast_body = fe.ast_body();
8589   auto got = test::ToString(p->program(), ast_body);
8590   auto* expect = R"(var_1 = 0u;
8591 loop {
8592   var_1 = 1u;
8593 }
8594 var_1 = 999u;
8595 return;
8596 )";
8597   ASSERT_EQ(expect, got);
8598 }
8599 
TEST_F(SpvParserCFGTest,EmitBody_Loop_Unconditional_Body_SingleBlockContinue)8600 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_SingleBlockContinue) {
8601   auto p = parser(test::Assemble(CommonTypes() + R"(
8602      %100 = OpFunction %void None %voidfn
8603 
8604      %10 = OpLabel
8605      OpStore %var %uint_0
8606      OpBranch %20
8607 
8608      %20 = OpLabel
8609      OpStore %var %uint_1
8610      OpLoopMerge %99 %50 None
8611      OpBranch %30
8612 
8613      %30 = OpLabel
8614      OpStore %var %uint_2
8615      OpBranch %50
8616 
8617      %50 = OpLabel
8618      OpStore %var %uint_3
8619      OpBranch %20
8620 
8621      %99 = OpLabel
8622      OpStore %var %999
8623      OpReturn
8624 
8625      OpFunctionEnd
8626   )"));
8627   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8628   auto fe = p->function_emitter(100);
8629   EXPECT_TRUE(fe.EmitBody()) << p->error();
8630 
8631   auto ast_body = fe.ast_body();
8632   auto got = test::ToString(p->program(), ast_body);
8633   auto* expect = R"(var_1 = 0u;
8634 loop {
8635   var_1 = 1u;
8636   var_1 = 2u;
8637 
8638   continuing {
8639     var_1 = 3u;
8640   }
8641 }
8642 var_1 = 999u;
8643 return;
8644 )";
8645   ASSERT_EQ(expect, got);
8646 }
8647 
TEST_F(SpvParserCFGTest,EmitBody_Loop_Unconditional_Body_MultiBlockContinue)8648 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_MultiBlockContinue) {
8649   auto p = parser(test::Assemble(CommonTypes() + R"(
8650      %100 = OpFunction %void None %voidfn
8651 
8652      %10 = OpLabel
8653      OpStore %var %uint_0
8654      OpBranch %20
8655 
8656      %20 = OpLabel
8657      OpStore %var %uint_1
8658      OpLoopMerge %99 %50 None
8659      OpBranch %30
8660 
8661      %30 = OpLabel
8662      OpStore %var %uint_2
8663      OpBranch %50
8664 
8665      %50 = OpLabel
8666      OpStore %var %uint_3
8667      OpBranch %60
8668 
8669      %60 = OpLabel
8670      OpStore %var %uint_4
8671      OpBranch %20
8672 
8673      %99 = OpLabel
8674      OpStore %var %999
8675      OpReturn
8676 
8677      OpFunctionEnd
8678   )"));
8679   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8680   auto fe = p->function_emitter(100);
8681   EXPECT_TRUE(fe.EmitBody()) << p->error();
8682 
8683   auto ast_body = fe.ast_body();
8684   auto got = test::ToString(p->program(), ast_body);
8685   auto* expect = R"(var_1 = 0u;
8686 loop {
8687   var_1 = 1u;
8688   var_1 = 2u;
8689 
8690   continuing {
8691     var_1 = 3u;
8692     var_1 = 4u;
8693   }
8694 }
8695 var_1 = 999u;
8696 return;
8697 )";
8698   ASSERT_EQ(expect, got);
8699 }
8700 
TEST_F(SpvParserCFGTest,EmitBody_Loop_Unconditional_Body_ContinueNestIf)8701 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_ContinueNestIf) {
8702   auto p = parser(test::Assemble(CommonTypes() + R"(
8703      %100 = OpFunction %void None %voidfn
8704 
8705      %10 = OpLabel
8706      OpStore %var %uint_0
8707      OpBranch %20
8708 
8709      %20 = OpLabel
8710      OpStore %var %uint_1
8711      OpLoopMerge %99 %50 None
8712      OpBranch %30
8713 
8714      %30 = OpLabel
8715      OpStore %var %uint_2
8716      OpBranch %50
8717 
8718      %50 = OpLabel ; continue target; also if-header
8719      OpStore %var %uint_3
8720      OpSelectionMerge %80 None
8721      OpBranchConditional %cond2 %60 %80
8722 
8723      %60 = OpLabel
8724      OpStore %var %uint_4
8725      OpBranch %80
8726 
8727      %80 = OpLabel
8728      OpStore %var %uint_5
8729      OpBranch %20
8730 
8731      %99 = OpLabel
8732      OpStore %var %999
8733      OpReturn
8734 
8735      OpFunctionEnd
8736   )"));
8737   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8738   auto fe = p->function_emitter(100);
8739   EXPECT_TRUE(fe.EmitBody()) << p->error();
8740 
8741   auto ast_body = fe.ast_body();
8742   auto got = test::ToString(p->program(), ast_body);
8743   auto* expect = R"(var_1 = 0u;
8744 loop {
8745   var_1 = 1u;
8746   var_1 = 2u;
8747 
8748   continuing {
8749     var_1 = 3u;
8750     if (true) {
8751       var_1 = 4u;
8752     }
8753     var_1 = 5u;
8754   }
8755 }
8756 var_1 = 999u;
8757 return;
8758 )";
8759   ASSERT_EQ(expect, got);
8760 }
8761 
TEST_F(SpvParserCFGTest,EmitBody_Loop_MultiBlockContinueIsEntireLoop)8762 TEST_F(SpvParserCFGTest, EmitBody_Loop_MultiBlockContinueIsEntireLoop) {
8763   // Test case where both branches exit. e.g both go to merge.
8764   auto p = parser(test::Assemble(CommonTypes() + R"(
8765      %100 = OpFunction %void None %voidfn
8766 
8767      %10 = OpLabel
8768      OpStore %var %uint_0
8769      OpBranch %20
8770 
8771      %20 = OpLabel ; its own continue target
8772      OpStore %var %uint_1
8773      OpLoopMerge %99 %20 None
8774      OpBranch %80
8775 
8776      %80 = OpLabel
8777      OpStore %var %uint_2
8778      OpBranchConditional %cond %99 %20
8779 
8780      %99 = OpLabel
8781      OpStore %var %uint_3
8782      OpReturn
8783 
8784      OpFunctionEnd
8785   )"));
8786   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8787   auto fe = p->function_emitter(100);
8788   EXPECT_TRUE(fe.EmitBody()) << p->error();
8789   auto ast_body = fe.ast_body();
8790   auto got = test::ToString(p->program(), ast_body);
8791   auto* expect = R"(var_1 = 0u;
8792 loop {
8793   var_1 = 1u;
8794   var_1 = 2u;
8795   if (false) {
8796     break;
8797   }
8798 }
8799 var_1 = 3u;
8800 return;
8801 )";
8802   ASSERT_EQ(expect, got);
8803 }
8804 
TEST_F(SpvParserCFGTest,EmitBody_Loop_Never)8805 TEST_F(SpvParserCFGTest, EmitBody_Loop_Never) {
8806   // Test case where both branches exit. e.g both go to merge.
8807   auto p = parser(test::Assemble(CommonTypes() + R"(
8808      %100 = OpFunction %void None %voidfn
8809 
8810      %10 = OpLabel
8811      OpBranch %20
8812 
8813      %20 = OpLabel
8814      OpStore %var %uint_1
8815      OpLoopMerge %99 %80 None
8816      OpBranchConditional %cond %99 %99
8817 
8818      %80 = OpLabel ; continue target
8819      OpStore %var %uint_2
8820      OpBranch %20
8821 
8822      %99 = OpLabel
8823      OpStore %var %uint_3
8824      OpReturn
8825 
8826      OpFunctionEnd
8827   )"));
8828   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8829   auto fe = p->function_emitter(100);
8830   EXPECT_TRUE(fe.EmitBody()) << p->error();
8831   auto ast_body = fe.ast_body();
8832   auto got = test::ToString(p->program(), ast_body);
8833   auto* expect = R"(loop {
8834   var_1 = 1u;
8835   break;
8836 
8837   continuing {
8838     var_1 = 2u;
8839   }
8840 }
8841 var_1 = 3u;
8842 return;
8843 )";
8844   ASSERT_EQ(expect, got);
8845 }
8846 
TEST_F(SpvParserCFGTest,EmitBody_Loop_HeaderBreakAndContinue)8847 TEST_F(SpvParserCFGTest, EmitBody_Loop_HeaderBreakAndContinue) {
8848   // Header block branches to merge, and to an outer continue.
8849   // This is disallowed by the rule:
8850   //    "a continue block is valid only for the innermost loop it is nested
8851   //    inside of"
8852   // See test ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError
8853 }
8854 
TEST_F(SpvParserCFGTest,EmitBody_Loop_TrueToBody_FalseBreaks)8855 TEST_F(SpvParserCFGTest, EmitBody_Loop_TrueToBody_FalseBreaks) {
8856   auto p = parser(test::Assemble(CommonTypes() + R"(
8857      %100 = OpFunction %void None %voidfn
8858 
8859      %10 = OpLabel
8860      OpBranch %20
8861 
8862      %20 = OpLabel
8863      OpStore %var %uint_1
8864      OpLoopMerge %99 %80 None
8865      OpBranchConditional %cond %30 %99
8866 
8867      %30 = OpLabel
8868      OpStore %var %uint_2
8869      OpBranch %80
8870 
8871      %80 = OpLabel ; continue target
8872      OpStore %var %uint_3
8873      OpBranch %20
8874 
8875      %99 = OpLabel
8876      OpStore %var %uint_4
8877      OpReturn
8878 
8879      OpFunctionEnd
8880   )"));
8881   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8882   auto fe = p->function_emitter(100);
8883   EXPECT_TRUE(fe.EmitBody()) << p->error();
8884   auto ast_body = fe.ast_body();
8885   auto got = test::ToString(p->program(), ast_body);
8886   auto* expect = R"(loop {
8887   var_1 = 1u;
8888   if (false) {
8889   } else {
8890     break;
8891   }
8892   var_1 = 2u;
8893 
8894   continuing {
8895     var_1 = 3u;
8896   }
8897 }
8898 var_1 = 4u;
8899 return;
8900 )";
8901   ASSERT_EQ(expect, got);
8902 }
8903 
TEST_F(SpvParserCFGTest,EmitBody_Loop_FalseToBody_TrueBreaks)8904 TEST_F(SpvParserCFGTest, EmitBody_Loop_FalseToBody_TrueBreaks) {
8905   auto p = parser(test::Assemble(CommonTypes() + R"(
8906      %100 = OpFunction %void None %voidfn
8907 
8908      %10 = OpLabel
8909      OpBranch %20
8910 
8911      %20 = OpLabel
8912      OpStore %var %uint_1
8913      OpLoopMerge %99 %80 None
8914      OpBranchConditional %cond %30 %99
8915 
8916      %30 = OpLabel
8917      OpStore %var %uint_2
8918      OpBranch %80
8919 
8920      %80 = OpLabel ; continue target
8921      OpStore %var %uint_3
8922      OpBranch %20
8923 
8924      %99 = OpLabel
8925      OpStore %var %uint_4
8926      OpReturn
8927 
8928      OpFunctionEnd
8929   )"));
8930   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8931   auto fe = p->function_emitter(100);
8932   EXPECT_TRUE(fe.EmitBody()) << p->error();
8933   auto ast_body = fe.ast_body();
8934   auto got = test::ToString(p->program(), ast_body);
8935   auto* expect = R"(loop {
8936   var_1 = 1u;
8937   if (false) {
8938   } else {
8939     break;
8940   }
8941   var_1 = 2u;
8942 
8943   continuing {
8944     var_1 = 3u;
8945   }
8946 }
8947 var_1 = 4u;
8948 return;
8949 )";
8950   ASSERT_EQ(expect, got);
8951 }
8952 
TEST_F(SpvParserCFGTest,EmitBody_Loop_NestedIfContinue)8953 TEST_F(SpvParserCFGTest, EmitBody_Loop_NestedIfContinue) {
8954   // By construction, it has to come from nested code.
8955   auto p = parser(test::Assemble(CommonTypes() + R"(
8956      %100 = OpFunction %void None %voidfn
8957 
8958      %10 = OpLabel
8959      OpBranch %20
8960 
8961      %20 = OpLabel
8962      OpLoopMerge %99 %80 None
8963      OpBranch %30
8964 
8965      %30 = OpLabel
8966      OpSelectionMerge %50 None
8967      OpBranchConditional %cond %40 %50
8968 
8969      %40 = OpLabel
8970      OpStore %var %uint_1
8971      OpBranch %80 ; continue edge
8972 
8973      %50 = OpLabel ; inner selection merge
8974      OpStore %var %uint_2
8975      OpBranch %80
8976 
8977      %80 = OpLabel ; continue target
8978      OpStore %var %uint_3
8979      OpBranch %20
8980 
8981      %99 = OpLabel
8982      OpReturn
8983 
8984      OpFunctionEnd
8985   )"));
8986   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
8987   auto fe = p->function_emitter(100);
8988   EXPECT_TRUE(fe.EmitBody()) << p->error();
8989   auto ast_body = fe.ast_body();
8990   auto got = test::ToString(p->program(), ast_body);
8991   auto* expect = R"(loop {
8992   if (false) {
8993     var_1 = 1u;
8994     continue;
8995   }
8996   var_1 = 2u;
8997 
8998   continuing {
8999     var_1 = 3u;
9000   }
9001 }
9002 return;
9003 )";
9004   ASSERT_EQ(expect, got);
9005 }
9006 
TEST_F(SpvParserCFGTest,EmitBody_Loop_BodyAlwaysBreaks)9007 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyAlwaysBreaks) {
9008   auto p = parser(test::Assemble(CommonTypes() + R"(
9009      %100 = OpFunction %void None %voidfn
9010 
9011      %10 = OpLabel
9012      OpBranch %20
9013 
9014      %20 = OpLabel
9015      OpLoopMerge %99 %80 None
9016      OpBranch %30
9017 
9018      %30 = OpLabel
9019      OpStore %var %uint_1
9020      OpBranch %99 ; break is here
9021 
9022      %80 = OpLabel
9023      OpStore %var %uint_2
9024      OpBranch %20 ; backedge
9025 
9026      %99 = OpLabel
9027      OpReturn
9028 
9029      OpFunctionEnd
9030   )"));
9031   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9032   auto fe = p->function_emitter(100);
9033   EXPECT_TRUE(fe.EmitBody()) << p->error();
9034 
9035   auto ast_body = fe.ast_body();
9036   auto got = test::ToString(p->program(), ast_body);
9037   auto* expect = R"(loop {
9038   var_1 = 1u;
9039   break;
9040 
9041   continuing {
9042     var_1 = 2u;
9043   }
9044 }
9045 return;
9046 )";
9047   ASSERT_EQ(expect, got);
9048 }
9049 
TEST_F(SpvParserCFGTest,EmitBody_Loop_BodyConditionallyBreaks_FromTrue)9050 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromTrue) {
9051   // The else-branch has a continue but it's skipped because it's from a
9052   // block that immediately precedes the continue construct.
9053   auto p = parser(test::Assemble(CommonTypes() + R"(
9054      %100 = OpFunction %void None %voidfn
9055 
9056      %10 = OpLabel
9057      OpBranch %20
9058 
9059      %20 = OpLabel
9060      OpLoopMerge %99 %80 None
9061      OpBranch %30
9062 
9063      %30 = OpLabel
9064      OpStore %var %uint_1
9065      OpBranchConditional %cond %99 %80
9066 
9067      %80 = OpLabel
9068      OpStore %var %uint_2
9069      OpBranch %20 ; backedge
9070 
9071      %99 = OpLabel
9072      OpReturn
9073 
9074      OpFunctionEnd
9075   )"));
9076   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9077   auto fe = p->function_emitter(100);
9078   EXPECT_TRUE(fe.EmitBody()) << p->error();
9079 
9080   auto ast_body = fe.ast_body();
9081   auto got = test::ToString(p->program(), ast_body);
9082   auto* expect = R"(loop {
9083   var_1 = 1u;
9084   if (false) {
9085     break;
9086   }
9087 
9088   continuing {
9089     var_1 = 2u;
9090   }
9091 }
9092 return;
9093 )";
9094   ASSERT_EQ(expect, got);
9095 }
9096 
TEST_F(SpvParserCFGTest,EmitBody_Loop_BodyConditionallyBreaks_FromFalse)9097 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromFalse) {
9098   // The else-branch has a continue but it's skipped because it's from a
9099   // block that immediately precedes the continue construct.
9100   auto p = parser(test::Assemble(CommonTypes() + R"(
9101      %100 = OpFunction %void None %voidfn
9102 
9103      %10 = OpLabel
9104      OpBranch %20
9105 
9106      %20 = OpLabel
9107      OpLoopMerge %99 %80 None
9108      OpBranch %30
9109 
9110      %30 = OpLabel
9111      OpStore %var %uint_1
9112      OpBranchConditional %cond %80 %99
9113 
9114      %80 = OpLabel
9115      OpStore %var %uint_2
9116      OpBranch %20 ; backedge
9117 
9118      %99 = OpLabel
9119      OpReturn
9120 
9121      OpFunctionEnd
9122   )"));
9123   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9124   auto fe = p->function_emitter(100);
9125   EXPECT_TRUE(fe.EmitBody()) << p->error();
9126 
9127   auto ast_body = fe.ast_body();
9128   auto got = test::ToString(p->program(), ast_body);
9129   auto* expect = R"(loop {
9130   var_1 = 1u;
9131   if (false) {
9132   } else {
9133     break;
9134   }
9135 
9136   continuing {
9137     var_1 = 2u;
9138   }
9139 }
9140 return;
9141 )";
9142   ASSERT_EQ(expect, got);
9143 }
9144 
TEST_F(SpvParserCFGTest,EmitBody_Loop_BodyConditionallyBreaks_FromTrue_Early)9145 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromTrue_Early) {
9146   auto p = parser(test::Assemble(CommonTypes() + R"(
9147      %100 = OpFunction %void None %voidfn
9148 
9149      %10 = OpLabel
9150      OpBranch %20
9151 
9152      %20 = OpLabel
9153      OpLoopMerge %99 %80 None
9154      OpBranch %30
9155 
9156      %30 = OpLabel
9157      OpStore %var %uint_1
9158      OpBranchConditional %cond %99 %70
9159 
9160      %70 = OpLabel
9161      OpStore %var %uint_3
9162      OpBranch %80
9163 
9164      %80 = OpLabel
9165      OpStore %var %uint_2
9166      OpBranch %20 ; backedge
9167 
9168      %99 = OpLabel
9169      OpReturn
9170 
9171      OpFunctionEnd
9172   )"));
9173   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9174   auto fe = p->function_emitter(100);
9175   EXPECT_TRUE(fe.EmitBody()) << p->error();
9176 
9177   auto ast_body = fe.ast_body();
9178   auto got = test::ToString(p->program(), ast_body);
9179   auto* expect = R"(loop {
9180   var_1 = 1u;
9181   if (false) {
9182     break;
9183   }
9184   var_1 = 3u;
9185 
9186   continuing {
9187     var_1 = 2u;
9188   }
9189 }
9190 return;
9191 )";
9192   ASSERT_EQ(expect, got);
9193 }
9194 
TEST_F(SpvParserCFGTest,EmitBody_Loop_BodyConditionallyBreaks_FromFalse_Early)9195 TEST_F(SpvParserCFGTest,
9196        EmitBody_Loop_BodyConditionallyBreaks_FromFalse_Early) {
9197   auto p = parser(test::Assemble(CommonTypes() + R"(
9198      %100 = OpFunction %void None %voidfn
9199 
9200      %10 = OpLabel
9201      OpBranch %20
9202 
9203      %20 = OpLabel
9204      OpLoopMerge %99 %80 None
9205      OpBranch %30
9206 
9207      %30 = OpLabel
9208      OpStore %var %uint_1
9209      OpBranchConditional %cond %70 %99
9210 
9211      %70 = OpLabel
9212      OpStore %var %uint_3
9213      OpBranch %80
9214 
9215      %80 = OpLabel
9216      OpStore %var %uint_2
9217      OpBranch %20 ; backedge
9218 
9219      %99 = OpLabel
9220      OpReturn
9221 
9222      OpFunctionEnd
9223   )"));
9224   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9225   auto fe = p->function_emitter(100);
9226   EXPECT_TRUE(fe.EmitBody()) << p->error();
9227 
9228   auto ast_body = fe.ast_body();
9229   auto got = test::ToString(p->program(), ast_body);
9230   auto* expect = R"(loop {
9231   var_1 = 1u;
9232   if (false) {
9233   } else {
9234     break;
9235   }
9236   var_1 = 3u;
9237 
9238   continuing {
9239     var_1 = 2u;
9240   }
9241 }
9242 return;
9243 )";
9244   ASSERT_EQ(expect, got);
9245 }
9246 
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsMerge_NoCases)9247 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_NoCases) {
9248   auto p = parser(test::Assemble(CommonTypes() + R"(
9249      %100 = OpFunction %void None %voidfn
9250 
9251      %10 = OpLabel
9252      OpStore %var %uint_1
9253      OpSelectionMerge %99 None
9254      OpSwitch %selector %99
9255 
9256      %99 = OpLabel
9257      OpStore %var %uint_7
9258      OpReturn
9259 
9260      OpFunctionEnd
9261   )"));
9262   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9263   auto fe = p->function_emitter(100);
9264   EXPECT_TRUE(fe.EmitBody()) << p->error();
9265 
9266   auto ast_body = fe.ast_body();
9267   auto got = test::ToString(p->program(), ast_body);
9268   auto* expect = R"(var_1 = 1u;
9269 switch(42u) {
9270   default: {
9271   }
9272 }
9273 var_1 = 7u;
9274 return;
9275 )";
9276   ASSERT_EQ(expect, got);
9277 }
9278 
9279 // First do no special control flow: no fallthroughs, breaks, continues.
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsMerge_OneCase)9280 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_OneCase) {
9281   auto p = parser(test::Assemble(CommonTypes() + R"(
9282      %100 = OpFunction %void None %voidfn
9283 
9284      %10 = OpLabel
9285      OpStore %var %uint_1
9286      OpSelectionMerge %99 None
9287      OpSwitch %selector %99 20 %20
9288 
9289      %20 = OpLabel
9290      OpStore %var %uint_20
9291      OpBranch %99
9292 
9293      %99 = OpLabel
9294      OpStore %var %uint_7
9295      OpReturn
9296 
9297      OpFunctionEnd
9298   )"));
9299   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9300   auto fe = p->function_emitter(100);
9301   EXPECT_TRUE(fe.EmitBody()) << p->error();
9302 
9303   auto ast_body = fe.ast_body();
9304   auto got = test::ToString(p->program(), ast_body);
9305   auto* expect = R"(var_1 = 1u;
9306 switch(42u) {
9307   case 20u: {
9308     var_1 = 20u;
9309   }
9310   default: {
9311   }
9312 }
9313 var_1 = 7u;
9314 return;
9315 )";
9316   ASSERT_EQ(expect, got);
9317 }
9318 
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsMerge_TwoCases)9319 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_TwoCases) {
9320   auto p = parser(test::Assemble(CommonTypes() + R"(
9321      %100 = OpFunction %void None %voidfn
9322 
9323      %10 = OpLabel
9324      OpStore %var %uint_1
9325      OpSelectionMerge %99 None
9326      OpSwitch %selector %99 20 %20 30 %30
9327 
9328      %20 = OpLabel
9329      OpStore %var %uint_20
9330      OpBranch %99
9331 
9332      %30 = OpLabel
9333      OpStore %var %uint_30
9334      OpBranch %99
9335 
9336      %99 = OpLabel
9337      OpStore %var %uint_7
9338      OpReturn
9339 
9340      OpFunctionEnd
9341   )"));
9342   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9343   auto fe = p->function_emitter(100);
9344   EXPECT_TRUE(fe.EmitBody()) << p->error();
9345 
9346   auto ast_body = fe.ast_body();
9347   auto got = test::ToString(p->program(), ast_body);
9348   auto* expect = R"(var_1 = 1u;
9349 switch(42u) {
9350   case 30u: {
9351     var_1 = 30u;
9352   }
9353   case 20u: {
9354     var_1 = 20u;
9355   }
9356   default: {
9357   }
9358 }
9359 var_1 = 7u;
9360 return;
9361 )";
9362   ASSERT_EQ(expect, got);
9363 }
9364 
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsMerge_CasesWithDup)9365 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_CasesWithDup) {
9366   auto p = parser(test::Assemble(CommonTypes() + R"(
9367      %100 = OpFunction %void None %voidfn
9368 
9369      %10 = OpLabel
9370      OpStore %var %uint_1
9371      OpSelectionMerge %99 None
9372      OpSwitch %selector %99 20 %20 30 %30 40 %20
9373 
9374      %20 = OpLabel
9375      OpStore %var %uint_20
9376      OpBranch %99
9377 
9378      %30 = OpLabel
9379      OpStore %var %uint_30
9380      OpBranch %99
9381 
9382      %99 = OpLabel
9383      OpStore %var %uint_7
9384      OpReturn
9385 
9386      OpFunctionEnd
9387   )"));
9388   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9389   auto fe = p->function_emitter(100);
9390   EXPECT_TRUE(fe.EmitBody()) << p->error();
9391 
9392   auto ast_body = fe.ast_body();
9393   auto got = test::ToString(p->program(), ast_body);
9394   auto* expect = R"(var_1 = 1u;
9395 switch(42u) {
9396   case 30u: {
9397     var_1 = 30u;
9398   }
9399   case 20u, 40u: {
9400     var_1 = 20u;
9401   }
9402   default: {
9403   }
9404 }
9405 var_1 = 7u;
9406 return;
9407 )";
9408   ASSERT_EQ(expect, got);
9409 }
9410 
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsCase_NoDupCases)9411 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsCase_NoDupCases) {
9412   // The default block is not the merge block. But not the same as a case
9413   // either.
9414   auto p = parser(test::Assemble(CommonTypes() + R"(
9415      %100 = OpFunction %void None %voidfn
9416 
9417      %10 = OpLabel
9418      OpStore %var %uint_1
9419      OpSelectionMerge %99 None
9420      OpSwitch %selector %30 20 %20 40 %40
9421 
9422      %20 = OpLabel
9423      OpStore %var %uint_20
9424      OpBranch %99
9425 
9426      %30 = OpLabel ; the named default block
9427      OpStore %var %uint_30
9428      OpBranch %99
9429 
9430      %40 = OpLabel
9431      OpStore %var %uint_40
9432      OpBranch %99
9433 
9434      %99 = OpLabel
9435      OpStore %var %uint_7
9436      OpReturn
9437 
9438      OpFunctionEnd
9439   )"));
9440   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9441   auto fe = p->function_emitter(100);
9442   EXPECT_TRUE(fe.EmitBody()) << p->error();
9443 
9444   auto ast_body = fe.ast_body();
9445   auto got = test::ToString(p->program(), ast_body);
9446   auto* expect = R"(var_1 = 1u;
9447 switch(42u) {
9448   case 40u: {
9449     var_1 = 40u;
9450   }
9451   case 20u: {
9452     var_1 = 20u;
9453   }
9454   default: {
9455     var_1 = 30u;
9456   }
9457 }
9458 var_1 = 7u;
9459 return;
9460 )";
9461   ASSERT_EQ(expect, got);
9462 }
9463 
TEST_F(SpvParserCFGTest,EmitBody_Switch_DefaultIsCase_WithDupCase)9464 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsCase_WithDupCase) {
9465   // The default block is not the merge block and is the same as a case.
9466   // We emit the default case separately, but just before the labeled
9467   // case, and with a fallthrough.
9468   auto p = parser(test::Assemble(CommonTypes() + R"(
9469      %100 = OpFunction %void None %voidfn
9470 
9471      %10 = OpLabel
9472      OpStore %var %uint_1
9473      OpSelectionMerge %99 None
9474      OpSwitch %selector %30 20 %20 30 %30 40 %40
9475 
9476      %20 = OpLabel
9477      OpStore %var %uint_20
9478      OpBranch %99
9479 
9480      %30 = OpLabel ; the named default block, also a case
9481      OpStore %var %uint_30
9482      OpBranch %99
9483 
9484      %40 = OpLabel
9485      OpStore %var %uint_40
9486      OpBranch %99
9487 
9488      %99 = OpLabel
9489      OpStore %var %uint_7
9490      OpReturn
9491 
9492      OpFunctionEnd
9493   )"));
9494   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9495   auto fe = p->function_emitter(100);
9496   EXPECT_TRUE(fe.EmitBody()) << p->error();
9497 
9498   auto ast_body = fe.ast_body();
9499   auto got = test::ToString(p->program(), ast_body);
9500   auto* expect = R"(var_1 = 1u;
9501 switch(42u) {
9502   case 40u: {
9503     var_1 = 40u;
9504   }
9505   case 20u: {
9506     var_1 = 20u;
9507   }
9508   default: {
9509     fallthrough;
9510   }
9511   case 30u: {
9512     var_1 = 30u;
9513   }
9514 }
9515 var_1 = 7u;
9516 return;
9517 )";
9518   ASSERT_EQ(expect, got);
9519 }
9520 
TEST_F(SpvParserCFGTest,EmitBody_Switch_Case_SintValue)9521 TEST_F(SpvParserCFGTest, EmitBody_Switch_Case_SintValue) {
9522   auto p = parser(test::Assemble(CommonTypes() + R"(
9523      %100 = OpFunction %void None %voidfn
9524 
9525      %10 = OpLabel
9526      OpStore %var %uint_1
9527      OpSelectionMerge %99 None
9528      ; SPIR-V assembler doesn't support negative literals in switch
9529      OpSwitch %signed_selector %99 20 %20 2000000000 %30 !4000000000 %40
9530 
9531      %20 = OpLabel
9532      OpStore %var %uint_20
9533      OpBranch %99
9534 
9535      %30 = OpLabel
9536      OpStore %var %uint_30
9537      OpBranch %99
9538 
9539      %40 = OpLabel
9540      OpStore %var %uint_40
9541      OpBranch %99
9542 
9543      %99 = OpLabel
9544      OpStore %var %uint_7
9545      OpReturn
9546 
9547      OpFunctionEnd
9548   )"));
9549   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9550   auto fe = p->function_emitter(100);
9551   EXPECT_TRUE(fe.EmitBody()) << p->error();
9552 
9553   auto ast_body = fe.ast_body();
9554   auto got = test::ToString(p->program(), ast_body);
9555   auto* expect = R"(var_1 = 1u;
9556 switch(42) {
9557   case -294967296: {
9558     var_1 = 40u;
9559   }
9560   case 2000000000: {
9561     var_1 = 30u;
9562   }
9563   case 20: {
9564     var_1 = 20u;
9565   }
9566   default: {
9567   }
9568 }
9569 var_1 = 7u;
9570 return;
9571 )";
9572   ASSERT_EQ(expect, got);
9573 }
9574 
TEST_F(SpvParserCFGTest,EmitBody_Switch_Case_UintValue)9575 TEST_F(SpvParserCFGTest, EmitBody_Switch_Case_UintValue) {
9576   auto p = parser(test::Assemble(CommonTypes() + R"(
9577      %100 = OpFunction %void None %voidfn
9578 
9579      %10 = OpLabel
9580      OpStore %var %uint_1
9581      OpSelectionMerge %99 None
9582      OpSwitch %selector %99 20 %20 2000000000 %30 50 %40
9583 
9584      %20 = OpLabel
9585      OpStore %var %uint_20
9586      OpBranch %99
9587 
9588      %30 = OpLabel
9589      OpStore %var %uint_30
9590      OpBranch %99
9591 
9592      %40 = OpLabel
9593      OpStore %var %uint_40
9594      OpBranch %99
9595 
9596      %99 = OpLabel
9597      OpStore %var %uint_7
9598      OpReturn
9599 
9600      OpFunctionEnd
9601   )"));
9602   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9603   auto fe = p->function_emitter(100);
9604   EXPECT_TRUE(fe.EmitBody()) << p->error();
9605 
9606   auto ast_body = fe.ast_body();
9607   auto got = test::ToString(p->program(), ast_body);
9608   auto* expect = R"(var_1 = 1u;
9609 switch(42u) {
9610   case 50u: {
9611     var_1 = 40u;
9612   }
9613   case 2000000000u: {
9614     var_1 = 30u;
9615   }
9616   case 20u: {
9617     var_1 = 20u;
9618   }
9619   default: {
9620   }
9621 }
9622 var_1 = 7u;
9623 return;
9624 )";
9625   ASSERT_EQ(expect, got);
9626 }
9627 
TEST_F(SpvParserCFGTest,EmitBody_Return_TopLevel)9628 TEST_F(SpvParserCFGTest, EmitBody_Return_TopLevel) {
9629   auto p = parser(test::Assemble(CommonTypes() + R"(
9630      %100 = OpFunction %void None %voidfn
9631 
9632      %10 = OpLabel
9633      OpReturn
9634 
9635      OpFunctionEnd
9636   )"));
9637   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9638   auto fe = p->function_emitter(100);
9639   EXPECT_TRUE(fe.EmitBody()) << p->error();
9640 
9641   auto ast_body = fe.ast_body();
9642   auto got = test::ToString(p->program(), ast_body);
9643   auto* expect = R"(return;
9644 )";
9645   ASSERT_EQ(expect, got);
9646 }
9647 
TEST_F(SpvParserCFGTest,EmitBody_Return_InsideIf)9648 TEST_F(SpvParserCFGTest, EmitBody_Return_InsideIf) {
9649   auto p = parser(test::Assemble(CommonTypes() + R"(
9650      %100 = OpFunction %void None %voidfn
9651 
9652      %10 = OpLabel
9653      OpSelectionMerge %99 None
9654      OpBranchConditional %cond %20 %99
9655 
9656      %20 = OpLabel
9657      OpReturn
9658 
9659      %99 = OpLabel
9660      OpReturn
9661 
9662      OpFunctionEnd
9663   )"));
9664   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9665   auto fe = p->function_emitter(100);
9666   EXPECT_TRUE(fe.EmitBody()) << p->error();
9667 
9668   auto ast_body = fe.ast_body();
9669   auto got = test::ToString(p->program(), ast_body);
9670   auto* expect = R"(if (false) {
9671   return;
9672 }
9673 return;
9674 )";
9675   ASSERT_EQ(expect, got);
9676 }
9677 
TEST_F(SpvParserCFGTest,EmitBody_Return_InsideLoop)9678 TEST_F(SpvParserCFGTest, EmitBody_Return_InsideLoop) {
9679   auto p = parser(test::Assemble(CommonTypes() + R"(
9680      %100 = OpFunction %void None %voidfn
9681 
9682      %10 = OpLabel
9683      OpBranch %20
9684 
9685      %20 = OpLabel
9686      OpLoopMerge %99 %80 None
9687      OpBranchConditional %cond %30 %30
9688 
9689      %30 = OpLabel
9690      OpReturn
9691 
9692      %80 = OpLabel
9693      OpBranch %20
9694 
9695      %99 = OpLabel
9696      OpReturn
9697 
9698      OpFunctionEnd
9699   )"));
9700   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9701   auto fe = p->function_emitter(100);
9702   EXPECT_TRUE(fe.EmitBody()) << p->error();
9703 
9704   auto ast_body = fe.ast_body();
9705   auto got = test::ToString(p->program(), ast_body);
9706   auto* expect = R"(loop {
9707   return;
9708 }
9709 return;
9710 )";
9711   ASSERT_EQ(expect, got);
9712 }
9713 
TEST_F(SpvParserCFGTest,EmitBody_ReturnValue_TopLevel)9714 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_TopLevel) {
9715   auto p = parser(test::Assemble(CommonTypes() + R"(
9716      %200 = OpFunction %uint None %uintfn
9717 
9718      %210 = OpLabel
9719      OpReturnValue %uint_2
9720 
9721      OpFunctionEnd
9722 
9723      %100 = OpFunction %void None %voidfn
9724 
9725      %10 = OpLabel
9726      %11 = OpFunctionCall %uint %200
9727      OpReturn
9728 
9729      OpFunctionEnd
9730   )"));
9731   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9732   auto fe = p->function_emitter(200);
9733   EXPECT_TRUE(fe.EmitBody()) << p->error();
9734 
9735   auto ast_body = fe.ast_body();
9736   auto got = test::ToString(p->program(), ast_body);
9737   auto* expect = R"(return 2u;
9738 )";
9739   ASSERT_EQ(expect, got);
9740 }
9741 
TEST_F(SpvParserCFGTest,EmitBody_ReturnValue_InsideIf)9742 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_InsideIf) {
9743   auto p = parser(test::Assemble(CommonTypes() + R"(
9744      %200 = OpFunction %uint None %uintfn
9745 
9746      %210 = OpLabel
9747      OpSelectionMerge %299 None
9748      OpBranchConditional %cond %220 %299
9749 
9750      %220 = OpLabel
9751      OpReturnValue %uint_2
9752 
9753      %299 = OpLabel
9754      OpReturnValue %uint_3
9755 
9756      OpFunctionEnd
9757 
9758 
9759      %100 = OpFunction %void None %voidfn
9760 
9761      %10 = OpLabel
9762      %11 = OpFunctionCall %uint %200
9763      OpReturn
9764 
9765      OpFunctionEnd
9766   )"));
9767   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9768   auto fe = p->function_emitter(200);
9769   EXPECT_TRUE(fe.EmitBody()) << p->error();
9770 
9771   auto ast_body = fe.ast_body();
9772   auto got = test::ToString(p->program(), ast_body);
9773   auto* expect = R"(if (false) {
9774   return 2u;
9775 }
9776 return 3u;
9777 )";
9778   ASSERT_EQ(expect, got);
9779 }
9780 
TEST_F(SpvParserCFGTest,EmitBody_ReturnValue_Loop)9781 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_Loop) {
9782   auto p = parser(test::Assemble(CommonTypes() + R"(
9783      %200 = OpFunction %uint None %uintfn
9784 
9785      %210 = OpLabel
9786      OpBranch %220
9787 
9788      %220 = OpLabel
9789      OpLoopMerge %299 %280 None
9790      OpBranchConditional %cond %230 %230
9791 
9792      %230 = OpLabel
9793      OpReturnValue %uint_2
9794 
9795      %280 = OpLabel
9796      OpBranch %220
9797 
9798      %299 = OpLabel
9799      OpReturnValue %uint_3
9800 
9801      OpFunctionEnd
9802 
9803 
9804      %100 = OpFunction %void None %voidfn
9805 
9806      %10 = OpLabel
9807      %11 = OpFunctionCall %uint %200
9808      OpReturn
9809 
9810      OpFunctionEnd
9811   )"));
9812   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9813   auto fe = p->function_emitter(200);
9814   EXPECT_TRUE(fe.EmitBody()) << p->error();
9815 
9816   auto ast_body = fe.ast_body();
9817   auto got = test::ToString(p->program(), ast_body);
9818   auto* expect = R"(loop {
9819   return 2u;
9820 }
9821 return 3u;
9822 )";
9823   ASSERT_EQ(expect, got);
9824 }
9825 
TEST_F(SpvParserCFGTest,EmitBody_Kill_TopLevel)9826 TEST_F(SpvParserCFGTest, EmitBody_Kill_TopLevel) {
9827   auto p = parser(test::Assemble(CommonTypes() + R"(
9828      %100 = OpFunction %void None %voidfn
9829 
9830      %10 = OpLabel
9831      OpKill
9832 
9833      OpFunctionEnd
9834   )"));
9835   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9836   auto fe = p->function_emitter(100);
9837   EXPECT_TRUE(fe.EmitBody()) << p->error();
9838 
9839   auto ast_body = fe.ast_body();
9840   auto got = test::ToString(p->program(), ast_body);
9841   auto* expect = R"(discard;
9842 )";
9843   ASSERT_EQ(expect, got);
9844 }
9845 
TEST_F(SpvParserCFGTest,EmitBody_Kill_InsideIf)9846 TEST_F(SpvParserCFGTest, EmitBody_Kill_InsideIf) {
9847   auto p = parser(test::Assemble(CommonTypes() + R"(
9848      %100 = OpFunction %void None %voidfn
9849 
9850      %10 = OpLabel
9851      OpSelectionMerge %99 None
9852      OpBranchConditional %cond %20 %99
9853 
9854      %20 = OpLabel
9855      OpKill
9856 
9857      %99 = OpLabel
9858      OpKill
9859 
9860      OpFunctionEnd
9861   )"));
9862   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9863   auto fe = p->function_emitter(100);
9864   EXPECT_TRUE(fe.EmitBody()) << p->error();
9865 
9866   auto ast_body = fe.ast_body();
9867   auto got = test::ToString(p->program(), ast_body);
9868   auto* expect = R"(if (false) {
9869   discard;
9870 }
9871 discard;
9872 )";
9873   ASSERT_EQ(expect, got);
9874 }
9875 
TEST_F(SpvParserCFGTest,EmitBody_Kill_InsideLoop)9876 TEST_F(SpvParserCFGTest, EmitBody_Kill_InsideLoop) {
9877   auto p = parser(test::Assemble(CommonTypes() + R"(
9878      %100 = OpFunction %void None %voidfn
9879 
9880      %10 = OpLabel
9881      OpBranch %20
9882 
9883      %20 = OpLabel
9884      OpLoopMerge %99 %80 None
9885      OpBranchConditional %cond %30 %30
9886 
9887      %30 = OpLabel
9888      OpKill
9889 
9890      %80 = OpLabel
9891      OpBranch %20
9892 
9893      %99 = OpLabel
9894      OpKill
9895 
9896      OpFunctionEnd
9897   )"));
9898   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9899   auto fe = p->function_emitter(100);
9900   EXPECT_TRUE(fe.EmitBody()) << p->error();
9901 
9902   auto ast_body = fe.ast_body();
9903   auto got = test::ToString(p->program(), ast_body);
9904   auto* expect = R"(loop {
9905   discard;
9906 }
9907 discard;
9908 )";
9909   ASSERT_EQ(expect, got);
9910 }
9911 
TEST_F(SpvParserCFGTest,EmitBody_Unreachable_TopLevel)9912 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_TopLevel) {
9913   auto p = parser(test::Assemble(CommonTypes() + R"(
9914      %100 = OpFunction %void None %voidfn
9915 
9916      %10 = OpLabel
9917      OpUnreachable
9918 
9919      OpFunctionEnd
9920   )"));
9921   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9922   auto fe = p->function_emitter(100);
9923   EXPECT_TRUE(fe.EmitBody()) << p->error();
9924 
9925   auto ast_body = fe.ast_body();
9926   auto got = test::ToString(p->program(), ast_body);
9927   auto* expect = R"(return;
9928 )";
9929   ASSERT_EQ(expect, got);
9930 }
9931 
TEST_F(SpvParserCFGTest,EmitBody_Unreachable_InsideIf)9932 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InsideIf) {
9933   auto p = parser(test::Assemble(CommonTypes() + R"(
9934      %100 = OpFunction %void None %voidfn
9935 
9936      %10 = OpLabel
9937      OpSelectionMerge %99 None
9938      OpBranchConditional %cond %20 %99
9939 
9940      %20 = OpLabel
9941      OpUnreachable
9942 
9943      %99 = OpLabel
9944      OpReturn
9945 
9946      OpFunctionEnd
9947   )"));
9948   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9949   auto fe = p->function_emitter(100);
9950   EXPECT_TRUE(fe.EmitBody()) << p->error();
9951 
9952   auto ast_body = fe.ast_body();
9953   auto got = test::ToString(p->program(), ast_body);
9954   auto* expect = R"(if (false) {
9955   return;
9956 }
9957 return;
9958 )";
9959   ASSERT_EQ(expect, got);
9960 }
9961 
TEST_F(SpvParserCFGTest,EmitBody_Unreachable_InsideLoop)9962 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InsideLoop) {
9963   auto p = parser(test::Assemble(CommonTypes() + R"(
9964      %100 = OpFunction %void None %voidfn
9965 
9966      %10 = OpLabel
9967      OpBranch %20
9968 
9969      %20 = OpLabel
9970      OpLoopMerge %99 %80 None
9971      OpBranchConditional %cond %30 %30
9972 
9973      %30 = OpLabel
9974      OpUnreachable
9975 
9976      %80 = OpLabel
9977      OpBranch %20
9978 
9979      %99 = OpLabel
9980      OpReturn
9981 
9982      OpFunctionEnd
9983   )"));
9984   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
9985   auto fe = p->function_emitter(100);
9986   EXPECT_TRUE(fe.EmitBody()) << p->error();
9987 
9988   auto ast_body = fe.ast_body();
9989   auto got = test::ToString(p->program(), ast_body);
9990   auto* expect = R"(loop {
9991   return;
9992 }
9993 return;
9994 )";
9995   ASSERT_EQ(expect, got);
9996 }
9997 
TEST_F(SpvParserCFGTest,EmitBody_Unreachable_InNonVoidFunction)9998 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InNonVoidFunction) {
9999   auto p = parser(test::Assemble(CommonTypes() + R"(
10000      %200 = OpFunction %uint None %uintfn
10001 
10002      %210 = OpLabel
10003      OpUnreachable
10004 
10005      OpFunctionEnd
10006 
10007      %100 = OpFunction %void None %voidfn
10008 
10009      %10 = OpLabel
10010      %11 = OpFunctionCall %uint %200
10011      OpReturn
10012 
10013      OpFunctionEnd
10014   )"));
10015   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10016   auto fe = p->function_emitter(200);
10017   EXPECT_TRUE(fe.EmitBody()) << p->error();
10018 
10019   auto ast_body = fe.ast_body();
10020   auto got = test::ToString(p->program(), ast_body);
10021   auto* expect = R"(return 0u;
10022 )";
10023   ASSERT_EQ(expect, got);
10024 }
10025 
TEST_F(SpvParserCFGTest,EmitBody_Branch_BackEdge_MultiBlockLoop)10026 TEST_F(SpvParserCFGTest, EmitBody_Branch_BackEdge_MultiBlockLoop) {
10027   auto p = parser(test::Assemble(CommonTypes() + R"(
10028      %100 = OpFunction %void None %voidfn
10029 
10030      %10 = OpLabel
10031      OpBranch %20
10032 
10033      %20 = OpLabel
10034      OpLoopMerge %99 %80 None
10035      OpBranch %80
10036 
10037      %80 = OpLabel
10038      OpStore %var %uint_1
10039      OpBranch %20 ; here is one
10040 
10041      %99 = OpLabel
10042      OpReturn
10043 
10044      OpFunctionEnd
10045   )"));
10046   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10047   auto fe = p->function_emitter(100);
10048   EXPECT_TRUE(fe.EmitBody()) << p->error();
10049 
10050   auto ast_body = fe.ast_body();
10051   auto got = test::ToString(p->program(), ast_body);
10052   auto* expect = R"(loop {
10053 
10054   continuing {
10055     var_1 = 1u;
10056   }
10057 }
10058 return;
10059 )";
10060   ASSERT_EQ(expect, got);
10061 }
10062 
TEST_F(SpvParserCFGTest,EmitBody_Branch_BackEdge_SingleBlockLoop)10063 TEST_F(SpvParserCFGTest, EmitBody_Branch_BackEdge_SingleBlockLoop) {
10064   auto p = parser(test::Assemble(CommonTypes() + R"(
10065      %100 = OpFunction %void None %voidfn
10066 
10067      %10 = OpLabel
10068      OpBranch %20
10069 
10070      %20 = OpLabel
10071      OpStore %var %uint_1
10072      OpLoopMerge %99 %20 None
10073      OpBranch %20 ; backedge in single block loop
10074 
10075      %99 = OpLabel
10076      OpReturn
10077 
10078      OpFunctionEnd
10079   )"));
10080   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10081   auto fe = p->function_emitter(100);
10082   EXPECT_TRUE(fe.EmitBody()) << p->error();
10083 
10084   auto ast_body = fe.ast_body();
10085   auto got = test::ToString(p->program(), ast_body);
10086   auto* expect = R"(loop {
10087   var_1 = 1u;
10088 }
10089 return;
10090 )";
10091   ASSERT_EQ(expect, got);
10092 }
10093 
TEST_F(SpvParserCFGTest,EmitBody_Branch_SwitchBreak_LastInCase)10094 TEST_F(SpvParserCFGTest, EmitBody_Branch_SwitchBreak_LastInCase) {
10095   // When the break is last in its case, we omit it because it's implicit in
10096   // WGSL.
10097   auto p = parser(test::Assemble(CommonTypes() + R"(
10098      %100 = OpFunction %void None %voidfn
10099 
10100      %10 = OpLabel
10101      OpStore %var %uint_1
10102      OpSelectionMerge %99 None
10103      OpSwitch %selector %99 20 %20
10104 
10105      %20 = OpLabel
10106      OpStore %var %uint_20
10107      OpBranch %99 ; branch to merge. Last in case
10108 
10109      %99 = OpLabel
10110      OpStore %var %uint_7
10111      OpReturn
10112 
10113      OpFunctionEnd
10114   )"));
10115   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10116   auto fe = p->function_emitter(100);
10117   EXPECT_TRUE(fe.EmitBody()) << p->error();
10118 
10119   auto ast_body = fe.ast_body();
10120   auto got = test::ToString(p->program(), ast_body);
10121   auto* expect = R"(var_1 = 1u;
10122 switch(42u) {
10123   case 20u: {
10124     var_1 = 20u;
10125   }
10126   default: {
10127   }
10128 }
10129 var_1 = 7u;
10130 return;
10131 )";
10132   ASSERT_EQ(expect, got);
10133 }
10134 
TEST_F(SpvParserCFGTest,EmitBody_Branch_SwitchBreak_NotLastInCase)10135 TEST_F(SpvParserCFGTest, EmitBody_Branch_SwitchBreak_NotLastInCase) {
10136   // When the break is not last in its case, we must emit a 'break'
10137   auto p = parser(test::Assemble(CommonTypes() + R"(
10138      %100 = OpFunction %void None %voidfn
10139 
10140      %10 = OpLabel
10141      OpStore %var %uint_1
10142      OpSelectionMerge %99 None
10143      OpSwitch %selector %99 20 %20
10144 
10145      %20 = OpLabel
10146      OpStore %var %uint_20
10147      OpSelectionMerge %50 None
10148      OpBranchConditional %cond %40 %50
10149 
10150      %40 = OpLabel
10151      OpStore %var %uint_40
10152      OpBranch %99 ; branch to merge. Not last in case
10153 
10154      %50 = OpLabel ; inner merge
10155      OpStore %var %uint_50
10156      OpBranch %99
10157 
10158      %99 = OpLabel
10159      OpStore %var %uint_7
10160      OpReturn
10161 
10162      OpFunctionEnd
10163   )"));
10164   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10165   auto fe = p->function_emitter(100);
10166   EXPECT_TRUE(fe.EmitBody()) << p->error();
10167 
10168   auto ast_body = fe.ast_body();
10169   auto got = test::ToString(p->program(), ast_body);
10170   auto* expect = R"(var_1 = 1u;
10171 switch(42u) {
10172   case 20u: {
10173     var_1 = 20u;
10174     if (false) {
10175       var_1 = 40u;
10176       break;
10177     }
10178     var_1 = 50u;
10179   }
10180   default: {
10181   }
10182 }
10183 var_1 = 7u;
10184 return;
10185 )";
10186   ASSERT_EQ(expect, got);
10187 }
10188 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopBreak_MultiBlockLoop_FromBody)10189 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopBreak_MultiBlockLoop_FromBody) {
10190   auto p = parser(test::Assemble(CommonTypes() + R"(
10191      %100 = OpFunction %void None %voidfn
10192 
10193      %10 = OpLabel
10194      OpBranch %20
10195 
10196      %20 = OpLabel
10197      OpLoopMerge %99 %80 None
10198      OpBranch %30
10199 
10200      %30 = OpLabel
10201      OpStore %var %uint_1
10202      OpBranch %99 ; break is here
10203 
10204      %80 = OpLabel
10205      OpStore %var %uint_2
10206      OpBranch %20 ; backedge
10207 
10208      %99 = OpLabel
10209      OpReturn
10210 
10211      OpFunctionEnd
10212   )"));
10213   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10214   auto fe = p->function_emitter(100);
10215   EXPECT_TRUE(fe.EmitBody()) << p->error();
10216 
10217   auto ast_body = fe.ast_body();
10218   auto got = test::ToString(p->program(), ast_body);
10219   auto* expect = R"(loop {
10220   var_1 = 1u;
10221   break;
10222 
10223   continuing {
10224     var_1 = 2u;
10225   }
10226 }
10227 return;
10228 )";
10229   ASSERT_EQ(expect, got);
10230 }
10231 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructConditional)10232 TEST_F(
10233     SpvParserCFGTest,
10234     EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructConditional) {
10235   // This case is invalid because the backedge block doesn't post-dominate the
10236   // continue target.
10237   auto p = parser(test::Assemble(CommonTypes() + R"(
10238      %100 = OpFunction %void None %voidfn
10239 
10240      %10 = OpLabel
10241      OpBranch %20
10242 
10243      %20 = OpLabel
10244      OpLoopMerge %99 %30 None
10245      OpBranch %30
10246 
10247      %30 = OpLabel ; continue target; also an if-header
10248      OpSelectionMerge %80 None
10249      OpBranchConditional %cond %40 %80
10250 
10251      %40 = OpLabel
10252      OpBranch %99 ; break, inside a nested if.
10253 
10254      %80 = OpLabel
10255      OpBranch %20 ; backedge
10256 
10257      %99 = OpLabel
10258      OpReturn
10259 
10260      OpFunctionEnd
10261   )"));
10262   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10263   auto fe = p->function_emitter(100);
10264   EXPECT_FALSE(fe.EmitBody()) << p->error();
10265   EXPECT_THAT(p->error(),
10266               Eq("Invalid exit (40->99) from continue construct: 40 is not the "
10267                  "last block in the continue construct starting at 30 "
10268                  "(violates post-dominance rule)"));
10269 }
10270 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Unconditional)10271 TEST_F(
10272     SpvParserCFGTest,
10273     EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Unconditional) {  // NOLINT - line length
10274   auto p = parser(test::Assemble(CommonTypes() + R"(
10275      %100 = OpFunction %void None %voidfn
10276 
10277      %10 = OpLabel
10278      OpBranch %20
10279 
10280      %20 = OpLabel
10281      OpLoopMerge %99 %80 None
10282      OpBranch %80
10283 
10284      %80 = OpLabel ; continue target
10285      OpStore %var %uint_1
10286      OpBranch %99  ; should be a backedge
10287      ; This is invalid as there must be a backedge to the loop header.
10288      ; The SPIR-V allows this and understands how to emit it, even if it's not
10289      ; permitted by the SPIR-V validator.
10290 
10291      %99 = OpLabel
10292      OpReturn
10293 
10294      OpFunctionEnd
10295   )"));
10296 
10297   p->DeliberatelyInvalidSpirv();
10298 
10299   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10300   auto fe = p->function_emitter(100);
10301   EXPECT_TRUE(fe.EmitBody()) << p->error();
10302   auto ast_body = fe.ast_body();
10303   auto got = test::ToString(p->program(), ast_body);
10304   auto* expect = R"(loop {
10305 
10306   continuing {
10307     var_1 = 1u;
10308     break;
10309   }
10310 }
10311 return;
10312 )";
10313   ASSERT_EQ(expect, got);
10314 }
10315 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Conditional)10316 TEST_F(
10317     SpvParserCFGTest,
10318     EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Conditional) {  // NOLINT - line length
10319   auto p = parser(test::Assemble(CommonTypes() + R"(
10320      %100 = OpFunction %void None %voidfn
10321 
10322      %10 = OpLabel
10323      OpBranch %20
10324 
10325      %20 = OpLabel
10326      OpLoopMerge %99 %80 None
10327      OpBranch %80
10328 
10329      %80 = OpLabel ; continue target
10330      OpStore %var %uint_1
10331      OpBranchConditional %cond %20 %99  ; backedge, and exit
10332 
10333      %99 = OpLabel
10334      OpReturn
10335 
10336      OpFunctionEnd
10337   )"));
10338   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10339   auto fe = p->function_emitter(100);
10340   EXPECT_TRUE(fe.EmitBody()) << p->error();
10341   auto ast_body = fe.ast_body();
10342   auto got = test::ToString(p->program(), ast_body);
10343   auto* expect = R"(loop {
10344 
10345   continuing {
10346     var_1 = 1u;
10347     if (false) {
10348     } else {
10349       break;
10350     }
10351   }
10352 }
10353 return;
10354 )";
10355   ASSERT_EQ(expect, got);
10356 }
10357 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopContinue_LastInLoopConstruct)10358 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_LastInLoopConstruct) {
10359   auto p = parser(test::Assemble(CommonTypes() + R"(
10360      %100 = OpFunction %void None %voidfn
10361 
10362      %10 = OpLabel
10363      OpBranch %20
10364 
10365      %20 = OpLabel
10366      OpLoopMerge %99 %80 None
10367      OpBranch %30
10368 
10369      %30 = OpLabel
10370      OpStore %var %uint_1
10371      OpBranch %80 ; continue edge from last block before continue target
10372 
10373      %80 = OpLabel ; continue target
10374      OpStore %var %uint_2
10375      OpBranch %20
10376 
10377      %99 = OpLabel
10378      OpReturn
10379 
10380      OpFunctionEnd
10381   )"));
10382   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10383   auto fe = p->function_emitter(100);
10384   EXPECT_TRUE(fe.EmitBody()) << p->error();
10385   auto ast_body = fe.ast_body();
10386   auto got = test::ToString(p->program(), ast_body);
10387   auto* expect = R"(loop {
10388   var_1 = 1u;
10389 
10390   continuing {
10391     var_1 = 2u;
10392   }
10393 }
10394 return;
10395 )";
10396   ASSERT_EQ(expect, got);
10397 }
10398 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopContinue_BeforeLast)10399 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_BeforeLast) {
10400   // By construction, it has to come from nested code.
10401   auto p = parser(test::Assemble(CommonTypes() + R"(
10402      %100 = OpFunction %void None %voidfn
10403 
10404      %10 = OpLabel
10405      OpBranch %20
10406 
10407      %20 = OpLabel
10408      OpLoopMerge %99 %80 None
10409      OpBranch %30
10410 
10411      %30 = OpLabel
10412      OpSelectionMerge %50 None
10413      OpBranchConditional %cond %40 %50
10414 
10415      %40 = OpLabel
10416      OpStore %var %uint_1
10417      OpBranch %80 ; continue edge
10418 
10419      %50 = OpLabel ; inner selection merge
10420      OpStore %var %uint_2
10421      OpBranch %80
10422 
10423      %80 = OpLabel ; continue target
10424      OpStore %var %uint_3
10425      OpBranch %20
10426 
10427      %99 = OpLabel
10428      OpReturn
10429 
10430      OpFunctionEnd
10431   )"));
10432   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10433   auto fe = p->function_emitter(100);
10434   EXPECT_TRUE(fe.EmitBody()) << p->error();
10435   auto ast_body = fe.ast_body();
10436   auto got = test::ToString(p->program(), ast_body);
10437   auto* expect = R"(loop {
10438   if (false) {
10439     var_1 = 1u;
10440     continue;
10441   }
10442   var_1 = 2u;
10443 
10444   continuing {
10445     var_1 = 3u;
10446   }
10447 }
10448 return;
10449 )";
10450   ASSERT_EQ(expect, got);
10451 }
10452 
TEST_F(SpvParserCFGTest,EmitBody_Branch_LoopContinue_FromSwitch)10453 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_FromSwitch) {
10454   auto p = parser(test::Assemble(CommonTypes() + R"(
10455      %100 = OpFunction %void None %voidfn
10456 
10457      %10 = OpLabel
10458      OpStore %var %uint_1
10459      OpBranch %20
10460 
10461      %20 = OpLabel
10462      OpStore %var %uint_2
10463      OpLoopMerge %99 %80 None
10464      OpBranch %30
10465 
10466      %30 = OpLabel
10467      OpStore %var %uint_3
10468      OpSelectionMerge %79 None
10469      OpSwitch %selector %79 40 %40
10470 
10471      %40 = OpLabel
10472      OpStore %var %uint_4
10473      OpBranch %80 ; continue edge
10474 
10475      %79 = OpLabel ; switch merge
10476      OpStore %var %uint_5
10477      OpBranch %80
10478 
10479      %80 = OpLabel ; continue target
10480      OpStore %var %uint_6
10481      OpBranch %20
10482 
10483      %99 = OpLabel
10484      OpStore %var %uint_7
10485      OpReturn
10486 
10487      OpFunctionEnd
10488   )"));
10489   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10490   auto fe = p->function_emitter(100);
10491   EXPECT_TRUE(fe.EmitBody()) << p->error();
10492   auto ast_body = fe.ast_body();
10493   auto got = test::ToString(p->program(), ast_body);
10494   auto* expect = R"(var_1 = 1u;
10495 loop {
10496   var_1 = 2u;
10497   var_1 = 3u;
10498   switch(42u) {
10499     case 40u: {
10500       var_1 = 4u;
10501       continue;
10502     }
10503     default: {
10504     }
10505   }
10506   var_1 = 5u;
10507 
10508   continuing {
10509     var_1 = 6u;
10510   }
10511 }
10512 var_1 = 7u;
10513 return;
10514 )";
10515   ASSERT_EQ(expect, got);
10516 }
10517 
TEST_F(SpvParserCFGTest,EmitBody_Branch_IfBreak_FromThen)10518 TEST_F(SpvParserCFGTest, EmitBody_Branch_IfBreak_FromThen) {
10519   // When unconditional, the if-break must be last in the then clause.
10520   auto p = parser(test::Assemble(CommonTypes() + R"(
10521      %100 = OpFunction %void None %voidfn
10522 
10523      %10 = OpLabel
10524      OpSelectionMerge %99 None
10525      OpBranchConditional %cond %30 %99
10526 
10527      %30 = OpLabel
10528      OpStore %var %uint_1
10529      OpBranch %99
10530 
10531      %99 = OpLabel
10532      OpStore %var %uint_2
10533      OpReturn
10534 
10535      OpFunctionEnd
10536   )"));
10537   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10538   auto fe = p->function_emitter(100);
10539   EXPECT_TRUE(fe.EmitBody()) << p->error();
10540   auto ast_body = fe.ast_body();
10541   auto got = test::ToString(p->program(), ast_body);
10542   auto* expect = R"(if (false) {
10543   var_1 = 1u;
10544 }
10545 var_1 = 2u;
10546 return;
10547 )";
10548   ASSERT_EQ(expect, got);
10549 }
10550 
TEST_F(SpvParserCFGTest,EmitBody_Branch_IfBreak_FromElse)10551 TEST_F(SpvParserCFGTest, EmitBody_Branch_IfBreak_FromElse) {
10552   // When unconditional, the if-break must be last in the else clause.
10553   auto p = parser(test::Assemble(CommonTypes() + R"(
10554      %100 = OpFunction %void None %voidfn
10555 
10556      %10 = OpLabel
10557      OpSelectionMerge %99 None
10558      OpBranchConditional %cond %99 %30
10559 
10560      %30 = OpLabel
10561      OpStore %var %uint_1
10562      OpBranch %99
10563 
10564      %99 = OpLabel
10565      OpStore %var %uint_2
10566      OpReturn
10567 
10568      OpFunctionEnd
10569   )"));
10570   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10571   auto fe = p->function_emitter(100);
10572   EXPECT_TRUE(fe.EmitBody()) << p->error();
10573   auto ast_body = fe.ast_body();
10574   auto got = test::ToString(p->program(), ast_body);
10575   auto* expect = R"(if (false) {
10576 } else {
10577   var_1 = 1u;
10578 }
10579 var_1 = 2u;
10580 return;
10581 )";
10582   ASSERT_EQ(expect, got);
10583 }
10584 
TEST_F(SpvParserCFGTest,EmitBody_Branch_Fallthrough)10585 TEST_F(SpvParserCFGTest, EmitBody_Branch_Fallthrough) {
10586   auto p = parser(test::Assemble(CommonTypes() + R"(
10587      %100 = OpFunction %void None %voidfn
10588 
10589      %10 = OpLabel
10590      OpStore %var %uint_1
10591      OpSelectionMerge %99 None
10592      OpSwitch %selector %99 20 %20 30 %30
10593 
10594      %20 = OpLabel
10595      OpStore %var %uint_20
10596      OpBranch %30 ; uncondtional fallthrough
10597 
10598      %30 = OpLabel
10599      OpStore %var %uint_30
10600      OpBranch %99
10601 
10602      %99 = OpLabel
10603      OpStore %var %uint_7
10604      OpReturn
10605 
10606      OpFunctionEnd
10607   )"));
10608   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10609   auto fe = p->function_emitter(100);
10610   EXPECT_TRUE(fe.EmitBody()) << p->error();
10611 
10612   auto ast_body = fe.ast_body();
10613   auto got = test::ToString(p->program(), ast_body);
10614   auto* expect = R"(var_1 = 1u;
10615 switch(42u) {
10616   case 20u: {
10617     var_1 = 20u;
10618     fallthrough;
10619   }
10620   case 30u: {
10621     var_1 = 30u;
10622   }
10623   default: {
10624   }
10625 }
10626 var_1 = 7u;
10627 return;
10628 )";
10629   ASSERT_EQ(expect, got);
10630 }
10631 
TEST_F(SpvParserCFGTest,EmitBody_Branch_Forward)10632 TEST_F(SpvParserCFGTest, EmitBody_Branch_Forward) {
10633   auto p = parser(test::Assemble(CommonTypes() + R"(
10634      %100 = OpFunction %void None %voidfn
10635 
10636      %10 = OpLabel
10637      OpStore %var %uint_1
10638      OpBranch %99 ; forward
10639 
10640      %99 = OpLabel
10641      OpStore %var %uint_2
10642      OpReturn
10643 
10644      OpFunctionEnd
10645   )"));
10646   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10647   auto fe = p->function_emitter(100);
10648   EXPECT_TRUE(fe.EmitBody()) << p->error();
10649   auto ast_body = fe.ast_body();
10650   auto got = test::ToString(p->program(), ast_body);
10651   auto* expect = R"(var_1 = 1u;
10652 var_1 = 2u;
10653 return;
10654 )";
10655   ASSERT_EQ(expect, got);
10656 }
10657 
10658 // Test matrix for normal OpBranchConditional:
10659 //
10660 //    kBack with:
10661 //      kBack : TESTED dup general case
10662 //      kSwitchBreak: invalid (invalid escape, or invalid backedge)
10663 //      kLoopBreak: TESTED in single- and multi block loop configurations
10664 //      kLoopContinue: invalid
10665 //                      If single block loop, then the continue is backward
10666 //                      If continue is forward, then it's a continue from a
10667 //                      continue which is also invalid.
10668 //      kIfBreak: invalid: loop and if must have distinct merge blocks
10669 //      kCaseFallThrough: invalid: loop header must dominate its merge
10670 //      kForward: impossible; would be a loop break
10671 //
10672 //    kSwitchBreak with:
10673 //      kBack : symmetry
10674 //      kSwitchBreak: dup general case
10675 //      kLoopBreak: invalid; only one kind of break allowed
10676 //      kLoopContinue: TESTED
10677 //      kIfBreak: invalid: switch and if must have distinct merge blocks
10678 //      kCaseFallThrough: TESTED
10679 //      kForward: TESTED
10680 //
10681 //    kLoopBreak with:
10682 //      kBack : symmetry
10683 //      kSwitchBreak: symmetry
10684 //      kLoopBreak: dup general case
10685 //      kLoopContinue: TESTED
10686 //      kIfBreak: invalid: switch and if must have distinct merge blocks
10687 //      kCaseFallThrough: not possible, because switch break conflicts with loop
10688 //      break kForward: TESTED
10689 //
10690 //    kLoopContinue with:
10691 //      kBack : symmetry
10692 //      kSwitchBreak: symmetry
10693 //      kLoopBreak: symmetry
10694 //      kLoopContinue: dup general case
10695 //      kIfBreak: TESTED
10696 //      kCaseFallThrough: TESTED
10697 //      kForward: TESTED
10698 //
10699 //    kIfBreak with:
10700 //      kBack : symmetry
10701 //      kSwitchBreak: symmetry
10702 //      kLoopBreak: symmetry
10703 //      kLoopContinue: symmetry
10704 //      kIfBreak: dup general case
10705 //      kCaseFallThrough: invalid; violates nesting or unique merges
10706 //      kForward: invalid: needs a merge instruction
10707 //
10708 //    kCaseFallThrough with:
10709 //      kBack : symmetry
10710 //      kSwitchBreak: symmetry
10711 //      kLoopBreak: symmetry
10712 //      kLoopContinue: symmetry
10713 //      kIfBreak: symmetry
10714 //      kCaseFallThrough: dup general case
10715 //      kForward: invalid (tested)
10716 //
10717 //    kForward with:
10718 //      kBack : symmetry
10719 //      kSwitchBreak: symmetry
10720 //      kLoopBreak: symmetry
10721 //      kLoopContinue: symmetry
10722 //      kIfBreak: symmetry
10723 //      kCaseFallThrough: symmetry
10724 //      kForward: dup general case
10725 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Back_SingleBlock_Back)10726 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_SingleBlock_Back) {
10727   auto p = parser(test::Assemble(CommonTypes() + R"(
10728      %100 = OpFunction %void None %voidfn
10729 
10730      %10 = OpLabel
10731      OpStore %var %uint_0
10732      OpBranch %20
10733 
10734      %20 = OpLabel
10735      OpStore %var %uint_1
10736      OpLoopMerge %99 %20 None
10737      OpBranchConditional %cond %20 %20
10738 
10739      %99 = OpLabel ; dead
10740      OpStore %var %uint_5
10741      OpReturn
10742 
10743      OpFunctionEnd
10744   )"));
10745   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10746   auto fe = p->function_emitter(100);
10747   EXPECT_TRUE(fe.EmitBody()) << p->error();
10748   auto ast_body = fe.ast_body();
10749   auto got = test::ToString(p->program(), ast_body);
10750   auto* expect = R"(var_1 = 0u;
10751 loop {
10752   var_1 = 1u;
10753 }
10754 var_1 = 5u;
10755 return;
10756 )";
10757   ASSERT_EQ(expect, got);
10758 }
10759 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnTrue)10760 TEST_F(SpvParserCFGTest,
10761        EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnTrue) {
10762   auto p = parser(test::Assemble(CommonTypes() + R"(
10763      %100 = OpFunction %void None %voidfn
10764 
10765      %10 = OpLabel
10766      OpStore %var %uint_0
10767      OpBranch %20
10768 
10769      %20 = OpLabel
10770      OpStore %var %uint_1
10771      OpLoopMerge %99 %20 None
10772      OpBranchConditional %cond %99 %20
10773 
10774      %99 = OpLabel
10775      OpStore %var %uint_5
10776      OpReturn
10777 
10778      OpFunctionEnd
10779   )"));
10780   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10781   auto fe = p->function_emitter(100);
10782   EXPECT_TRUE(fe.EmitBody()) << p->error();
10783   auto ast_body = fe.ast_body();
10784   auto got = test::ToString(p->program(), ast_body);
10785   auto* expect = R"(var_1 = 0u;
10786 loop {
10787   var_1 = 1u;
10788   if (false) {
10789     break;
10790   }
10791 }
10792 var_1 = 5u;
10793 return;
10794 )";
10795   ASSERT_EQ(expect, got);
10796 }
10797 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnFalse)10798 TEST_F(SpvParserCFGTest,
10799        EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnFalse) {
10800   auto p = parser(test::Assemble(CommonTypes() + R"(
10801      %100 = OpFunction %void None %voidfn
10802 
10803      %10 = OpLabel
10804      OpStore %var %uint_0
10805      OpBranch %20
10806 
10807      %20 = OpLabel
10808      OpStore %var %uint_1
10809      OpLoopMerge %99 %20 None
10810      OpBranchConditional %cond %20 %99
10811 
10812      %99 = OpLabel
10813      OpStore %var %uint_5
10814      OpReturn
10815 
10816      OpFunctionEnd
10817   )"));
10818   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10819   auto fe = p->function_emitter(100);
10820   EXPECT_TRUE(fe.EmitBody()) << p->error();
10821   auto ast_body = fe.ast_body();
10822   auto got = test::ToString(p->program(), ast_body);
10823   auto* expect = R"(var_1 = 0u;
10824 loop {
10825   var_1 = 1u;
10826   if (false) {
10827   } else {
10828     break;
10829   }
10830 }
10831 var_1 = 5u;
10832 return;
10833 )";
10834   ASSERT_EQ(expect, got);
10835 }
10836 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnTrue)10837 TEST_F(SpvParserCFGTest,
10838        EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnTrue) {
10839   auto p = parser(test::Assemble(CommonTypes() + R"(
10840      %100 = OpFunction %void None %voidfn
10841 
10842      %10 = OpLabel
10843      OpStore %var %uint_0
10844      OpBranch %20
10845 
10846      %20 = OpLabel
10847      OpStore %var %uint_1
10848      OpLoopMerge %99 %80 None
10849      OpBranch %80
10850 
10851      %80 = OpLabel
10852      OpBranchConditional %cond %99 %20
10853 
10854      %99 = OpLabel
10855      OpStore %var %uint_5
10856      OpReturn
10857 
10858      OpFunctionEnd
10859   )"));
10860   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10861   auto fe = p->function_emitter(100);
10862   EXPECT_TRUE(fe.EmitBody()) << p->error();
10863   auto ast_body = fe.ast_body();
10864   auto got = test::ToString(p->program(), ast_body);
10865   auto* expect = R"(var_1 = 0u;
10866 loop {
10867   var_1 = 1u;
10868 
10869   continuing {
10870     if (false) {
10871       break;
10872     }
10873   }
10874 }
10875 var_1 = 5u;
10876 return;
10877 )";
10878   ASSERT_EQ(expect, got);
10879 }
10880 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnFalse)10881 TEST_F(SpvParserCFGTest,
10882        EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnFalse) {
10883   auto p = parser(test::Assemble(CommonTypes() + R"(
10884      %100 = OpFunction %void None %voidfn
10885 
10886      %10 = OpLabel
10887      OpStore %var %uint_0
10888      OpBranch %20
10889 
10890      %20 = OpLabel
10891      OpStore %var %uint_1
10892      OpLoopMerge %99 %80 None
10893      OpBranch %80
10894 
10895      %80 = OpLabel
10896      OpBranchConditional %cond %20 %99
10897 
10898      %99 = OpLabel
10899      OpStore %var %uint_5
10900      OpReturn
10901 
10902      OpFunctionEnd
10903   )"));
10904   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10905   auto fe = p->function_emitter(100);
10906   EXPECT_TRUE(fe.EmitBody()) << p->error();
10907   auto ast_body = fe.ast_body();
10908   auto got = test::ToString(p->program(), ast_body);
10909   auto* expect = R"(var_1 = 0u;
10910 loop {
10911   var_1 = 1u;
10912 
10913   continuing {
10914     if (false) {
10915     } else {
10916       break;
10917     }
10918   }
10919 }
10920 var_1 = 5u;
10921 return;
10922 )";
10923   ASSERT_EQ(expect, got);
10924 }
10925 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_SwitchBreak_LastInCase)10926 TEST_F(SpvParserCFGTest,
10927        EmitBody_BranchConditional_SwitchBreak_SwitchBreak_LastInCase) {
10928   // When the break is last in its case, we omit it because it's implicit in
10929   // WGSL.
10930   auto p = parser(test::Assemble(CommonTypes() + R"(
10931      %100 = OpFunction %void None %voidfn
10932 
10933      %10 = OpLabel
10934      OpStore %var %uint_1
10935      OpSelectionMerge %99 None
10936      OpSwitch %selector %99 20 %20
10937 
10938      %20 = OpLabel
10939      OpStore %var %uint_20
10940      OpBranchConditional %cond2 %99 %99 ; branch to merge. Last in case
10941 
10942      %99 = OpLabel
10943      OpStore %var %uint_7
10944      OpReturn
10945 
10946      OpFunctionEnd
10947   )"));
10948   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10949   auto fe = p->function_emitter(100);
10950   EXPECT_TRUE(fe.EmitBody()) << p->error();
10951 
10952   auto ast_body = fe.ast_body();
10953   auto got = test::ToString(p->program(), ast_body);
10954   auto* expect = R"(var_1 = 1u;
10955 switch(42u) {
10956   case 20u: {
10957     var_1 = 20u;
10958   }
10959   default: {
10960   }
10961 }
10962 var_1 = 7u;
10963 return;
10964 )";
10965   ASSERT_EQ(expect, got);
10966 }
10967 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_SwitchBreak_NotLastInCase)10968 TEST_F(SpvParserCFGTest,
10969        EmitBody_BranchConditional_SwitchBreak_SwitchBreak_NotLastInCase) {
10970   // When the break is not last in its case, we must emit a 'break'
10971   auto p = parser(test::Assemble(CommonTypes() + R"(
10972      %100 = OpFunction %void None %voidfn
10973 
10974      %10 = OpLabel
10975      OpStore %var %uint_1
10976      OpSelectionMerge %99 None
10977      OpSwitch %selector %99 20 %20
10978 
10979      %20 = OpLabel
10980      OpStore %var %uint_20
10981      OpSelectionMerge %50 None
10982      OpBranchConditional %cond %40 %50
10983 
10984      %40 = OpLabel
10985      OpStore %var %uint_40
10986      OpBranchConditional %cond2 %99 %99 ; branch to merge. Not last in case
10987 
10988      %50 = OpLabel ; inner merge
10989      OpStore %var %uint_50
10990      OpBranch %99
10991 
10992      %99 = OpLabel
10993      OpStore %var %uint_7
10994      OpReturn
10995 
10996      OpFunctionEnd
10997   )"));
10998   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
10999   auto fe = p->function_emitter(100);
11000   EXPECT_TRUE(fe.EmitBody()) << p->error();
11001 
11002   auto ast_body = fe.ast_body();
11003   auto got = test::ToString(p->program(), ast_body);
11004   auto* expect = R"(var_1 = 1u;
11005 switch(42u) {
11006   case 20u: {
11007     var_1 = 20u;
11008     if (false) {
11009       var_1 = 40u;
11010       break;
11011     }
11012     var_1 = 50u;
11013   }
11014   default: {
11015   }
11016 }
11017 var_1 = 7u;
11018 return;
11019 )";
11020   ASSERT_EQ(expect, got);
11021 }
11022 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Continue_OnTrue)11023 TEST_F(SpvParserCFGTest,
11024        EmitBody_BranchConditional_SwitchBreak_Continue_OnTrue) {
11025   auto p = parser(test::Assemble(CommonTypes() + R"(
11026      %100 = OpFunction %void None %voidfn
11027 
11028      %10 = OpLabel
11029      OpStore %var %uint_1
11030      OpBranch %20
11031 
11032      %20 = OpLabel
11033      OpStore %var %uint_2
11034      OpLoopMerge %99 %80 None
11035      OpBranch %30
11036 
11037      %30 = OpLabel
11038      OpStore %var %uint_3
11039      OpSelectionMerge %79 None
11040      OpSwitch %selector %79 40 %40
11041 
11042      %40 = OpLabel
11043      OpStore %var %uint_40
11044      OpBranchConditional %cond %80 %79 ; break; continue on true
11045 
11046      %79 = OpLabel
11047      OpStore %var %uint_6
11048      OpBranch %80
11049 
11050      %80 = OpLabel ; continue target
11051      OpStore %var %uint_7
11052      OpBranch %20
11053 
11054      %99 = OpLabel ; loop merge
11055      OpStore %var %uint_8
11056      OpReturn
11057 
11058      OpFunctionEnd
11059   )"));
11060   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11061   auto fe = p->function_emitter(100);
11062   EXPECT_TRUE(fe.EmitBody()) << p->error();
11063 
11064   auto ast_body = fe.ast_body();
11065   auto got = test::ToString(p->program(), ast_body);
11066   auto* expect = R"(var_1 = 1u;
11067 loop {
11068   var_1 = 2u;
11069   var_1 = 3u;
11070   switch(42u) {
11071     case 40u: {
11072       var_1 = 40u;
11073       if (false) {
11074         continue;
11075       }
11076     }
11077     default: {
11078     }
11079   }
11080   var_1 = 6u;
11081 
11082   continuing {
11083     var_1 = 7u;
11084   }
11085 }
11086 var_1 = 8u;
11087 return;
11088 )";
11089   ASSERT_EQ(expect, got);
11090 }
11091 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Continue_OnFalse)11092 TEST_F(SpvParserCFGTest,
11093        EmitBody_BranchConditional_SwitchBreak_Continue_OnFalse) {
11094   auto p = parser(test::Assemble(CommonTypes() + R"(
11095      %100 = OpFunction %void None %voidfn
11096 
11097      %10 = OpLabel
11098      OpStore %var %uint_1
11099      OpBranch %20
11100 
11101      %20 = OpLabel
11102      OpStore %var %uint_2
11103      OpLoopMerge %99 %80 None
11104      OpBranch %30
11105 
11106      %30 = OpLabel
11107      OpStore %var %uint_3
11108      OpSelectionMerge %79 None
11109      OpSwitch %selector %79 40 %40
11110 
11111      %40 = OpLabel
11112      OpStore %var %uint_40
11113      OpBranchConditional %cond %79 %80 ; break; continue on false
11114 
11115      %79 = OpLabel
11116      OpStore %var %uint_6
11117      OpBranch %80
11118 
11119      %80 = OpLabel ; continue target
11120      OpStore %var %uint_7
11121      OpBranch %20
11122 
11123      %99 = OpLabel ; loop merge
11124      OpStore %var %uint_8
11125      OpReturn
11126 
11127      OpFunctionEnd
11128   )"));
11129   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11130   auto fe = p->function_emitter(100);
11131   EXPECT_TRUE(fe.EmitBody()) << p->error();
11132 
11133   auto ast_body = fe.ast_body();
11134   auto got = test::ToString(p->program(), ast_body);
11135   auto* expect = R"(var_1 = 1u;
11136 loop {
11137   var_1 = 2u;
11138   var_1 = 3u;
11139   switch(42u) {
11140     case 40u: {
11141       var_1 = 40u;
11142       if (false) {
11143       } else {
11144         continue;
11145       }
11146     }
11147     default: {
11148     }
11149   }
11150   var_1 = 6u;
11151 
11152   continuing {
11153     var_1 = 7u;
11154   }
11155 }
11156 var_1 = 8u;
11157 return;
11158 )";
11159   ASSERT_EQ(expect, got);
11160 }
11161 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Forward_OnTrue)11162 TEST_F(SpvParserCFGTest,
11163        EmitBody_BranchConditional_SwitchBreak_Forward_OnTrue) {
11164   auto p = parser(test::Assemble(CommonTypes() + R"(
11165      %100 = OpFunction %void None %voidfn
11166 
11167      %10 = OpLabel
11168      OpStore %var %uint_1
11169      OpSelectionMerge %99 None
11170      OpSwitch %selector %99 20 %20
11171 
11172      %20 = OpLabel
11173      OpStore %var %uint_20
11174      OpBranchConditional %cond %30 %99 ; break; forward on true
11175 
11176      %30 = OpLabel
11177      OpStore %var %uint_30
11178      OpBranch %99
11179 
11180      %99 = OpLabel ; switch merge
11181      OpStore %var %uint_8
11182      OpReturn
11183 
11184      OpFunctionEnd
11185   )"));
11186   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11187   auto fe = p->function_emitter(100);
11188   EXPECT_TRUE(fe.EmitBody()) << p->error();
11189   auto ast_body = fe.ast_body();
11190   auto got = test::ToString(p->program(), ast_body);
11191   auto* expect = R"(var_1 = 1u;
11192 switch(42u) {
11193   case 20u: {
11194     var_1 = 20u;
11195     if (false) {
11196     } else {
11197       break;
11198     }
11199     var_1 = 30u;
11200   }
11201   default: {
11202   }
11203 }
11204 var_1 = 8u;
11205 return;
11206 )";
11207   ASSERT_EQ(expect, got);
11208 }
11209 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Forward_OnFalse)11210 TEST_F(SpvParserCFGTest,
11211        EmitBody_BranchConditional_SwitchBreak_Forward_OnFalse) {
11212   auto p = parser(test::Assemble(CommonTypes() + R"(
11213      %100 = OpFunction %void None %voidfn
11214 
11215      %10 = OpLabel
11216      OpStore %var %uint_1
11217      OpSelectionMerge %99 None
11218      OpSwitch %selector %99 20 %20
11219 
11220      %20 = OpLabel
11221      OpStore %var %uint_20
11222      OpBranchConditional %cond %99 %30 ; break; forward on false
11223 
11224      %30 = OpLabel
11225      OpStore %var %uint_30
11226      OpBranch %99
11227 
11228      %99 = OpLabel ; switch merge
11229      OpStore %var %uint_8
11230      OpReturn
11231 
11232      OpFunctionEnd
11233   )"));
11234   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11235   auto fe = p->function_emitter(100);
11236   EXPECT_TRUE(fe.EmitBody()) << p->error();
11237   auto ast_body = fe.ast_body();
11238   auto got = test::ToString(p->program(), ast_body);
11239   auto* expect = R"(var_1 = 1u;
11240 switch(42u) {
11241   case 20u: {
11242     var_1 = 20u;
11243     if (false) {
11244       break;
11245     }
11246     var_1 = 30u;
11247   }
11248   default: {
11249   }
11250 }
11251 var_1 = 8u;
11252 return;
11253 )";
11254   ASSERT_EQ(expect, got);
11255 }
11256 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnTrue)11257 TEST_F(SpvParserCFGTest,
11258        EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnTrue) {
11259   auto p = parser(test::Assemble(CommonTypes() + R"(
11260      %100 = OpFunction %void None %voidfn
11261 
11262      %10 = OpLabel
11263      OpStore %var %uint_1
11264      OpSelectionMerge %99 None
11265      OpSwitch %selector %99 20 %20 30 %30
11266 
11267      %20 = OpLabel
11268      OpStore %var %uint_20
11269      OpBranchConditional %cond %30 %99; fallthrough on true
11270 
11271      %30 = OpLabel
11272      OpStore %var %uint_30
11273      OpBranch %99
11274 
11275      %99 = OpLabel
11276      OpStore %var %uint_7
11277      OpReturn
11278 
11279      OpFunctionEnd
11280   )"));
11281   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11282   auto fe = p->function_emitter(100);
11283   EXPECT_TRUE(fe.EmitBody()) << p->error();
11284 
11285   auto ast_body = fe.ast_body();
11286   auto got = test::ToString(p->program(), ast_body);
11287   auto* expect = R"(var_1 = 1u;
11288 switch(42u) {
11289   case 20u: {
11290     var_1 = 20u;
11291     if (false) {
11292     } else {
11293       break;
11294     }
11295     fallthrough;
11296   }
11297   case 30u: {
11298     var_1 = 30u;
11299   }
11300   default: {
11301   }
11302 }
11303 var_1 = 7u;
11304 return;
11305 )";
11306   ASSERT_EQ(expect, got);
11307 }
11308 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnFalse)11309 TEST_F(SpvParserCFGTest,
11310        EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnFalse) {
11311   auto p = parser(test::Assemble(CommonTypes() + R"(
11312      %100 = OpFunction %void None %voidfn
11313 
11314      %10 = OpLabel
11315      OpStore %var %uint_1
11316      OpSelectionMerge %99 None
11317      OpSwitch %selector %99 20 %20 30 %30
11318 
11319      %20 = OpLabel
11320      OpStore %var %uint_20
11321      OpBranchConditional %cond %99 %30; fallthrough on false
11322 
11323      %30 = OpLabel
11324      OpStore %var %uint_30
11325      OpBranch %99
11326 
11327      %99 = OpLabel
11328      OpStore %var %uint_7
11329      OpReturn
11330 
11331      OpFunctionEnd
11332   )"));
11333   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11334   auto fe = p->function_emitter(100);
11335   EXPECT_TRUE(fe.EmitBody()) << p->error();
11336 
11337   auto ast_body = fe.ast_body();
11338   auto got = test::ToString(p->program(), ast_body);
11339   auto* expect = R"(var_1 = 1u;
11340 switch(42u) {
11341   case 20u: {
11342     var_1 = 20u;
11343     if (false) {
11344       break;
11345     }
11346     fallthrough;
11347   }
11348   case 30u: {
11349     var_1 = 30u;
11350   }
11351   default: {
11352   }
11353 }
11354 var_1 = 7u;
11355 return;
11356 )";
11357   ASSERT_EQ(expect, got);
11358 }
11359 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_SingleBlock_LoopBreak)11360 TEST_F(SpvParserCFGTest,
11361        EmitBody_BranchConditional_LoopBreak_SingleBlock_LoopBreak) {
11362   auto p = parser(test::Assemble(CommonTypes() + R"(
11363      %100 = OpFunction %void None %voidfn
11364 
11365      %10 = OpLabel
11366      OpStore %var %uint_0
11367      OpBranch %20
11368 
11369      %20 = OpLabel
11370      OpStore %var %uint_1
11371      OpLoopMerge %99 %80 None
11372      OpBranchConditional %cond %99 %99
11373 
11374      %80 = OpLabel ; continue target
11375      OpStore %var %uint_4
11376      OpBranch %20
11377 
11378      %99 = OpLabel
11379      OpStore %var %uint_5
11380      OpReturn
11381 
11382      OpFunctionEnd
11383   )"));
11384   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11385   auto fe = p->function_emitter(100);
11386   EXPECT_TRUE(fe.EmitBody()) << p->error();
11387   auto ast_body = fe.ast_body();
11388   auto got = test::ToString(p->program(), ast_body);
11389   auto* expect = R"(var_1 = 0u;
11390 loop {
11391   var_1 = 1u;
11392   break;
11393 
11394   continuing {
11395     var_1 = 4u;
11396   }
11397 }
11398 var_1 = 5u;
11399 return;
11400 )";
11401   ASSERT_EQ(expect, got);
11402 }
11403 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_MultiBlock_LoopBreak)11404 TEST_F(SpvParserCFGTest,
11405        EmitBody_BranchConditional_LoopBreak_MultiBlock_LoopBreak) {
11406   auto p = parser(test::Assemble(CommonTypes() + R"(
11407      %100 = OpFunction %void None %voidfn
11408 
11409      %10 = OpLabel
11410      OpStore %var %uint_0
11411      OpBranch %20
11412 
11413      %20 = OpLabel
11414      OpStore %var %uint_1
11415      OpLoopMerge %99 %80 None
11416      OpBranch %30
11417 
11418      %30 = OpLabel
11419      OpStore %var %uint_2
11420      OpBranchConditional %cond %99 %99
11421 
11422      %80 = OpLabel ; continue target
11423      OpStore %var %uint_4
11424      OpBranch %20
11425 
11426      %99 = OpLabel
11427      OpStore %var %uint_5
11428      OpReturn
11429 
11430      OpFunctionEnd
11431   )"));
11432   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11433   auto fe = p->function_emitter(100);
11434   EXPECT_TRUE(fe.EmitBody()) << p->error();
11435   auto ast_body = fe.ast_body();
11436   auto got = test::ToString(p->program(), ast_body);
11437   auto* expect = R"(var_1 = 0u;
11438 loop {
11439   var_1 = 1u;
11440   var_1 = 2u;
11441   break;
11442 
11443   continuing {
11444     var_1 = 4u;
11445   }
11446 }
11447 var_1 = 5u;
11448 return;
11449 )";
11450   ASSERT_EQ(expect, got);
11451 }
11452 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_Continue_OnTrue)11453 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Continue_OnTrue) {
11454   auto p = parser(test::Assemble(CommonTypes() + R"(
11455      %100 = OpFunction %void None %voidfn
11456 
11457      %10 = OpLabel
11458      OpStore %var %uint_0
11459      OpBranch %20
11460 
11461      %20 = OpLabel
11462      OpStore %var %uint_1
11463      OpLoopMerge %99 %80 None
11464      OpBranch %25
11465 
11466      ; Need this extra selection to make another block between
11467      ; %30 and the continue target, so we actually induce a Continue
11468      ; statement to exist.
11469      %25 = OpLabel
11470      OpSelectionMerge %40 None
11471      OpBranchConditional %cond2 %30 %40
11472 
11473      %30 = OpLabel
11474      OpStore %var %uint_2
11475 ; break; continue on true
11476      OpBranchConditional %cond %80 %99
11477 
11478      %40 = OpLabel
11479      OpStore %var %uint_3
11480      OpBranch %80
11481 
11482      %80 = OpLabel ; continue target
11483      OpStore %var %uint_4
11484      OpBranch %20
11485 
11486      %99 = OpLabel
11487      OpStore %var %uint_5
11488      OpReturn
11489 
11490      OpFunctionEnd
11491   )"));
11492   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11493   auto fe = p->function_emitter(100);
11494   EXPECT_TRUE(fe.EmitBody()) << p->error();
11495   auto ast_body = fe.ast_body();
11496   auto got = test::ToString(p->program(), ast_body);
11497   auto* expect = R"(var_1 = 0u;
11498 loop {
11499   var_1 = 1u;
11500   if (true) {
11501     var_1 = 2u;
11502     if (false) {
11503       continue;
11504     } else {
11505       break;
11506     }
11507   }
11508   var_1 = 3u;
11509 
11510   continuing {
11511     var_1 = 4u;
11512   }
11513 }
11514 var_1 = 5u;
11515 return;
11516 )";
11517   ASSERT_EQ(expect, got);
11518 }
11519 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_Continue_OnFalse)11520 TEST_F(SpvParserCFGTest,
11521        EmitBody_BranchConditional_LoopBreak_Continue_OnFalse) {
11522   auto p = parser(test::Assemble(CommonTypes() + R"(
11523      %100 = OpFunction %void None %voidfn
11524 
11525      %10 = OpLabel
11526      OpStore %var %uint_0
11527      OpBranch %20
11528 
11529      %20 = OpLabel
11530      OpStore %var %uint_1
11531      OpLoopMerge %99 %80 None
11532      OpBranch %25
11533 
11534      ; Need this extra selection to make another block between
11535      ; %30 and the continue target, so we actually induce a Continue
11536      ; statement to exist.
11537      %25 = OpLabel
11538      OpSelectionMerge %40 None
11539      OpBranchConditional %cond2 %30 %40
11540 
11541      %30 = OpLabel
11542      OpStore %var %uint_2
11543 ; break; continue on false
11544      OpBranchConditional %cond %99 %80
11545 
11546      %40 = OpLabel
11547      OpStore %var %uint_3
11548      OpBranch %80
11549 
11550      %80 = OpLabel ; continue target
11551      OpStore %var %uint_4
11552      OpBranch %20
11553 
11554      %99 = OpLabel
11555      OpStore %var %uint_5
11556      OpReturn
11557 
11558      OpFunctionEnd
11559   )"));
11560   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11561   auto fe = p->function_emitter(100);
11562   EXPECT_TRUE(fe.EmitBody()) << p->error();
11563   auto ast_body = fe.ast_body();
11564   auto got = test::ToString(p->program(), ast_body);
11565   auto* expect = R"(var_1 = 0u;
11566 loop {
11567   var_1 = 1u;
11568   if (true) {
11569     var_1 = 2u;
11570     if (false) {
11571       break;
11572     } else {
11573       continue;
11574     }
11575   }
11576   var_1 = 3u;
11577 
11578   continuing {
11579     var_1 = 4u;
11580   }
11581 }
11582 var_1 = 5u;
11583 return;
11584 )";
11585   ASSERT_EQ(expect, got);
11586 }
11587 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_Fallthrough_IsError)11588 TEST_F(SpvParserCFGTest,
11589        EmitBody_BranchConditional_LoopBreak_Fallthrough_IsError) {
11590   // It's an error because switch break conflicts with loop break.
11591   auto p = parser(test::Assemble(CommonTypes() + R"(
11592      %100 = OpFunction %void None %voidfn
11593 
11594      %10 = OpLabel
11595      OpStore %var %uint_0
11596      OpBranch %20
11597 
11598      %20 = OpLabel
11599      OpStore %var %uint_1
11600      OpLoopMerge %99 %80 None
11601      OpBranch %30
11602 
11603      %30 = OpLabel
11604      OpSelectionMerge %79 None
11605      OpSwitch %selector %79 40 %40 50 %50
11606 
11607      %40 = OpLabel
11608      OpStore %var %uint_40
11609      ; error: branch to 99 bypasses switch's merge
11610      OpBranchConditional %cond %99 %50 ; loop break; fall through
11611 
11612      %50 = OpLabel
11613      OpStore %var %uint_50
11614      OpBranch %79
11615 
11616      %79 = OpLabel ; switch merge
11617      OpBranch %80
11618 
11619      %80 = OpLabel ; continue target
11620      OpStore %var %uint_4
11621      OpBranch %20
11622 
11623      %99 = OpLabel
11624      OpStore %var %uint_5
11625      OpReturn
11626 
11627      OpFunctionEnd
11628   )"));
11629   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11630   auto fe = p->function_emitter(100);
11631   EXPECT_FALSE(fe.EmitBody()) << p->error();
11632   EXPECT_THAT(
11633       p->error(),
11634       Eq("Branch from block 40 to block 99 is an invalid exit from construct "
11635          "starting at block 30; branch bypasses merge block 79"));
11636 }
11637 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_Forward_OnTrue)11638 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Forward_OnTrue) {
11639   auto p = parser(test::Assemble(CommonTypes() + R"(
11640      %100 = OpFunction %void None %voidfn
11641 
11642      %10 = OpLabel
11643      OpStore %var %uint_0
11644      OpBranch %20
11645 
11646      %20 = OpLabel
11647      OpStore %var %uint_1
11648      OpLoopMerge %99 %80 None
11649      OpBranch %30
11650 
11651      %30 = OpLabel
11652      OpStore %var %uint_2
11653 ; break; forward on true
11654      OpBranchConditional %cond %40 %99
11655 
11656      %40 = OpLabel
11657      OpStore %var %uint_3
11658      OpBranch %80
11659 
11660      %80 = OpLabel ; continue target
11661      OpStore %var %uint_4
11662      OpBranch %20
11663 
11664      %99 = OpLabel
11665      OpStore %var %uint_5
11666      OpReturn
11667 
11668      OpFunctionEnd
11669   )"));
11670   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11671   auto fe = p->function_emitter(100);
11672   EXPECT_TRUE(fe.EmitBody()) << p->error();
11673   auto ast_body = fe.ast_body();
11674   auto got = test::ToString(p->program(), ast_body);
11675   auto* expect = R"(var_1 = 0u;
11676 loop {
11677   var_1 = 1u;
11678   var_1 = 2u;
11679   if (false) {
11680   } else {
11681     break;
11682   }
11683   var_1 = 3u;
11684 
11685   continuing {
11686     var_1 = 4u;
11687   }
11688 }
11689 var_1 = 5u;
11690 return;
11691 )";
11692   ASSERT_EQ(expect, got);
11693 }
11694 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopBreak_Forward_OnFalse)11695 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Forward_OnFalse) {
11696   auto p = parser(test::Assemble(CommonTypes() + R"(
11697      %100 = OpFunction %void None %voidfn
11698 
11699      %10 = OpLabel
11700      OpStore %var %uint_0
11701      OpBranch %20
11702 
11703      %20 = OpLabel
11704      OpStore %var %uint_1
11705      OpLoopMerge %99 %80 None
11706      OpBranch %30
11707 
11708      %30 = OpLabel
11709      OpStore %var %uint_2
11710 ; break; forward on false
11711      OpBranchConditional %cond %99 %40
11712 
11713      %40 = OpLabel
11714      OpStore %var %uint_3
11715      OpBranch %80
11716 
11717      %80 = OpLabel ; continue target
11718      OpStore %var %uint_4
11719      OpBranch %20
11720 
11721      %99 = OpLabel
11722      OpStore %var %uint_5
11723      OpReturn
11724 
11725      OpFunctionEnd
11726   )"));
11727   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11728   auto fe = p->function_emitter(100);
11729   EXPECT_TRUE(fe.EmitBody()) << p->error();
11730   auto ast_body = fe.ast_body();
11731   auto got = test::ToString(p->program(), ast_body);
11732   auto* expect = R"(var_1 = 0u;
11733 loop {
11734   var_1 = 1u;
11735   var_1 = 2u;
11736   if (false) {
11737     break;
11738   }
11739   var_1 = 3u;
11740 
11741   continuing {
11742     var_1 = 4u;
11743   }
11744 }
11745 var_1 = 5u;
11746 return;
11747 )";
11748   ASSERT_EQ(expect, got);
11749 }
11750 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Continue_FromHeader)11751 TEST_F(SpvParserCFGTest,
11752        EmitBody_BranchConditional_Continue_Continue_FromHeader) {
11753   auto p = parser(test::Assemble(CommonTypes() + R"(
11754      %100 = OpFunction %void None %voidfn
11755 
11756      %10 = OpLabel
11757      OpStore %var %uint_0
11758      OpBranch %20
11759 
11760      %20 = OpLabel
11761      OpStore %var %uint_1
11762      OpLoopMerge %99 %80 None
11763      OpBranchConditional %cond %80 %80 ; to continue
11764 
11765      %80 = OpLabel ; continue target
11766      OpStore %var %uint_4
11767      OpBranch %20
11768 
11769      %99 = OpLabel
11770      OpStore %var %uint_5
11771      OpReturn
11772 
11773      OpFunctionEnd
11774   )"));
11775   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11776   auto fe = p->function_emitter(100);
11777   EXPECT_TRUE(fe.EmitBody()) << p->error();
11778   auto ast_body = fe.ast_body();
11779   auto got = test::ToString(p->program(), ast_body);
11780   auto* expect = R"(var_1 = 0u;
11781 loop {
11782   var_1 = 1u;
11783 
11784   continuing {
11785     var_1 = 4u;
11786   }
11787 }
11788 var_1 = 5u;
11789 return;
11790 )";
11791   ASSERT_EQ(expect, got);
11792 }
11793 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Continue_AfterHeader_Unconditional)11794 TEST_F(SpvParserCFGTest,
11795        EmitBody_BranchConditional_Continue_Continue_AfterHeader_Unconditional) {
11796   auto p = parser(test::Assemble(CommonTypes() + R"(
11797      %100 = OpFunction %void None %voidfn
11798 
11799      %10 = OpLabel
11800      OpStore %var %uint_0
11801      OpBranch %20
11802 
11803      %20 = OpLabel
11804      OpStore %var %uint_1
11805      OpLoopMerge %99 %80 None
11806      OpBranch %30
11807 
11808      %30 = OpLabel
11809      OpStore %var %uint_2
11810      OpBranchConditional %cond %80 %80 ; to continue
11811 
11812      %80 = OpLabel ; continue target
11813      OpStore %var %uint_4
11814      OpBranch %20
11815 
11816      %99 = OpLabel
11817      OpStore %var %uint_5
11818      OpReturn
11819 
11820      OpFunctionEnd
11821   )"));
11822   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11823   auto fe = p->function_emitter(100);
11824   EXPECT_TRUE(fe.EmitBody()) << p->error();
11825   auto ast_body = fe.ast_body();
11826   auto got = test::ToString(p->program(), ast_body);
11827   auto* expect = R"(var_1 = 0u;
11828 loop {
11829   var_1 = 1u;
11830   var_1 = 2u;
11831 
11832   continuing {
11833     var_1 = 4u;
11834   }
11835 }
11836 var_1 = 5u;
11837 return;
11838 )";
11839   ASSERT_EQ(expect, got);
11840 }
11841 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional)11842 TEST_F(SpvParserCFGTest,
11843        EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional) {
11844   // Create an intervening block so we actually require a "continue" statement
11845   // instead of just an adjacent fallthrough to the continue target.
11846   auto p = parser(test::Assemble(CommonTypes() + R"(
11847      %100 = OpFunction %void None %voidfn
11848 
11849      %10 = OpLabel
11850      OpStore %var %uint_0
11851      OpBranch %20
11852 
11853      %20 = OpLabel
11854      OpStore %var %uint_1
11855      OpLoopMerge %99 %80 None
11856      OpBranch %30
11857 
11858      %30 = OpLabel
11859      OpStore %var %uint_2
11860      OpSelectionMerge %50 None
11861      OpBranchConditional %cond2 %40 %50
11862 
11863      %40 = OpLabel
11864      OpStore %var %uint_3
11865      OpBranchConditional %cond3 %80 %80 ; to continue
11866 
11867      %50 = OpLabel ; merge for selection
11868      OpStore %var %uint_4
11869      OpBranch %80
11870 
11871      %80 = OpLabel ; continue target
11872      OpStore %var %uint_5
11873      OpBranch %20
11874 
11875      %99 = OpLabel
11876      OpStore %var %uint_6
11877      OpReturn
11878 
11879      OpFunctionEnd
11880   )"));
11881   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11882   auto fe = p->function_emitter(100);
11883   EXPECT_TRUE(fe.EmitBody()) << p->error();
11884   auto ast_body = fe.ast_body();
11885   auto got = test::ToString(p->program(), ast_body);
11886   auto* expect = R"(var_1 = 0u;
11887 loop {
11888   var_1 = 1u;
11889   var_1 = 2u;
11890   if (true) {
11891     var_1 = 3u;
11892     continue;
11893   }
11894   var_1 = 4u;
11895 
11896   continuing {
11897     var_1 = 5u;
11898   }
11899 }
11900 var_1 = 6u;
11901 return;
11902 )";
11903   ASSERT_EQ(expect, got);
11904 }
11905 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional_EmptyContinuing)11906 TEST_F(
11907     SpvParserCFGTest,
11908     EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional_EmptyContinuing) {  // NOLINT
11909   // Like the previous tests, but with an empty continuing clause.
11910   auto p = parser(test::Assemble(CommonTypes() + R"(
11911      %100 = OpFunction %void None %voidfn
11912 
11913      %10 = OpLabel
11914      OpStore %var %uint_0
11915      OpBranch %20
11916 
11917      %20 = OpLabel
11918      OpStore %var %uint_1
11919      OpLoopMerge %99 %80 None
11920      OpBranch %30
11921 
11922      %30 = OpLabel
11923      OpStore %var %uint_2
11924      OpSelectionMerge %50 None
11925      OpBranchConditional %cond2 %40 %50
11926 
11927      %40 = OpLabel
11928      OpStore %var %uint_3
11929      OpBranchConditional %cond3 %80 %80 ; to continue
11930 
11931      %50 = OpLabel ; merge for selection
11932      OpStore %var %uint_4
11933      OpBranch %80
11934 
11935      %80 = OpLabel ; continue target
11936      ; no statements here.
11937      OpBranch %20
11938 
11939      %99 = OpLabel
11940      OpStore %var %uint_6
11941      OpReturn
11942 
11943      OpFunctionEnd
11944   )"));
11945   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
11946   auto fe = p->function_emitter(100);
11947   EXPECT_TRUE(fe.EmitBody()) << p->error();
11948   auto ast_body = fe.ast_body();
11949   auto got = test::ToString(p->program(), ast_body);
11950   auto* expect = R"(var_1 = 0u;
11951 loop {
11952   var_1 = 1u;
11953   var_1 = 2u;
11954   if (true) {
11955     var_1 = 3u;
11956     continue;
11957   }
11958   var_1 = 4u;
11959 }
11960 var_1 = 6u;
11961 return;
11962 )";
11963   ASSERT_EQ(expect, got);
11964 }
11965 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_LoopContinue_FromSwitch)11966 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopContinue_FromSwitch) {
11967   auto p = parser(test::Assemble(CommonTypes() + R"(
11968      %100 = OpFunction %void None %voidfn
11969 
11970      %10 = OpLabel
11971      OpStore %var %uint_1
11972      OpBranch %20
11973 
11974      %20 = OpLabel
11975      OpStore %var %uint_2
11976      OpLoopMerge %99 %80 None
11977      OpBranch %30
11978 
11979      %30 = OpLabel
11980      OpStore %var %uint_3
11981      OpSelectionMerge %79 None
11982      OpSwitch %selector %79 40 %40
11983 
11984      %40 = OpLabel
11985      OpStore %var %uint_4
11986      OpBranchConditional %cond2 %80 %80; dup continue edge
11987 
11988      %79 = OpLabel ; switch merge
11989      OpStore %var %uint_5
11990      OpBranch %80
11991 
11992      %80 = OpLabel ; continue target
11993      OpStore %var %uint_6
11994      OpBranch %20
11995 
11996      %99 = OpLabel
11997      OpStore %var %uint_7
11998      OpReturn
11999 
12000      OpFunctionEnd
12001   )"));
12002   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12003   auto fe = p->function_emitter(100);
12004   EXPECT_TRUE(fe.EmitBody()) << p->error();
12005   auto ast_body = fe.ast_body();
12006   auto got = test::ToString(p->program(), ast_body);
12007   auto* expect = R"(var_1 = 1u;
12008 loop {
12009   var_1 = 2u;
12010   var_1 = 3u;
12011   switch(42u) {
12012     case 40u: {
12013       var_1 = 4u;
12014       continue;
12015     }
12016     default: {
12017     }
12018   }
12019   var_1 = 5u;
12020 
12021   continuing {
12022     var_1 = 6u;
12023   }
12024 }
12025 var_1 = 7u;
12026 return;
12027 )";
12028   ASSERT_EQ(expect, got);
12029 }
12030 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_IfBreak_OnTrue)12031 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_IfBreak_OnTrue) {
12032   auto p = parser(test::Assemble(CommonTypes() + R"(
12033      %100 = OpFunction %void None %voidfn
12034 
12035      %10 = OpLabel
12036      OpStore %var %uint_0
12037      OpBranch %20
12038 
12039      %20 = OpLabel
12040      OpStore %var %uint_1
12041      OpLoopMerge %99 %80 None
12042      OpBranch %30
12043 
12044      %30 = OpLabel
12045      OpStore %var %uint_2
12046      OpSelectionMerge %50 None
12047      OpBranchConditional %cond2 %40 %50
12048 
12049      %40 = OpLabel
12050      OpStore %var %uint_3
12051  ; true to if's merge;  false to continue
12052      OpBranchConditional %cond3 %50 %80
12053 
12054      %50 = OpLabel ; merge for selection
12055      OpStore %var %uint_4
12056      OpBranch %80
12057 
12058      %80 = OpLabel ; continue target
12059      OpStore %var %uint_5
12060      OpBranch %20
12061 
12062      %99 = OpLabel
12063      OpStore %var %uint_6
12064      OpReturn
12065 
12066      OpFunctionEnd
12067   )"));
12068   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12069   auto fe = p->function_emitter(100);
12070   EXPECT_TRUE(fe.EmitBody()) << p->error();
12071   auto ast_body = fe.ast_body();
12072   auto got = test::ToString(p->program(), ast_body);
12073   auto* expect = R"(var_1 = 0u;
12074 loop {
12075   var_1 = 1u;
12076   var_1 = 2u;
12077   if (true) {
12078     var_1 = 3u;
12079     if (false) {
12080     } else {
12081       continue;
12082     }
12083   }
12084   var_1 = 4u;
12085 
12086   continuing {
12087     var_1 = 5u;
12088   }
12089 }
12090 var_1 = 6u;
12091 return;
12092 )";
12093   ASSERT_EQ(expect, got);
12094 }
12095 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_IfBreak_OnFalse)12096 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_IfBreak_OnFalse) {
12097   auto p = parser(test::Assemble(CommonTypes() + R"(
12098      %100 = OpFunction %void None %voidfn
12099 
12100      %10 = OpLabel
12101      OpStore %var %uint_0
12102      OpBranch %20
12103 
12104      %20 = OpLabel
12105      OpStore %var %uint_1
12106      OpLoopMerge %99 %80 None
12107      OpBranch %30
12108 
12109      %30 = OpLabel
12110      OpStore %var %uint_2
12111      OpSelectionMerge %50 None
12112      OpBranchConditional %cond2 %40 %50
12113 
12114      %40 = OpLabel
12115      OpStore %var %uint_3
12116  ; false to if's merge;  true to continue
12117      OpBranchConditional %cond3 %80 %50
12118 
12119      %50 = OpLabel ; merge for selection
12120      OpStore %var %uint_4
12121      OpBranch %80
12122 
12123      %80 = OpLabel ; continue target
12124      OpStore %var %uint_5
12125      OpBranch %20
12126 
12127      %99 = OpLabel
12128      OpStore %var %uint_6
12129      OpReturn
12130 
12131      OpFunctionEnd
12132   )"));
12133   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12134   auto fe = p->function_emitter(100);
12135   EXPECT_TRUE(fe.EmitBody()) << p->error();
12136   auto ast_body = fe.ast_body();
12137   auto got = test::ToString(p->program(), ast_body);
12138   auto* expect = R"(var_1 = 0u;
12139 loop {
12140   var_1 = 1u;
12141   var_1 = 2u;
12142   if (true) {
12143     var_1 = 3u;
12144     if (false) {
12145       continue;
12146     }
12147   }
12148   var_1 = 4u;
12149 
12150   continuing {
12151     var_1 = 5u;
12152   }
12153 }
12154 var_1 = 6u;
12155 return;
12156 )";
12157   ASSERT_EQ(expect, got);
12158 }
12159 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Fallthrough_OnTrue)12160 TEST_F(SpvParserCFGTest,
12161        EmitBody_BranchConditional_Continue_Fallthrough_OnTrue) {
12162   auto p = parser(test::Assemble(CommonTypes() + R"(
12163      %100 = OpFunction %void None %voidfn
12164 
12165      %10 = OpLabel
12166      OpStore %var %uint_0
12167      OpBranch %20
12168 
12169      %20 = OpLabel
12170      OpStore %var %uint_1
12171      OpLoopMerge %99 %80 None
12172      OpBranch %30
12173 
12174      %30 = OpLabel
12175      OpStore %var %uint_2
12176      OpSelectionMerge %79 None
12177      OpSwitch %selector %79 40 %40 50 %50
12178 
12179      %40 = OpLabel
12180      OpStore %var %uint_40
12181      OpBranchConditional %cond %50 %80 ; loop continue; fall through on true
12182 
12183      %50 = OpLabel
12184      OpStore %var %uint_50
12185      OpBranch %79
12186 
12187      %79 = OpLabel ; switch merge
12188      OpStore %var %uint_3
12189      OpBranch %80
12190 
12191      %80 = OpLabel ; continue target
12192      OpStore %var %uint_4
12193      OpBranch %20
12194 
12195      %99 = OpLabel
12196      OpStore %var %uint_5
12197      OpReturn
12198 
12199      OpFunctionEnd
12200   )"));
12201   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12202   auto fe = p->function_emitter(100);
12203   EXPECT_TRUE(fe.EmitBody()) << p->error();
12204   auto ast_body = fe.ast_body();
12205   auto got = test::ToString(p->program(), ast_body);
12206   auto* expect = R"(var_1 = 0u;
12207 loop {
12208   var_1 = 1u;
12209   var_1 = 2u;
12210   switch(42u) {
12211     case 40u: {
12212       var_1 = 40u;
12213       if (false) {
12214       } else {
12215         continue;
12216       }
12217       fallthrough;
12218     }
12219     case 50u: {
12220       var_1 = 50u;
12221     }
12222     default: {
12223     }
12224   }
12225   var_1 = 3u;
12226 
12227   continuing {
12228     var_1 = 4u;
12229   }
12230 }
12231 var_1 = 5u;
12232 return;
12233 )";
12234   ASSERT_EQ(expect, got);
12235 }
12236 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Fallthrough_OnFalse)12237 TEST_F(SpvParserCFGTest,
12238        EmitBody_BranchConditional_Continue_Fallthrough_OnFalse) {
12239   auto p = parser(test::Assemble(CommonTypes() + R"(
12240      %100 = OpFunction %void None %voidfn
12241 
12242      %10 = OpLabel
12243      OpStore %var %uint_0
12244      OpBranch %20
12245 
12246      %20 = OpLabel
12247      OpStore %var %uint_1
12248      OpLoopMerge %99 %80 None
12249      OpBranch %30
12250 
12251      %30 = OpLabel
12252      OpStore %var %uint_2
12253      OpSelectionMerge %79 None
12254      OpSwitch %selector %79 40 %40 50 %50
12255 
12256      %40 = OpLabel
12257      OpStore %var %uint_40
12258      OpBranchConditional %cond %80 %50 ; loop continue; fall through on false
12259 
12260      %50 = OpLabel
12261      OpStore %var %uint_50
12262      OpBranch %79
12263 
12264      %79 = OpLabel ; switch merge
12265      OpStore %var %uint_3
12266      OpBranch %80
12267 
12268      %80 = OpLabel ; continue target
12269      OpStore %var %uint_4
12270      OpBranch %20
12271 
12272      %99 = OpLabel
12273      OpStore %var %uint_5
12274      OpReturn
12275 
12276      OpFunctionEnd
12277   )"));
12278   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12279   auto fe = p->function_emitter(100);
12280   EXPECT_TRUE(fe.EmitBody()) << p->error();
12281   auto ast_body = fe.ast_body();
12282   auto got = test::ToString(p->program(), ast_body);
12283   auto* expect = R"(var_1 = 0u;
12284 loop {
12285   var_1 = 1u;
12286   var_1 = 2u;
12287   switch(42u) {
12288     case 40u: {
12289       var_1 = 40u;
12290       if (false) {
12291         continue;
12292       }
12293       fallthrough;
12294     }
12295     case 50u: {
12296       var_1 = 50u;
12297     }
12298     default: {
12299     }
12300   }
12301   var_1 = 3u;
12302 
12303   continuing {
12304     var_1 = 4u;
12305   }
12306 }
12307 var_1 = 5u;
12308 return;
12309 )";
12310   ASSERT_EQ(expect, got);
12311 }
12312 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Forward_OnTrue)12313 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Forward_OnTrue) {
12314   auto p = parser(test::Assemble(CommonTypes() + R"(
12315      %100 = OpFunction %void None %voidfn
12316 
12317      %10 = OpLabel
12318      OpStore %var %uint_0
12319      OpBranch %20
12320 
12321      %20 = OpLabel
12322      OpStore %var %uint_1
12323      OpLoopMerge %99 %80 None
12324      OpBranch %30
12325 
12326      %30 = OpLabel
12327      OpStore %var %uint_2
12328 ; continue; forward on true
12329      OpBranchConditional %cond %40 %80
12330 
12331      %40 = OpLabel
12332      OpStore %var %uint_3
12333      OpBranch %80
12334 
12335      %80 = OpLabel ; continue target
12336      OpStore %var %uint_4
12337      OpBranch %20
12338 
12339      %99 = OpLabel
12340      OpStore %var %uint_5
12341      OpReturn
12342 
12343      OpFunctionEnd
12344   )"));
12345   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12346   auto fe = p->function_emitter(100);
12347   EXPECT_TRUE(fe.EmitBody()) << p->error();
12348   auto ast_body = fe.ast_body();
12349   auto got = test::ToString(p->program(), ast_body);
12350   auto* expect = R"(var_1 = 0u;
12351 loop {
12352   var_1 = 1u;
12353   var_1 = 2u;
12354   if (false) {
12355   } else {
12356     continue;
12357   }
12358   var_1 = 3u;
12359 
12360   continuing {
12361     var_1 = 4u;
12362   }
12363 }
12364 var_1 = 5u;
12365 return;
12366 )";
12367   ASSERT_EQ(expect, got);
12368 }
12369 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Continue_Forward_OnFalse)12370 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Forward_OnFalse) {
12371   auto p = parser(test::Assemble(CommonTypes() + R"(
12372      %100 = OpFunction %void None %voidfn
12373 
12374      %10 = OpLabel
12375      OpStore %var %uint_0
12376      OpBranch %20
12377 
12378      %20 = OpLabel
12379      OpStore %var %uint_1
12380      OpLoopMerge %99 %80 None
12381      OpBranch %30
12382 
12383      %30 = OpLabel
12384      OpStore %var %uint_2
12385 ; continue; forward on true
12386      OpBranchConditional %cond %80 %40
12387 
12388      %40 = OpLabel
12389      OpStore %var %uint_3
12390      OpBranch %80
12391 
12392      %80 = OpLabel ; continue target
12393      OpStore %var %uint_4
12394      OpBranch %20
12395 
12396      %99 = OpLabel
12397      OpStore %var %uint_5
12398      OpReturn
12399 
12400      OpFunctionEnd
12401   )"));
12402   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12403   auto fe = p->function_emitter(100);
12404   EXPECT_TRUE(fe.EmitBody()) << p->error();
12405   auto ast_body = fe.ast_body();
12406   auto got = test::ToString(p->program(), ast_body);
12407   auto* expect = R"(var_1 = 0u;
12408 loop {
12409   var_1 = 1u;
12410   var_1 = 2u;
12411   if (false) {
12412     continue;
12413   }
12414   var_1 = 3u;
12415 
12416   continuing {
12417     var_1 = 4u;
12418   }
12419 }
12420 var_1 = 5u;
12421 return;
12422 )";
12423   ASSERT_EQ(expect, got);
12424 }
12425 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_IfBreak_IfBreak_Same)12426 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_IfBreak_IfBreak_Same) {
12427   auto p = parser(test::Assemble(CommonTypes() + R"(
12428      %100 = OpFunction %void None %voidfn
12429 
12430      %10 = OpLabel
12431      OpStore %var %uint_0
12432      OpSelectionMerge %99 None
12433      OpBranchConditional %cond %99 %99
12434 
12435      %20 = OpLabel ; dead
12436      OpStore %var %uint_1
12437      OpBranch %99
12438 
12439      %99 = OpLabel
12440      OpStore %var %uint_5
12441      OpReturn
12442 
12443      OpFunctionEnd
12444   )"));
12445   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12446   auto fe = p->function_emitter(100);
12447   EXPECT_TRUE(fe.EmitBody()) << p->error();
12448   auto ast_body = fe.ast_body();
12449   auto got = test::ToString(p->program(), ast_body);
12450   auto* expect = R"(var_1 = 0u;
12451 if (false) {
12452 }
12453 var_1 = 5u;
12454 return;
12455 )";
12456   ASSERT_EQ(expect, got);
12457 }
12458 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_IfBreak_IfBreak_DifferentIsError)12459 TEST_F(SpvParserCFGTest,
12460        EmitBody_BranchConditional_IfBreak_IfBreak_DifferentIsError) {
12461   auto p = parser(test::Assemble(CommonTypes() + R"(
12462      %100 = OpFunction %void None %voidfn
12463 
12464      %10 = OpLabel
12465      OpStore %var %uint_0
12466      OpSelectionMerge %99 None
12467      OpBranchConditional %cond %20 %99
12468 
12469      %20 = OpLabel
12470      OpStore %var %uint_1
12471      OpSelectionMerge %89 None
12472      OpBranchConditional %cond %30 %89
12473 
12474      %30 = OpLabel
12475      OpStore %var %uint_2
12476      OpBranchConditional %cond %89 %99 ; invalid divergence
12477 
12478      %89 = OpLabel ; inner if-merge
12479      OpBranch %99
12480 
12481      %99 = OpLabel ; outer if-merge
12482      OpStore %var %uint_5
12483      OpReturn
12484 
12485      OpFunctionEnd
12486   )"));
12487   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12488   auto fe = p->function_emitter(100);
12489   EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
12490   EXPECT_THAT(
12491       p->error(),
12492       Eq("Branch from block 30 to block 99 is an invalid exit from construct "
12493          "starting at block 20; branch bypasses merge block 89"));
12494 }
12495 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Fallthrough_Fallthrough_Same)12496 TEST_F(SpvParserCFGTest,
12497        EmitBody_BranchConditional_Fallthrough_Fallthrough_Same) {
12498   auto p = parser(test::Assemble(CommonTypes() + R"(
12499      %100 = OpFunction %void None %voidfn
12500 
12501      %10 = OpLabel
12502      OpStore %var %uint_1
12503      OpSelectionMerge %99 None
12504      OpSwitch %selector %99 20 %20 30 %30
12505 
12506      %20 = OpLabel
12507      OpStore %var %uint_20
12508      OpBranchConditional %cond %30 %30 ; fallthrough fallthrough
12509 
12510      %30 = OpLabel
12511      OpStore %var %uint_30
12512      OpBranch %99
12513 
12514      %99 = OpLabel
12515      OpStore %var %uint_7
12516      OpReturn
12517 
12518      OpFunctionEnd
12519   )"));
12520   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12521   auto fe = p->function_emitter(100);
12522   EXPECT_TRUE(fe.EmitBody()) << p->error();
12523 
12524   auto ast_body = fe.ast_body();
12525   auto got = test::ToString(p->program(), ast_body);
12526   auto* expect = R"(var_1 = 1u;
12527 switch(42u) {
12528   case 20u: {
12529     var_1 = 20u;
12530     fallthrough;
12531   }
12532   case 30u: {
12533     var_1 = 30u;
12534   }
12535   default: {
12536   }
12537 }
12538 var_1 = 7u;
12539 return;
12540 )";
12541   ASSERT_EQ(expect, got);
12542 }
12543 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Fallthrough_NotLastInCase_IsError)12544 TEST_F(SpvParserCFGTest,
12545        EmitBody_BranchConditional_Fallthrough_NotLastInCase_IsError) {
12546   // See also
12547   // ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError.
12548   auto p = parser(test::Assemble(CommonTypes() + R"(
12549      %100 = OpFunction %void None %voidfn
12550 
12551      %10 = OpLabel
12552      OpSelectionMerge %99 None
12553      OpSwitch %selector %99 20 %20 40 %40
12554 
12555      %20 = OpLabel ; case 30
12556      OpSelectionMerge %39 None
12557      OpBranchConditional %cond %40 %30 ; fallthrough and forward
12558 
12559      %30 = OpLabel
12560      OpBranch %39
12561 
12562      %39 = OpLabel
12563      OpBranch %99
12564 
12565      %40 = OpLabel  ; case 40
12566      OpBranch %99
12567 
12568      %99 = OpLabel
12569      OpReturn
12570 
12571      OpFunctionEnd
12572   )"));
12573   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12574   auto fe = p->function_emitter(100);
12575   EXPECT_FALSE(fe.EmitBody());
12576   // The weird forward branch pulls in 40 as part of the selection rather than
12577   // as a case.
12578   EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 30, 39, 99));
12579   EXPECT_THAT(
12580       p->error(),
12581       Eq("Branch from 10 to 40 bypasses header 20 (dominance rule violated)"));
12582 }
12583 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Forward_Forward_Same)12584 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Forward_Forward_Same) {
12585   auto p = parser(test::Assemble(CommonTypes() + R"(
12586      %100 = OpFunction %void None %voidfn
12587 
12588      %10 = OpLabel
12589      OpStore %var %uint_1
12590      OpBranchConditional %cond %99 %99; forward
12591 
12592      %99 = OpLabel
12593      OpStore %var %uint_2
12594      OpReturn
12595 
12596      OpFunctionEnd
12597   )"));
12598   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12599   auto fe = p->function_emitter(100);
12600   EXPECT_TRUE(fe.EmitBody()) << p->error();
12601   auto ast_body = fe.ast_body();
12602   auto got = test::ToString(p->program(), ast_body);
12603   auto* expect = R"(var_1 = 1u;
12604 var_1 = 2u;
12605 return;
12606 )";
12607   ASSERT_EQ(expect, got);
12608 }
12609 
TEST_F(SpvParserCFGTest,EmitBody_BranchConditional_Forward_Forward_Different_IsError)12610 TEST_F(SpvParserCFGTest,
12611        EmitBody_BranchConditional_Forward_Forward_Different_IsError) {
12612   auto p = parser(test::Assemble(CommonTypes() + R"(
12613      %100 = OpFunction %void None %voidfn
12614 
12615      %10 = OpLabel
12616      OpBranchConditional %cond %20 %99
12617 
12618      %20 = OpLabel
12619      OpReturn
12620 
12621      %99 = OpLabel
12622      OpStore %var %uint_2
12623      OpReturn
12624 
12625      OpFunctionEnd
12626   )"));
12627   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12628   auto fe = p->function_emitter(100);
12629   EXPECT_FALSE(fe.EmitBody());
12630   EXPECT_THAT(p->error(),
12631               Eq("Control flow diverges at block 10 (to 20, 99) but it is not "
12632                  "a structured header (it has no merge instruction)"));
12633 }
12634 
TEST_F(SpvParserCFGTest,Switch_NotAsSelectionHeader_Simple)12635 TEST_F(SpvParserCFGTest, Switch_NotAsSelectionHeader_Simple) {
12636   auto assembly = CommonTypes() + R"(
12637      %100 = OpFunction %void None %voidfn
12638 
12639      %10 = OpLabel
12640      OpSwitch %uint_0 %99
12641 
12642      %99 = OpLabel
12643      OpReturn
12644 
12645      OpFunctionEnd
12646 )";
12647   auto p = parser(test::Assemble(assembly));
12648   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12649   auto fe = p->function_emitter(100);
12650   EXPECT_FALSE(fe.EmitBody());
12651   EXPECT_THAT(
12652       p->error(),
12653       HasSubstr("invalid structured control flow: found an OpSwitch that "
12654                 "is not preceded by an OpSelectionMerge:"));
12655 }
12656 
TEST_F(SpvParserCFGTest,Switch_NotAsSelectionHeader_NonDefaultBranchesAreContinue)12657 TEST_F(SpvParserCFGTest,
12658        Switch_NotAsSelectionHeader_NonDefaultBranchesAreContinue) {
12659   // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
12660   auto p = parser(test::Assemble(CommonTypes() + R"(
12661  %100 = OpFunction %void None %voidfn
12662  %entry = OpLabel
12663  OpBranch %loop
12664  %loop = OpLabel
12665  OpLoopMerge %merge %cont None
12666  OpBranchConditional %cond %merge %b1
12667 
12668  ; Here an OpSwitch is used with only one "unseen-so-far" target
12669  ; so it doesn't need an OpSelectionMerge.
12670  ; The %cont target can be implemented via "continue". So we can
12671  ; generate:
12672  ;    if ((selector != 1) && (selector != 3)) { continue; }
12673  %b1 = OpLabel
12674  OpSwitch %selector %b2 0 %b2 1 %cont 2 %b2 3 %cont
12675 
12676  %b2 = OpLabel ; the one unseen target
12677  OpBranch %cont
12678  %cont = OpLabel
12679  OpBranchConditional %cond2 %merge %loop
12680  %merge = OpLabel
12681  OpReturn
12682  OpFunctionEnd
12683    )"));
12684   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12685   auto fe = p->function_emitter(100);
12686   EXPECT_FALSE(fe.EmitBody());
12687   EXPECT_THAT(
12688       p->error(),
12689       HasSubstr("invalid structured control flow: found an OpSwitch that "
12690                 "is not preceded by an OpSelectionMerge:"));
12691 }
12692 
TEST_F(SpvParserCFGTest,Switch_NotAsSelectionHeader_DefaultBranchIsContinue)12693 TEST_F(SpvParserCFGTest, Switch_NotAsSelectionHeader_DefaultBranchIsContinue) {
12694   // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
12695   auto p = parser(test::Assemble(CommonTypes() + R"(
12696  %100 = OpFunction %void None %voidfn
12697  %entry = OpLabel
12698  OpBranch %loop
12699  %loop = OpLabel
12700  OpLoopMerge %merge %cont None
12701  OpBranchConditional %cond %merge %b1
12702 
12703  ; Here an OpSwitch is used with only one "unseen-so-far" target
12704  ; so it doesn't need an OpSelectionMerge.
12705  ; The %cont target can be implemented via "continue". So we can
12706  ; generate:
12707  ;    if (!(selector == 0 || selector == 2)) {continue;}
12708  %b1 = OpLabel
12709  OpSwitch %selector %cont 0 %b2 1 %cont 2 %b2
12710 
12711  %b2 = OpLabel ; the one unseen target
12712  OpBranch %cont
12713  %cont = OpLabel
12714  OpBranchConditional %cond2 %merge %loop
12715  %merge = OpLabel
12716  OpReturn
12717  OpFunctionEnd
12718    )"));
12719   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12720   auto fe = p->function_emitter(100);
12721   EXPECT_FALSE(fe.EmitBody());
12722   EXPECT_THAT(
12723       p->error(),
12724       HasSubstr("invalid structured control flow: found an OpSwitch that "
12725                 "is not preceded by an OpSelectionMerge:"));
12726 }
12727 
TEST_F(SpvParserCFGTest,SiblingLoopConstruct_Null)12728 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_Null) {
12729   auto assembly = CommonTypes() + R"(
12730      %100 = OpFunction %void None %voidfn
12731      %10 = OpLabel
12732      OpReturn
12733      OpFunctionEnd
12734 )";
12735   auto p = parser(test::Assemble(assembly));
12736   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12737   auto fe = p->function_emitter(100);
12738   EXPECT_EQ(fe.SiblingLoopConstruct(nullptr), nullptr);
12739 }
12740 
TEST_F(SpvParserCFGTest,SiblingLoopConstruct_NotAContinue)12741 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_NotAContinue) {
12742   auto assembly = CommonTypes() + R"(
12743      %100 = OpFunction %void None %voidfn
12744 
12745      %10 = OpLabel
12746      OpReturn
12747 
12748      OpFunctionEnd
12749 )";
12750   auto p = parser(test::Assemble(assembly));
12751   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12752   auto fe = p->function_emitter(100);
12753   ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
12754   const Construct* c = fe.GetBlockInfo(10)->construct;
12755   EXPECT_NE(c, nullptr);
12756   EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
12757 }
12758 
TEST_F(SpvParserCFGTest,SiblingLoopConstruct_SingleBlockLoop)12759 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_SingleBlockLoop) {
12760   auto assembly = CommonTypes() + R"(
12761      %100 = OpFunction %void None %voidfn
12762 
12763      %10 = OpLabel
12764      OpBranch %20
12765 
12766      %20 = OpLabel
12767      OpLoopMerge %99 %20 None
12768      OpBranchConditional %cond %20 %99
12769 
12770      %99 = OpLabel
12771      OpReturn
12772 
12773      OpFunctionEnd
12774 )";
12775   auto p = parser(test::Assemble(assembly));
12776   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12777   auto fe = p->function_emitter(100);
12778   ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
12779   const Construct* c = fe.GetBlockInfo(20)->construct;
12780   EXPECT_EQ(c->kind, Construct::kContinue);
12781   EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
12782 }
12783 
TEST_F(SpvParserCFGTest,SiblingLoopConstruct_ContinueIsWholeMultiBlockLoop)12784 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_ContinueIsWholeMultiBlockLoop) {
12785   auto assembly = CommonTypes() + R"(
12786      %100 = OpFunction %void None %voidfn
12787 
12788      %10 = OpLabel
12789      OpBranch %20
12790 
12791      %20 = OpLabel
12792      OpLoopMerge %99 %20 None ; continue target is also loop header
12793      OpBranch %30
12794 
12795      %30 = OpLabel
12796      OpBranchConditional %cond %20 %99
12797 
12798      %99 = OpLabel
12799      OpReturn
12800 
12801      OpFunctionEnd
12802 )";
12803   auto p = parser(test::Assemble(assembly));
12804   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
12805       << p->error() << assembly;
12806   auto fe = p->function_emitter(100);
12807   ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
12808   const Construct* c = fe.GetBlockInfo(20)->construct;
12809   EXPECT_EQ(c->kind, Construct::kContinue);
12810   EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
12811 }
12812 
TEST_F(SpvParserCFGTest,SiblingLoopConstruct_HasSiblingLoop)12813 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_HasSiblingLoop) {
12814   auto assembly = CommonTypes() + R"(
12815      %100 = OpFunction %void None %voidfn
12816 
12817      %10 = OpLabel
12818      OpBranch %20
12819 
12820      %20 = OpLabel
12821      OpLoopMerge %99 %30 None
12822      OpBranchConditional %cond %30 %99
12823 
12824      %30 = OpLabel ; continue target
12825      OpBranch %20
12826 
12827      %99 = OpLabel
12828      OpReturn
12829 
12830      OpFunctionEnd
12831 )";
12832   auto p = parser(test::Assemble(assembly));
12833   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12834   auto fe = p->function_emitter(100);
12835   ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
12836   const Construct* c = fe.GetBlockInfo(30)->construct;
12837   EXPECT_EQ(c->kind, Construct::kContinue);
12838   EXPECT_THAT(ToString(fe.SiblingLoopConstruct(c)),
12839               Eq("Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 "
12840                  "parent:Function@10 scope:[1,3) in-l:Loop@20 }"));
12841 }
12842 
TEST_F(SpvParserCFGTest,EmitBody_IfSelection_TrueBranch_LoopBreak)12843 TEST_F(SpvParserCFGTest, EmitBody_IfSelection_TrueBranch_LoopBreak) {
12844   // crbug.com/tint/243
12845   auto assembly = CommonTypes() + R"(
12846      %100 = OpFunction %void None %voidfn
12847 
12848      %5 = OpLabel
12849      OpBranch %10
12850 
12851      %10 = OpLabel
12852      OpLoopMerge %99 %90 None
12853      OpBranch %20
12854 
12855      %20 = OpLabel
12856      OpSelectionMerge %40 None
12857      OpBranchConditional %cond %99 %30 ; true branch breaking is ok
12858 
12859      %30 = OpLabel
12860      OpBranch %40
12861 
12862      %40 = OpLabel ; selection merge
12863      OpBranch %90
12864 
12865      %90 = OpLabel ; continue target
12866      OpBranch %10 ; backedge
12867 
12868      %99 = OpLabel ; loop merge
12869      OpReturn
12870      OpFunctionEnd
12871 )";
12872   auto p = parser(test::Assemble(assembly));
12873   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12874   auto fe = p->function_emitter(100);
12875   EXPECT_TRUE(fe.EmitBody()) << p->error();
12876 
12877   auto ast_body = fe.ast_body();
12878   auto got = test::ToString(p->program(), ast_body);
12879   auto* expect = R"(loop {
12880   if (false) {
12881     break;
12882   }
12883 }
12884 return;
12885 )";
12886   ASSERT_EQ(expect, got);
12887 }
12888 
TEST_F(SpvParserCFGTest,EmitBody_TrueBranch_LoopContinue)12889 TEST_F(SpvParserCFGTest, EmitBody_TrueBranch_LoopContinue) {
12890   // crbug.com/tint/243
12891   auto assembly = CommonTypes() + R"(
12892      %100 = OpFunction %void None %voidfn
12893 
12894      %5 = OpLabel
12895      OpBranch %10
12896 
12897      %10 = OpLabel
12898      OpLoopMerge %99 %90 None
12899      OpBranch %20
12900 
12901      %20 = OpLabel
12902      OpSelectionMerge %40 None
12903      OpBranchConditional %cond %90 %30 ; true branch continue is ok
12904 
12905      %30 = OpLabel
12906      OpBranch %40
12907 
12908      %40 = OpLabel ; selection merge
12909      OpBranch %90
12910 
12911      %90 = OpLabel ; continue target
12912      OpBranch %10 ; backedge
12913 
12914      %99 = OpLabel ; loop merge
12915      OpReturn
12916 
12917      OpFunctionEnd
12918 )";
12919   auto p = parser(test::Assemble(assembly));
12920   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12921   auto fe = p->function_emitter(100);
12922   EXPECT_TRUE(fe.EmitBody()) << p->error();
12923   auto ast_body = fe.ast_body();
12924   auto got = test::ToString(p->program(), ast_body);
12925   auto* expect = R"(loop {
12926   if (false) {
12927     continue;
12928   }
12929 }
12930 return;
12931 )";
12932   ASSERT_EQ(expect, got);
12933 }
12934 
TEST_F(SpvParserCFGTest,EmitBody_TrueBranch_SwitchBreak)12935 TEST_F(SpvParserCFGTest, EmitBody_TrueBranch_SwitchBreak) {
12936   // crbug.com/tint/243
12937   auto assembly = CommonTypes() + R"(
12938      %100 = OpFunction %void None %voidfn
12939 
12940      %10 = OpLabel
12941      OpSelectionMerge %99 None
12942      OpSwitch %uint_20 %99 20 %20
12943 
12944      %20 = OpLabel
12945      OpSelectionMerge %40 None
12946      OpBranchConditional %cond %99 %30 ; true branch switch break is ok
12947 
12948      %30 = OpLabel
12949      OpBranch %40
12950 
12951      %40 = OpLabel ; if-selection merge
12952      OpBranch %99
12953 
12954      %99 = OpLabel ; switch merge
12955      OpReturn
12956 
12957      OpFunctionEnd
12958 )";
12959   auto p = parser(test::Assemble(assembly));
12960   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
12961   auto fe = p->function_emitter(100);
12962   EXPECT_TRUE(fe.EmitBody()) << p->error();
12963   auto ast_body = fe.ast_body();
12964   auto got = test::ToString(p->program(), ast_body);
12965   auto* expect = R"(switch(20u) {
12966   case 20u: {
12967     if (false) {
12968       break;
12969     }
12970   }
12971   default: {
12972   }
12973 }
12974 return;
12975 )";
12976   ASSERT_EQ(expect, got);
12977 }
12978 
TEST_F(SpvParserCFGTest,EmitBody_FalseBranch_LoopBreak)12979 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_LoopBreak) {
12980   // crbug.com/tint/243
12981   auto assembly = CommonTypes() + R"(
12982      %100 = OpFunction %void None %voidfn
12983 
12984      %5 = OpLabel
12985      OpBranch %10
12986 
12987      %10 = OpLabel
12988      OpLoopMerge %99 %90 None
12989      OpBranch %20
12990 
12991      %20 = OpLabel
12992      OpSelectionMerge %40 None
12993      OpBranchConditional %cond %30 %99 ; false branch breaking is ok
12994 
12995      %30 = OpLabel
12996      OpBranch %40
12997 
12998      %40 = OpLabel ; selection merge
12999      OpBranch %90
13000 
13001      %90 = OpLabel ; continue target
13002      OpBranch %10 ; backedge
13003 
13004      %99 = OpLabel ; loop merge
13005      OpReturn
13006 
13007      OpFunctionEnd
13008 )";
13009   auto p = parser(test::Assemble(assembly));
13010   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
13011   auto fe = p->function_emitter(100);
13012   EXPECT_TRUE(fe.EmitBody()) << p->error();
13013   auto ast_body = fe.ast_body();
13014   auto got = test::ToString(p->program(), ast_body);
13015   auto* expect = R"(loop {
13016   if (false) {
13017   } else {
13018     break;
13019   }
13020 }
13021 return;
13022 )";
13023   ASSERT_EQ(expect, got);
13024 }
13025 
TEST_F(SpvParserCFGTest,EmitBody_FalseBranch_LoopContinue)13026 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_LoopContinue) {
13027   // crbug.com/tint/243
13028   auto assembly = CommonTypes() + R"(
13029      %100 = OpFunction %void None %voidfn
13030 
13031      %5 = OpLabel
13032      OpBranch %10
13033 
13034      %10 = OpLabel
13035      OpLoopMerge %99 %90 None
13036      OpBranch %20
13037 
13038      %20 = OpLabel
13039      OpSelectionMerge %40 None
13040      OpBranchConditional %cond %30 %90 ; false branch continue is ok
13041 
13042      %30 = OpLabel
13043      OpBranch %40
13044 
13045      %40 = OpLabel ; selection merge
13046      OpBranch %90
13047 
13048      %90 = OpLabel ; continue target
13049      OpBranch %10 ; backedge
13050 
13051      %99 = OpLabel ; loop merge
13052      OpReturn
13053 
13054      OpFunctionEnd
13055 )";
13056   auto p = parser(test::Assemble(assembly));
13057   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
13058   auto fe = p->function_emitter(100);
13059   EXPECT_TRUE(fe.EmitBody()) << p->error();
13060   auto ast_body = fe.ast_body();
13061   auto got = test::ToString(p->program(), ast_body);
13062   auto* expect = R"(loop {
13063   if (false) {
13064   } else {
13065     continue;
13066   }
13067 }
13068 return;
13069 )";
13070   ASSERT_EQ(expect, got) << p->error();
13071 }
13072 
TEST_F(SpvParserCFGTest,EmitBody_FalseBranch_SwitchBreak)13073 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_SwitchBreak) {
13074   // crbug.com/tint/243
13075   auto assembly = CommonTypes() + R"(
13076      %100 = OpFunction %void None %voidfn
13077 
13078      %10 = OpLabel
13079      OpSelectionMerge %99 None
13080      OpSwitch %uint_20 %99 20 %20
13081 
13082      %20 = OpLabel
13083      OpSelectionMerge %40 None
13084      OpBranchConditional %cond %30 %99 ; false branch switch break is ok
13085 
13086      %30 = OpLabel
13087      OpBranch %40
13088 
13089      %40 = OpLabel ; if-selection merge
13090      OpBranch %99
13091 
13092      %99 = OpLabel ; switch merge
13093      OpReturn
13094 
13095      OpFunctionEnd
13096 )";
13097   auto p = parser(test::Assemble(assembly));
13098   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
13099   auto fe = p->function_emitter(100);
13100   EXPECT_TRUE(fe.EmitBody()) << p->error();
13101   auto ast_body = fe.ast_body();
13102   auto got = test::ToString(p->program(), ast_body);
13103   auto* expect = R"(switch(20u) {
13104   case 20u: {
13105     if (false) {
13106     } else {
13107       break;
13108     }
13109   }
13110   default: {
13111   }
13112 }
13113 return;
13114 )";
13115   ASSERT_EQ(expect, got);
13116 }
13117 
TEST_F(SpvParserCFGTest,EmitBody_LoopInternallyDiverge_Simple)13118 TEST_F(SpvParserCFGTest, EmitBody_LoopInternallyDiverge_Simple) {
13119   // crbug.com/tint/524
13120   auto assembly = CommonTypes() + R"(
13121      %100 = OpFunction %void None %voidfn
13122      %10 = OpLabel
13123      OpStore %var %uint_10
13124      OpBranch %20
13125 
13126      %20 = OpLabel
13127      OpStore %var %uint_20
13128      OpLoopMerge %99 %90 None
13129      OpBranchConditional %cond %30 %40 ; divergence
13130 
13131        %30 = OpLabel
13132        OpStore %var %uint_30
13133        OpBranch %90
13134 
13135        %40 = OpLabel
13136        OpStore %var %uint_40
13137        OpBranch %90
13138 
13139      %90 = OpLabel ; continue target
13140      OpStore %var %uint_90
13141      OpBranch %20
13142 
13143      %99 = OpLabel ; loop merge
13144      OpStore %var %uint_99
13145      OpReturn
13146 
13147      OpFunctionEnd
13148 )";
13149   auto p = parser(test::Assemble(assembly));
13150   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
13151   auto fe = p->function_emitter(100);
13152   EXPECT_TRUE(fe.EmitBody()) << p->error();
13153   auto ast_body = fe.ast_body();
13154   auto got = test::ToString(p->program(), ast_body);
13155   auto* expect = R"(var_1 = 10u;
13156 loop {
13157   var_1 = 20u;
13158   if (false) {
13159     var_1 = 30u;
13160     continue;
13161   } else {
13162     var_1 = 40u;
13163   }
13164 
13165   continuing {
13166     var_1 = 90u;
13167   }
13168 }
13169 var_1 = 99u;
13170 return;
13171 )";
13172   ASSERT_EQ(expect, got) << got;
13173 }
13174 
TEST_F(SpvParserCFGTest,EmitBody_ContinueFromSingleBlockLoopToOuterLoop_IsError)13175 TEST_F(SpvParserCFGTest,
13176        EmitBody_ContinueFromSingleBlockLoopToOuterLoop_IsError) {
13177   // crbug.com/tint/793
13178   // This is invalid SPIR-V but the validator was only recently upgraded
13179   // to catch it.
13180   auto assembly = CommonTypes() + R"(
13181   %100 = OpFunction %void None %voidfn
13182   %5 = OpLabel
13183   OpBranch %10
13184 
13185   %10 = OpLabel ; outer loop header
13186   OpLoopMerge %99 %89 None
13187   OpBranchConditional %cond %99 %20
13188 
13189   %20 = OpLabel ; inner loop single block loop
13190   OpLoopMerge %79 %20 None
13191 
13192   ; true -> continue to outer loop
13193   ; false -> self-loop
13194   ; The true branch is invalid because a "continue block", i.e. the block
13195   ; containing the branch to the continue target, "is valid only for the
13196   ; innermost loop it is nested inside of".
13197   ; So it can't branch to the continue target of an outer loop.
13198   OpBranchConditional %cond %89 %20
13199 
13200   %79 = OpLabel ; merge for outer loop
13201   OpUnreachable
13202 
13203   %89 = OpLabel
13204   OpBranch %10 ; backedge for outer loop
13205 
13206   %99 = OpLabel ; merge for outer
13207   OpReturn
13208 
13209   OpFunctionEnd
13210 
13211 )";
13212   auto p = parser(test::Assemble(assembly));
13213   EXPECT_FALSE(p->Parse());
13214   EXPECT_FALSE(p->success());
13215   EXPECT_THAT(p->error(),
13216               HasSubstr("block <ID> 20[%20] exits the continue headed by <ID> "
13217                         "20[%20], but not via a structured exit"))
13218       << p->error();
13219 }
13220 
13221 }  // namespace
13222 }  // namespace spirv
13223 }  // namespace reader
13224 }  // namespace tint
13225