From 050f8bfe791a406fefa5e41a8f8d9dcdc1d31de9 Mon Sep 17 00:00:00 2001 From: DH Date: Thu, 4 Dec 2025 21:24:42 +0300 Subject: [PATCH] shader test: add generated tests + 2 real world tests & verify that structured CFG is well ordered --- test/gcn_shader_tests.cpp | 2107 +++++++++++++++++++++++++++++++++++-- 1 file changed, 2042 insertions(+), 65 deletions(-) diff --git a/test/gcn_shader_tests.cpp b/test/gcn_shader_tests.cpp index a928c4b13..65fc2a289 100644 --- a/test/gcn_shader_tests.cpp +++ b/test/gcn_shader_tests.cpp @@ -94,19 +94,15 @@ protected: auto debugs = Builder::createAppend( *context, context->layout.getOrCreateDebugs(*context)); - auto cfg = buildCFG(region.getFirst()); - for (auto node : cfg.getPreorderNodes()) { - auto value = node->getLabel(); - if (auto name = context->ns.tryGetNameOf(value); !name.empty()) { - debugs.createSpvName(loc, value, std::string(name)); + for (auto inst : region.children()) { + if (auto value = inst.cast()) { + if (auto name = context->ns.tryGetNameOf(value); !name.empty()) { + debugs.createSpvName(loc, value, std::string(name)); + } } - } - for (auto bb : cfg.getPreorderNodes()) { - for (auto child : bb->range()) { - child.erase(); - functions.addChild(child); - } + inst.erase(); + functions.addChild(inst); } } region = functions; @@ -184,7 +180,7 @@ TEST_F(GcnShaderTest, ProjectDivaTest1) { createConditionalBranch(_3, _12, _11); createConditionalBranch(_4, _6, _5); createConditionalBranch(_5, _9, _8); - createBranch(_6, _7); + createConditionalBranch(_6, _7, _8); createBranch(_7, _6); createBranch(_8, _3); createBranch(_9, _10); @@ -196,57 +192,2038 @@ TEST_F(GcnShaderTest, ProjectDivaTest1) { EXPECT_TRUE(testStructurization()); } -// TEST_F(GcnShaderTest, BatmanReturnToArkham1) { -// auto _1 = createLabel("1"); -// auto _2 = createLabel("2"); -// auto _3 = createLabel("3"); -// auto _4 = createLabel("4"); -// auto _5 = createLabel("5"); -// auto _6 = createLabel("6"); -// auto _7 = createLabel("7"); -// auto _8 = createLabel("8"); -// auto _9 = createLabel("9"); -// auto _10 = createLabel("10"); -// auto _11 = createLabel("11"); -// auto _12 = createLabel("12"); -// auto _13 = createLabel("13"); -// auto _14 = createLabel("14"); -// auto _15 = createLabel("15"); -// auto _16 = createLabel("16"); -// auto _17 = createLabel("17"); -// auto _18 = createLabel("18"); -// auto _19 = createLabel("19"); -// auto _20 = createLabel("20"); -// auto _21 = createLabel("21"); -// auto _22 = createLabel("22"); -// auto _23 = createLabel("23"); -// auto _24 = createLabel("24"); -// auto _25 = createLabel("25"); -// createBranch(_1, _2); -// createConditionalBranch(_2, _4, _3); -// createConditionalBranch(_3, _6, _5); -// createBranch(_4, _3); -// createConditionalBranch(_5, _8, _7); -// createBranch(_6, _5); -// createConditionalBranch(_7, _10, _9); -// createBranch(_8, _7); -// createConditionalBranch(_9, _12, _11); -// createBranch(_10, _9); -// createConditionalBranch(_11, _14, _13); -// createBranch(_12, _11); -// createConditionalBranch(_13, _16, _15); -// createBranch(_14, _13); -// createBranch(_15, _25); -// createConditionalBranch(_16, _18, _17); -// createBranch(_17, _18); -// createConditionalBranch(_18, _20, _19); -// createBranch(_19, _20); -// createConditionalBranch(_20, _22, _21); -// createBranch(_21, _22); -// createConditionalBranch(_22, _24, _23); -// createBranch(_23, _24); -// createBranch(_24, _15); -// createReturn(_25); +TEST_F(GcnShaderTest, BatmanReturnToArkham1) { + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + auto _4 = createLabel("4"); + auto _5 = createLabel("5"); + auto _6 = createLabel("6"); + auto _7 = createLabel("7"); + auto _8 = createLabel("8"); + auto _9 = createLabel("9"); + auto _10 = createLabel("10"); + auto _11 = createLabel("11"); + auto _12 = createLabel("12"); + auto _13 = createLabel("13"); + auto _14 = createLabel("14"); + auto _15 = createLabel("15"); + auto _16 = createLabel("16"); + auto _17 = createLabel("17"); + auto _18 = createLabel("18"); + auto _19 = createLabel("19"); + auto _20 = createLabel("20"); + auto _21 = createLabel("21"); + auto _22 = createLabel("22"); + auto _23 = createLabel("23"); + auto _24 = createLabel("24"); + auto _25 = createLabel("25"); + createBranch(_1, _2); + createConditionalBranch(_2, _4, _3); + createConditionalBranch(_3, _6, _5); + createBranch(_4, _3); + createConditionalBranch(_5, _8, _7); + createBranch(_6, _5); + createConditionalBranch(_7, _10, _9); + createBranch(_8, _7); + createConditionalBranch(_9, _12, _11); + createBranch(_10, _9); + createConditionalBranch(_11, _14, _13); + createBranch(_12, _11); + createConditionalBranch(_13, _16, _15); + createBranch(_14, _13); + createBranch(_15, _25); + createConditionalBranch(_16, _18, _17); + createBranch(_17, _18); + createConditionalBranch(_18, _20, _19); + createBranch(_19, _20); + createConditionalBranch(_20, _22, _21); + createBranch(_21, _22); + createConditionalBranch(_22, _24, _23); + createBranch(_23, _24); + createBranch(_24, _15); + createReturn(_25); -// EXPECT_TRUE(testStructurization()); -// } + EXPECT_TRUE(testStructurization()); +} + +TEST_F(GcnShaderTest, Shadow1) { + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + auto _4 = createLabel("4"); + auto _5 = createLabel("5"); + auto _6 = createLabel("6"); + auto _7 = createLabel("7"); + auto _8 = createLabel("8"); + auto _9 = createLabel("9"); + auto _10 = createLabel("10"); + auto _11 = createLabel("11"); + auto _12 = createLabel("12"); + auto _13 = createLabel("13"); + auto _14 = createLabel("14"); + auto _15 = createLabel("15"); + auto _16 = createLabel("16"); + auto _17 = createLabel("17"); + auto _18 = createLabel("18"); + auto _19 = createLabel("19"); + auto _20 = createLabel("20"); + auto _21 = createLabel("21"); + auto _22 = createLabel("22"); + auto _23 = createLabel("23"); + auto _24 = createLabel("24"); + auto _25 = createLabel("25"); + auto _26 = createLabel("26"); + auto _27 = createLabel("27"); + auto _28 = createLabel("28"); + auto _29 = createLabel("29"); + auto _30 = createLabel("30"); + auto _31 = createLabel("31"); + auto _32 = createLabel("32"); + auto _33 = createLabel("33"); + auto _34 = createLabel("34"); + auto _35 = createLabel("35"); + auto _36 = createLabel("36"); + auto _37 = createLabel("37"); + auto _38 = createLabel("38"); + auto _39 = createLabel("39"); + auto _40 = createLabel("40"); + auto _41 = createLabel("41"); + auto _42 = createLabel("42"); + auto _43 = createLabel("43"); + auto _44 = createLabel("44"); + auto _45 = createLabel("45"); + auto _46 = createLabel("46"); + auto _47 = createLabel("47"); + auto _48 = createLabel("48"); + auto _49 = createLabel("49"); + auto _50 = createLabel("50"); + auto _51 = createLabel("51"); + auto _52 = createLabel("52"); + auto _53 = createLabel("53"); + auto _54 = createLabel("54"); + auto _55 = createLabel("55"); + auto _56 = createLabel("56"); + auto _57 = createLabel("57"); + auto _58 = createLabel("58"); + auto _59 = createLabel("59"); + auto _60 = createLabel("60"); + auto _61 = createLabel("61"); + createBranch(_1, _2); + createConditionalBranch(_2, _4, _3); + createConditionalBranch(_3, _61, _60); + createConditionalBranch(_4, _6, _5); + createConditionalBranch(_5, _28, _27); + createConditionalBranch(_6, _8, _7); + createConditionalBranch(_7, _18, _17); + createConditionalBranch(_8, _10, _9); + createBranch(_9, _7); + createConditionalBranch(_10, _12, _11); + createBranch(_11, _7); + createConditionalBranch(_12, _14, _13); + createBranch(_13, _7); + createConditionalBranch(_14, _16, _15); + createBranch(_15, _7); + createBranch(_16, _15); + createConditionalBranch(_17, _20, _19); + createBranch(_18, _5); + createBranch(_19, _5); + createConditionalBranch(_20, _22, _21); + createBranch(_21, _5); + createConditionalBranch(_22, _24, _23); + createBranch(_23, _21); + createConditionalBranch(_24, _26, _25); + createBranch(_25, _21); + createBranch(_26, _25); + createConditionalBranch(_27, _30, _29); + createBranch(_28, _27); + createConditionalBranch(_29, _50, _49); + createConditionalBranch(_30, _32, _31); + createConditionalBranch(_31, _29, _3); + createConditionalBranch(_32, _34, _33); + createConditionalBranch(_33, _48, _3); + createConditionalBranch(_34, _36, _35); + createConditionalBranch(_35, _47, _3); + createConditionalBranch(_36, _38, _37); + createConditionalBranch(_37, _46, _3); + createConditionalBranch(_38, _40, _39); + createConditionalBranch(_39, _45, _3); + createConditionalBranch(_40, _42, _41); + createConditionalBranch(_41, _44, _3); + createConditionalBranch(_42, _43, _3); + createBranch(_43, _29); + createBranch(_44, _29); + createBranch(_45, _29); + createBranch(_46, _29); + createBranch(_47, _29); + createBranch(_48, _29); + createConditionalBranch(_49, _58, _57); + createConditionalBranch(_50, _52, _51); + createConditionalBranch(_51, _49, _3); + createConditionalBranch(_52, _54, _53); + createConditionalBranch(_53, _56, _3); + createConditionalBranch(_54, _55, _3); + createBranch(_55, _49); + createBranch(_56, _49); + createBranch(_57, _58); + createBranch(_58, _59); + createReturn(_59); + createBranch(_60, _61); + createBranch(_61, _59); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test conditional CFG structurization + */ +TEST_F(GcnShaderTest, ConditionalCfgStructurization) { + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + auto _4 = createLabel("4"); + + // Build conditional CFG: 1 -> if(2,3), 2 -> 4, 3 -> 4 + createConditionalBranch(_1, _2, _3); + createBranch(_2, _4); + createBranch(_3, _4); + createReturn(_4); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop CFG structurization + */ +TEST_F(GcnShaderTest, LoopCfgStructurization) { + // Create simple loop: 1 -> 2 -> conditional back to 1 or forward to 3 + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + + createBranch(_1, _2); + createConditionalBranch(_2, _1, _3); + createReturn(_3); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test that new implementation doesn't crash with complex patterns + */ +TEST_F(GcnShaderTest, ComplexPatternResilience) { + // Create a more complex CFG and ensure it doesn't crash + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + + createBranch(_1, _2); + createBranch(_2, _3); + createReturn(_3); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test academic algorithm forward goto transformation + */ +TEST_F(GcnShaderTest, ForwardGotoTransformation) { + // Test the academic algorithm's handling of forward gotos + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + + createBranch(_1, _2); + createReturn(_2); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test nested loops CFG + */ +TEST_F(GcnShaderTest, NestedLoopCfgStructurization) { + auto entry = createLabel("entry"); + auto outer_loop = createLabel("outer_loop"); + auto inner_loop = createLabel("inner_loop"); + auto inner_body = createLabel("inner_body"); + auto exit = createLabel("exit"); + + // Build nested loop CFG + createBranch(entry, outer_loop); + createConditionalBranch(outer_loop, inner_loop, exit); + createConditionalBranch(inner_loop, outer_loop, inner_body); + createConditionalBranch(inner_body, inner_loop, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +TEST_F(GcnShaderTest, LoopWithHeaderCfgStructurization) { + // Create nested loops: outer -> inner -> inner_body -> inner (back), inner + // -> outer (back), outer -> exit + + auto outer_loop = createLabel("outer_loop"); + auto inner_loop = createLabel("inner_loop"); + auto inner_body = createLabel("inner_body"); + auto exit = createLabel("exit"); + + // Build nested loop CFG + createBranch(outer_loop, inner_loop); + createConditionalBranch(inner_loop, outer_loop, inner_body); + createConditionalBranch(inner_body, inner_loop, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test irreducible CFG (multiple entry loop) + */ +TEST_F(GcnShaderTest, IrreducibleCfgStructurization) { + // Create irreducible: entry -> if(A, B), A -> C, B -> C, C -> if(A, exit) + + auto entry = createLabel("entry"); + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, A, B); + createBranch(A, C); + createBranch(B, C); + createConditionalBranch(C, A, exit); // Back edge to A + createReturn(exit); + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch-like CFG + */ +TEST_F(GcnShaderTest, SwitchLikeCfgStructurization) { + // Create switch-like: entry -> if(case1, case2), case1 -> merge, case2 -> + // if(case3, merge), case3 -> merge + auto entry = createLabel("entry"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto merge = createLabel("merge"); + + createConditionalBranch(entry, case1, case2); + createBranch(case1, merge); + createConditionalBranch(case2, case3, merge); + createBranch(case3, merge); + createReturn(merge); + EXPECT_TRUE(testStructurization()); +} + +/** + * Test academic algorithm data structures (verify no regression) + */ +TEST_F(GcnShaderTest, AcademicAlgorithmDataStructures) { + // Create a basic CFG and ensure structure is created + auto _1 = createLabel("1"); + auto _2 = createLabel("2"); + auto _3 = createLabel("3"); + auto _4 = createLabel("4"); + + createBranch(_1, _2); + createReturn(_2); + + createBranch(_3, _4); + createReturn(_4); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test deeply nested loops (3 levels) + */ +TEST_F(GcnShaderTest, DeeplyNestedLoops) { + auto outer = createLabel("outer"); + auto middle = createLabel("middle"); + auto inner = createLabel("inner"); + auto body = createLabel("body"); + auto exit = createLabel("exit"); + + createBranch(outer, middle); + createConditionalBranch(middle, inner, outer); // middle can exit to outer + createConditionalBranch(inner, body, middle); // inner can exit to middle + createConditionalBranch(body, inner, exit); // body loops back or exits + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with multiple exits + */ +TEST_F(GcnShaderTest, LoopWithMultipleExits) { + auto header = createLabel("header"); + auto body1 = createLabel("body1"); + auto body2 = createLabel("body2"); + auto exit1 = createLabel("exit1"); + auto exit2 = createLabel("exit2"); + auto final_exit = createLabel("final_exit"); + + createConditionalBranch(header, body1, body2); + createConditionalBranch(body1, header, exit1); // loop or exit + createConditionalBranch(body2, header, exit2); // loop or exit + createBranch(exit1, final_exit); + createBranch(exit2, final_exit); + createReturn(final_exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with early return from inner block + */ +TEST_F(GcnShaderTest, LoopWithEarlyReturn) { + auto header = createLabel("header"); + auto check = createLabel("check"); + auto body = createLabel("body"); + auto exit = createLabel("exit"); + + createBranch(header, check); + createConditionalBranch(check, body, exit); + createConditionalBranch(body, header, exit); // loop back or return + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test irreducible CFG with multiple entry points + */ +TEST_F(GcnShaderTest, IrreducibleMultipleEntry) { + auto entry = createLabel("entry"); + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto D = createLabel("D"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, A, B); + createBranch(A, C); + createBranch(B, D); + createConditionalBranch(C, D, A); // C can go to D or back to A + createConditionalBranch(D, C, exit); // D can go to C or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch-like structure with fall-through + */ +TEST_F(GcnShaderTest, SwitchWithFallthrough) { + auto entry = createLabel("entry"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto default_case = createLabel("default"); + auto merge = createLabel("merge"); + + createConditionalBranch(entry, case1, case2); + createConditionalBranch(case1, case3, merge); // case1 can fall through + createBranch(case2, case3); // case2 falls through + createConditionalBranch(case3, default_case, merge); + createBranch(default_case, merge); + createReturn(merge); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with break and continue + */ +TEST_F(GcnShaderTest, LoopWithBreakContinue) { + auto header = createLabel("header"); + auto condition = createLabel("condition"); + auto body = createLabel("body"); + auto continue_block = createLabel("continue_block"); + auto exit = createLabel("exit"); + + createBranch(header, condition); + createConditionalBranch(condition, body, exit); // condition check + createConditionalBranch(body, continue_block, exit); // break or continue + createBranch(continue_block, header); // continue - back to header + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test diamond pattern inside loop + */ +TEST_F(GcnShaderTest, DiamondInLoop) { + auto header = createLabel("header"); + auto diamond_entry = createLabel("diamond_entry"); + auto left = createLabel("left"); + auto right = createLabel("right"); + auto diamond_merge = createLabel("diamond_merge"); + auto exit = createLabel("exit"); + + createBranch(header, diamond_entry); + createConditionalBranch(diamond_entry, left, right); + createBranch(left, diamond_merge); + createBranch(right, diamond_merge); + createConditionalBranch(diamond_merge, header, exit); // loop or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop inside diamond + */ +TEST_F(GcnShaderTest, LoopInDiamond) { + auto entry = createLabel("entry"); + auto left_branch = createLabel("left_branch"); + auto right_branch = createLabel("right_branch"); + auto loop_header = createLabel("loop_header"); + auto loop_body = createLabel("loop_body"); + auto merge = createLabel("merge"); + + createConditionalBranch(entry, left_branch, right_branch); + createBranch(left_branch, loop_header); + createBranch(right_branch, merge); + createConditionalBranch(loop_header, loop_body, merge); + createBranch(loop_body, loop_header); // loop back + createReturn(merge); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test crossing edges pattern + */ +TEST_F(GcnShaderTest, CrossingEdges) { + auto entry = createLabel("entry"); + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto D = createLabel("D"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, A, B); + createConditionalBranch(A, C, D); // A goes to C or D + createConditionalBranch(B, D, C); // B goes to D or C (crossing) + createBranch(C, exit); + createBranch(D, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test multiple nested loops with shared exit + */ +TEST_F(GcnShaderTest, MultipleLoopsSharedExit) { + auto entry = createLabel("entry"); + auto loop1_header = createLabel("loop1_header"); + auto loop1_body = createLabel("loop1_body"); + auto loop2_header = createLabel("loop2_header"); + auto loop2_body = createLabel("loop2_body"); + auto shared_exit = createLabel("shared_exit"); + + createConditionalBranch(entry, loop1_header, loop2_header); + createConditionalBranch(loop1_header, loop1_body, shared_exit); + createBranch(loop1_body, loop1_header); + createConditionalBranch(loop2_header, loop2_body, shared_exit); + createBranch(loop2_body, loop2_header); + createReturn(shared_exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test while-do-while combined pattern + */ +TEST_F(GcnShaderTest, WhileDoWhileCombined) { + auto entry = createLabel("entry"); + auto while_check = createLabel("while_check"); + auto while_body = createLabel("while_body"); + auto do_body = createLabel("do_body"); + auto do_check = createLabel("do_check"); + auto exit = createLabel("exit"); + + createBranch(entry, while_check); + createConditionalBranch(while_check, while_body, exit); + createBranch(while_body, do_body); + createBranch(do_body, do_check); + createConditionalBranch(do_check, do_body, + while_check); // do-while + back to while + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with exception-like exit + */ +TEST_F(GcnShaderTest, LoopWithExceptionExit) { + auto header = createLabel("header"); + auto try_block = createLabel("try_block"); + auto catch_block = createLabel("catch_block"); + auto normal_exit = createLabel("normal_exit"); + auto exception_exit = createLabel("exception_exit"); + auto final_exit = createLabel("final_exit"); + + createBranch(header, try_block); + createConditionalBranch(try_block, header, catch_block); // loop or exception + createConditionalBranch(catch_block, normal_exit, exception_exit); + createBranch(normal_exit, final_exit); + createBranch(exception_exit, final_exit); + createReturn(final_exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test figure-8 pattern (two interconnected loops) + */ +TEST_F(GcnShaderTest, Figure8Pattern) { + auto entry = createLabel("entry"); + auto loop1_header = createLabel("loop1_header"); + auto loop1_body = createLabel("loop1_body"); + auto loop2_header = createLabel("loop2_header"); + auto loop2_body = createLabel("loop2_body"); + auto exit = createLabel("exit"); + + createBranch(entry, loop1_header); + createConditionalBranch(loop1_header, loop1_body, exit); + createConditionalBranch(loop1_body, loop1_header, + loop2_header); // to loop1 or loop2 + createConditionalBranch(loop2_header, loop2_body, exit); + createConditionalBranch(loop2_body, loop2_header, + loop1_header); // to loop2 or loop1 + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test complex irreducible with 4-node cycle + */ +TEST_F(GcnShaderTest, ComplexIrreducible4Node) { + auto entry = createLabel("entry"); + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto D = createLabel("D"); + auto exit = createLabel("exit"); + + createBranch(entry, A); + createConditionalBranch(A, B, C); + createBranch(B, D); + createConditionalBranch(C, D, A); // back to A + createConditionalBranch(D, B, exit); // back to B or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test nested loops with cross-loop edges + */ +TEST_F(GcnShaderTest, NestedLoopsWithCrossEdges) { + auto outer_header = createLabel("outer_header"); + auto outer_body = createLabel("outer_body"); + auto inner_header = createLabel("inner_header"); + auto inner_body = createLabel("inner_body"); + auto cross_block = createLabel("cross_block"); + auto exit = createLabel("exit"); + + createBranch(outer_header, outer_body); + createConditionalBranch(outer_body, inner_header, cross_block); + createConditionalBranch(inner_header, inner_body, + outer_header); // inner to outer + createConditionalBranch(inner_body, inner_header, + cross_block); // inner loop or cross + createConditionalBranch(cross_block, outer_header, + exit); // back to outer or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test parallel diamond patterns + */ +TEST_F(GcnShaderTest, ParallelDiamonds) { + auto entry = createLabel("entry"); + auto diamond1_entry = createLabel("diamond1_entry"); + auto diamond1_left = createLabel("diamond1_left"); + auto diamond1_right = createLabel("diamond1_right"); + auto diamond1_merge = createLabel("diamond1_merge"); + auto diamond2_entry = createLabel("diamond2_entry"); + auto diamond2_left = createLabel("diamond2_left"); + auto diamond2_right = createLabel("diamond2_right"); + auto diamond2_merge = createLabel("diamond2_merge"); + auto final_merge = createLabel("final_merge"); + + createConditionalBranch(entry, diamond1_entry, diamond2_entry); + + // Diamond 1 + createConditionalBranch(diamond1_entry, diamond1_left, diamond1_right); + createBranch(diamond1_left, diamond1_merge); + createBranch(diamond1_right, diamond1_merge); + createBranch(diamond1_merge, final_merge); + + // Diamond 2 + createConditionalBranch(diamond2_entry, diamond2_left, diamond2_right); + createBranch(diamond2_left, diamond2_merge); + createBranch(diamond2_right, diamond2_merge); + createBranch(diamond2_merge, final_merge); + + createReturn(final_merge); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with internal switch + */ +TEST_F(GcnShaderTest, LoopWithInternalSwitch) { + auto header = createLabel("header"); + auto switch_entry = createLabel("switch_entry"); + auto case_a = createLabel("case_a"); + auto case_b = createLabel("case_b"); + auto case_c = createLabel("case_c"); + auto switch_merge = createLabel("switch_merge"); + auto exit = createLabel("exit"); + + createBranch(header, switch_entry); + createConditionalBranch(switch_entry, case_a, case_b); + createConditionalBranch(case_a, case_c, switch_merge); + createBranch(case_b, switch_merge); + createBranch(case_c, switch_merge); + createConditionalBranch(switch_merge, header, exit); // loop or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test deeply nested conditionals + */ +TEST_F(GcnShaderTest, DeeplyNestedConditionals) { + auto entry = createLabel("entry"); + auto cond1 = createLabel("cond1"); + auto cond2 = createLabel("cond2"); + auto cond3 = createLabel("cond3"); + auto leaf1 = createLabel("leaf1"); + auto leaf2 = createLabel("leaf2"); + auto leaf3 = createLabel("leaf3"); + auto leaf4 = createLabel("leaf4"); + auto merge3 = createLabel("merge3"); + auto merge2 = createLabel("merge2"); + auto merge1 = createLabel("merge1"); + + createConditionalBranch(entry, cond1, merge1); + createConditionalBranch(cond1, cond2, merge2); + createConditionalBranch(cond2, cond3, merge3); + createConditionalBranch(cond3, leaf1, leaf2); + createBranch(leaf1, merge3); + createBranch(leaf2, merge3); + createBranch(merge3, leaf3); + createBranch(leaf3, merge2); + createBranch(merge2, leaf4); + createBranch(leaf4, merge1); + createReturn(merge1); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with multiple latches + */ +TEST_F(GcnShaderTest, LoopWithMultipleLatches) { + auto header = createLabel("header"); + auto branch_point = createLabel("branch_point"); + auto latch1 = createLabel("latch1"); + auto latch2 = createLabel("latch2"); + auto body = createLabel("body"); + auto exit = createLabel("exit"); + + createBranch(header, branch_point); + createConditionalBranch(branch_point, latch1, latch2); + createConditionalBranch(latch1, header, body); // latch1 can loop back + createConditionalBranch(latch2, header, body); // latch2 can loop back + createBranch(body, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test triangular loop pattern + */ +TEST_F(GcnShaderTest, TriangularLoop) { + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto exit = createLabel("exit"); + + createConditionalBranch(A, B, exit); + createConditionalBranch(B, C, A); // B to C or back to A + createConditionalBranch(C, A, exit); // C back to A or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with nested exception handling + */ +TEST_F(GcnShaderTest, LoopWithNestedExceptionHandling) { + auto header = createLabel("header"); + auto try_outer = createLabel("try_outer"); + auto try_inner = createLabel("try_inner"); + auto catch_inner = createLabel("catch_inner"); + auto catch_outer = createLabel("catch_outer"); + auto finally_block = createLabel("finally_block"); + auto exit = createLabel("exit"); + + createBranch(header, try_outer); + createConditionalBranch(try_outer, try_inner, catch_outer); + createConditionalBranch(try_inner, finally_block, catch_inner); + createBranch(catch_inner, finally_block); + createBranch(catch_outer, finally_block); + createConditionalBranch(finally_block, header, exit); // loop or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test hourglass pattern (two diamonds connected) + */ +TEST_F(GcnShaderTest, HourglassPattern) { + auto entry = createLabel("entry"); + auto top_left = createLabel("top_left"); + auto top_right = createLabel("top_right"); + auto middle = createLabel("middle"); + auto bottom_left = createLabel("bottom_left"); + auto bottom_right = createLabel("bottom_right"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, top_left, top_right); + createBranch(top_left, middle); + createBranch(top_right, middle); + createConditionalBranch(middle, bottom_left, bottom_right); + createBranch(bottom_left, exit); + createBranch(bottom_right, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with break to outer scope + */ +TEST_F(GcnShaderTest, LoopWithBreakToOuter) { + auto outer_header = createLabel("outer_header"); + auto inner_header = createLabel("inner_header"); + auto inner_body = createLabel("inner_body"); + auto break_check = createLabel("break_check"); + auto outer_continue = createLabel("outer_continue"); + auto exit = createLabel("exit"); + + createBranch(outer_header, inner_header); + createConditionalBranch(inner_header, inner_body, outer_continue); + createBranch(inner_body, break_check); + createConditionalBranch(break_check, inner_header, + exit); // continue inner or break outer + createBranch(outer_continue, outer_header); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test complex switch with nested loops + */ +TEST_F(GcnShaderTest, ComplexSwitchWithNestedLoops) { + auto entry = createLabel("entry"); + auto switch_header = createLabel("switch_header"); + auto case1_loop = createLabel("case1_loop"); + auto case1_body = createLabel("case1_body"); + auto case2_loop = createLabel("case2_loop"); + auto case2_body = createLabel("case2_body"); + auto switch_exit = createLabel("switch_exit"); + + createBranch(entry, switch_header); + createConditionalBranch(switch_header, case1_loop, case2_loop); + + // Case 1 with loop + createConditionalBranch(case1_loop, case1_body, switch_exit); + createBranch(case1_body, case1_loop); + + // Case 2 with loop + createConditionalBranch(case2_loop, case2_body, switch_exit); + createBranch(case2_body, case2_loop); + + createReturn(switch_exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test ladder pattern (sequential conditions) + */ +TEST_F(GcnShaderTest, LadderPattern) { + auto entry = createLabel("entry"); + auto check1 = createLabel("check1"); + auto check2 = createLabel("check2"); + auto check3 = createLabel("check3"); + auto action1 = createLabel("action1"); + auto action2 = createLabel("action2"); + auto action3 = createLabel("action3"); + auto final_action = createLabel("final_action"); + auto exit = createLabel("exit"); + + createBranch(entry, check1); + createConditionalBranch(check1, action1, check2); + createBranch(action1, final_action); + createConditionalBranch(check2, action2, check3); + createBranch(action2, final_action); + createConditionalBranch(check3, action3, final_action); + createBranch(action3, final_action); + createBranch(final_action, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test spiral pattern (increasing complexity) + */ +TEST_F(GcnShaderTest, SpiralPattern) { + auto center = createLabel("center"); + auto ring1 = createLabel("ring1"); + auto ring2 = createLabel("ring2"); + auto ring3 = createLabel("ring3"); + auto connector1 = createLabel("connector1"); + auto connector2 = createLabel("connector2"); + auto exit = createLabel("exit"); + + createConditionalBranch(center, ring1, exit); + createConditionalBranch(ring1, ring2, connector1); + createConditionalBranch(ring2, ring3, connector2); + createConditionalBranch(ring3, center, exit); // spiral back to center + createBranch(connector1, center); + createBranch(connector2, ring1); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test binary tree traversal pattern + */ +TEST_F(GcnShaderTest, BinaryTreeTraversal) { + auto root = createLabel("root"); + auto left_subtree = createLabel("left_subtree"); + auto right_subtree = createLabel("right_subtree"); + auto left_leaf = createLabel("left_leaf"); + auto right_leaf = createLabel("right_leaf"); + auto process_left = createLabel("process_left"); + auto process_right = createLabel("process_right"); + auto merge = createLabel("merge"); + + createConditionalBranch(root, left_subtree, right_subtree); + createConditionalBranch(left_subtree, left_leaf, process_left); + createConditionalBranch(right_subtree, right_leaf, process_right); + createBranch(left_leaf, merge); + createBranch(right_leaf, merge); + createBranch(process_left, merge); + createBranch(process_right, merge); + createReturn(merge); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test state machine pattern + */ +TEST_F(GcnShaderTest, StateMachine) { + auto init_state = createLabel("init_state"); + auto state_a = createLabel("state_a"); + auto state_b = createLabel("state_b"); + auto state_c = createLabel("state_c"); + auto transition = createLabel("transition"); + auto final_state = createLabel("final_state"); + + createBranch(init_state, state_a); + createConditionalBranch(state_a, state_b, transition); + createConditionalBranch(state_b, state_c, state_a); // B to C or back to A + createConditionalBranch(state_c, state_a, final_state); // C to A or final + createConditionalBranch(transition, state_b, final_state); + createReturn(final_state); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test mesh pattern (highly connected) + */ +TEST_F(GcnShaderTest, MeshPattern) { + auto node1 = createLabel("node1"); + auto node2 = createLabel("node2"); + auto node3 = createLabel("node3"); + auto node4 = createLabel("node4"); + auto hub = createLabel("hub"); + auto exit = createLabel("exit"); + + createConditionalBranch(node1, node2, node3); + createConditionalBranch(node2, node4, hub); + createConditionalBranch(node3, node4, hub); + createConditionalBranch(node4, node1, hub); // back to node1 + createConditionalBranch(hub, node1, exit); // back to node1 or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test pipeline pattern (sequential stages) + */ +TEST_F(GcnShaderTest, PipelinePattern) { + auto input_stage = createLabel("input_stage"); + auto process_stage1 = createLabel("process_stage1"); + auto process_stage2 = createLabel("process_stage2"); + auto process_stage3 = createLabel("process_stage3"); + auto output_stage = createLabel("output_stage"); + auto error_handler = createLabel("error_handler"); + auto retry = createLabel("retry"); + auto exit = createLabel("exit"); + + createBranch(input_stage, process_stage1); + createConditionalBranch(process_stage1, process_stage2, error_handler); + createConditionalBranch(process_stage2, process_stage3, error_handler); + createConditionalBranch(process_stage3, output_stage, error_handler); + createBranch(output_stage, exit); + createConditionalBranch(error_handler, retry, exit); + createBranch(retry, input_stage); // retry from beginning + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test fractal-like recursive pattern + */ +TEST_F(GcnShaderTest, FractalPattern) { + auto entry = createLabel("entry"); + auto level1 = createLabel("level1"); + auto level2 = createLabel("level2"); + auto level3 = createLabel("level3"); + auto recurse_check = createLabel("recurse_check"); + auto base_case = createLabel("base_case"); + auto combine = createLabel("combine"); + auto exit = createLabel("exit"); + + createBranch(entry, level1); + createConditionalBranch(level1, level2, recurse_check); + createConditionalBranch(level2, level3, base_case); + createConditionalBranch(level3, base_case, combine); + createConditionalBranch(recurse_check, level1, combine); // recurse or combine + createBranch(base_case, combine); + createConditionalBranch(combine, level1, exit); // recurse again or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test butterfly pattern (symmetric branches that cross) + */ +TEST_F(GcnShaderTest, ButterflyPattern) { + auto entry = createLabel("entry"); + auto wing1_top = createLabel("wing1_top"); + auto wing1_bottom = createLabel("wing1_bottom"); + auto wing2_top = createLabel("wing2_top"); + auto wing2_bottom = createLabel("wing2_bottom"); + auto body_center = createLabel("body_center"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, wing1_top, wing2_top); + createConditionalBranch(wing1_top, wing2_bottom, + body_center); // cross pattern + createConditionalBranch(wing2_top, wing1_bottom, + body_center); // cross pattern + createBranch(wing1_bottom, exit); + createBranch(wing2_bottom, exit); + createBranch(body_center, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test nested try-catch with multiple exception types + */ +TEST_F(GcnShaderTest, NestedTryCatchMultipleExceptions) { + auto entry = createLabel("entry"); + auto try_outer = createLabel("try_outer"); + auto try_inner = createLabel("try_inner"); + auto risky_operation = createLabel("risky_operation"); + auto catch_type1 = createLabel("catch_type1"); + auto catch_type2 = createLabel("catch_type2"); + auto catch_all = createLabel("catch_all"); + auto finally_inner = createLabel("finally_inner"); + auto finally_outer = createLabel("finally_outer"); + auto success = createLabel("success"); + auto exit = createLabel("exit"); + + createBranch(entry, try_outer); + createBranch(try_outer, try_inner); + createBranch(try_inner, risky_operation); + createConditionalBranch(risky_operation, success, catch_type1); + createConditionalBranch(catch_type1, finally_inner, catch_type2); + createConditionalBranch(catch_type2, finally_inner, catch_all); + createBranch(catch_all, finally_inner); + createBranch(success, finally_inner); + createBranch(finally_inner, finally_outer); + createBranch(finally_outer, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test producer-consumer pattern + */ +TEST_F(GcnShaderTest, ProducerConsumerPattern) { + auto entry = createLabel("entry"); + auto producer = createLabel("producer"); + auto buffer_check = createLabel("buffer_check"); + auto consumer = createLabel("consumer"); + auto process_item = createLabel("process_item"); + auto sync_point = createLabel("sync_point"); + auto exit = createLabel("exit"); + + createConditionalBranch(entry, producer, consumer); + createBranch(producer, buffer_check); + createConditionalBranch(buffer_check, consumer, + producer); // buffer full, switch + createBranch(consumer, process_item); + createConditionalBranch(process_item, sync_point, + consumer); // process or continue + createConditionalBranch(sync_point, producer, exit); // sync or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test multi-level break pattern + */ +TEST_F(GcnShaderTest, MultiLevelBreakPattern) { + auto outer_loop = createLabel("outer_loop"); + auto middle_loop = createLabel("middle_loop"); + auto inner_loop = createLabel("inner_loop"); + auto inner_body = createLabel("inner_body"); + auto break_check = createLabel("break_check"); + auto middle_continue = createLabel("middle_continue"); + auto outer_continue = createLabel("outer_continue"); + auto exit = createLabel("exit"); + + createBranch(outer_loop, middle_loop); + createBranch(middle_loop, inner_loop); + createBranch(inner_loop, inner_body); + createBranch(inner_body, break_check); + createConditionalBranch(break_check, inner_loop, + middle_continue); // continue inner or break + createConditionalBranch(middle_continue, middle_loop, + outer_continue); // continue middle or break + createConditionalBranch(outer_continue, outer_loop, + exit); // continue outer or exit + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test parallel processing pattern + */ +TEST_F(GcnShaderTest, ParallelProcessingPattern) { + auto entry = createLabel("entry"); + auto fork_point = createLabel("fork_point"); + auto thread1 = createLabel("thread1"); + auto thread2 = createLabel("thread2"); + auto thread3 = createLabel("thread3"); + auto work1 = createLabel("work1"); + auto work2 = createLabel("work2"); + auto work3 = createLabel("work3"); + auto barrier = createLabel("barrier"); + auto join_point = createLabel("join_point"); + auto exit = createLabel("exit"); + + createBranch(entry, fork_point); + createConditionalBranch(fork_point, thread1, thread2); + createConditionalBranch(thread1, work1, thread3); + createBranch(thread2, work2); + createBranch(thread3, work3); + createBranch(work1, barrier); + createBranch(work2, barrier); + createBranch(work3, barrier); + createBranch(barrier, join_point); + createBranch(join_point, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test recursive descent parser pattern + */ +TEST_F(GcnShaderTest, RecursiveDescentParser) { + auto parse_expression = createLabel("parse_expression"); + auto parse_term = createLabel("parse_term"); + auto parse_factor = createLabel("parse_factor"); + auto parse_number = createLabel("parse_number"); + auto parse_parentheses = createLabel("parse_parentheses"); + auto operator_check = createLabel("operator_check"); + auto success = createLabel("success"); + auto error = createLabel("error"); + auto exit = createLabel("exit"); + + createBranch(parse_expression, parse_term); + createConditionalBranch(parse_term, parse_factor, operator_check); + createConditionalBranch(parse_factor, parse_number, parse_parentheses); + createBranch(parse_number, success); + createConditionalBranch(parse_parentheses, parse_expression, + error); // recursive call + createConditionalBranch(operator_check, parse_term, + success); // continue parsing + createBranch(success, exit); + createBranch(error, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test pathological irreducible CFG (worst case) + */ +TEST_F(GcnShaderTest, PathologicalIrreducibleCFG) { + auto entry = createLabel("entry"); + auto A = createLabel("A"); + auto B = createLabel("B"); + auto C = createLabel("C"); + auto D = createLabel("D"); + auto E = createLabel("E"); + auto F = createLabel("F"); + auto exit = createLabel("exit"); + + // Create a highly irreducible pattern where multiple nodes can reach multiple + // nodes + createConditionalBranch(entry, A, B); + createConditionalBranch(A, C, D); + createConditionalBranch(B, D, E); + createConditionalBranch(C, E, exit); + createConditionalBranch(D, F, A); // back to A + createConditionalBranch(E, A, B); // back to A or B + createConditionalBranch(F, B, C); // back to B or C + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop with computed goto simulation + */ +TEST_F(GcnShaderTest, ComputedGotoSimulation) { + auto entry = createLabel("entry"); + auto dispatch_table = createLabel("dispatch_table"); + auto target1 = createLabel("target1"); + auto target2 = createLabel("target2"); + auto target3 = createLabel("target3"); + auto target4 = createLabel("target4"); + auto merge_point = createLabel("merge_point"); + auto loop_back = createLabel("loop_back"); + auto exit = createLabel("exit"); + + createBranch(entry, dispatch_table); + createConditionalBranch(dispatch_table, target1, target2); + createConditionalBranch(target1, target3, merge_point); + createConditionalBranch(target2, target4, merge_point); + createBranch(target3, merge_point); + createBranch(target4, merge_point); + createConditionalBranch(merge_point, loop_back, exit); + createBranch(loop_back, dispatch_table); // computed goto loop + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test coroutine-like pattern with yield points + */ +TEST_F(GcnShaderTest, CoroutineLikePattern) { + auto entry = createLabel("entry"); + auto state_machine = createLabel("state_machine"); + auto yield_point1 = createLabel("yield_point1"); + auto work1 = createLabel("work1"); + auto yield_point2 = createLabel("yield_point2"); + auto work2 = createLabel("work2"); + auto yield_point3 = createLabel("yield_point3"); + auto final_work = createLabel("final_work"); + auto exit = createLabel("exit"); + + createBranch(entry, state_machine); + createConditionalBranch(state_machine, yield_point1, yield_point2); + createBranch(yield_point1, work1); + createConditionalBranch(work1, state_machine, + yield_point2); // yield or continue + createBranch(yield_point2, work2); + createConditionalBranch(work2, state_machine, + yield_point3); // yield or continue + createBranch(yield_point3, final_work); + createConditionalBranch(final_work, state_machine, exit); // yield or complete + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test extreme nesting depth (stress test) + */ +TEST_F(GcnShaderTest, ExtremeNestingDepth) { + auto level0 = createLabel("level0"); + auto level1 = createLabel("level1"); + auto level2 = createLabel("level2"); + auto level3 = createLabel("level3"); + auto level4 = createLabel("level4"); + auto level5 = createLabel("level5"); + auto level6 = createLabel("level6"); + auto level7 = createLabel("level7"); + auto level8 = createLabel("level8"); + auto level9 = createLabel("level9"); + auto deep_core = createLabel("deep_core"); + auto unwind = createLabel("unwind"); + auto exit = createLabel("exit"); + + // Create deeply nested structure + createConditionalBranch(level0, level1, unwind); + createConditionalBranch(level1, level2, unwind); + createConditionalBranch(level2, level3, unwind); + createConditionalBranch(level3, level4, unwind); + createConditionalBranch(level4, level5, unwind); + createConditionalBranch(level5, level6, unwind); + createConditionalBranch(level6, level7, unwind); + createConditionalBranch(level7, level8, unwind); + createConditionalBranch(level8, level9, unwind); + createConditionalBranch(level9, deep_core, unwind); + createConditionalBranch(deep_core, level0, exit); // back to top or exit + createBranch(unwind, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +// ========================= COMPREHENSIVE SWITCH PATTERN TESTS +// ========================= + +/** + * Test simple switch with 3 cases + */ +TEST_F(GcnShaderTest, SimpleSwitch3Cases) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + createBranch(case0, exit); + createBranch(case1, exit); + createBranch(case2, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with fallthrough patterns + */ +TEST_F(GcnShaderTest, SwitchWithFallthroughPattern) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{0, case0}, {1, case1}, {2, case2}, {3, case3}}); + createBranch(case0, case1); // fallthrough + createBranch(case1, case2); // fallthrough + createBranch(case2, exit); // break + createBranch(case3, exit); // break + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with mixed fallthrough and breaks + */ +TEST_F(GcnShaderTest, SwitchMixedFallthroughBreaks) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto case4 = createLabel("case4"); + auto exit = createLabel("exit"); + + createSwitchBranch( + entry, exit, + {{0, case0}, {1, case1}, {2, case2}, {3, case3}, {4, case4}}); + createBranch(case0, exit); // break + createBranch(case1, case2); // fallthrough + createBranch(case2, case3); // fallthrough + createBranch(case3, exit); // break + createBranch(case4, exit); // break + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test large switch with 10 cases + */ +TEST_F(GcnShaderTest, LargeSwitch10Cases) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto case4 = createLabel("case4"); + auto case5 = createLabel("case5"); + auto case6 = createLabel("case6"); + auto case7 = createLabel("case7"); + auto case8 = createLabel("case8"); + auto case9 = createLabel("case9"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{0, case0}, + {1, case1}, + {2, case2}, + {3, case3}, + {4, case4}, + {5, case5}, + {6, case6}, + {7, case7}, + {8, case8}, + {9, case9}}); + createBranch(case0, exit); + createBranch(case1, exit); + createBranch(case2, exit); + createBranch(case3, exit); + createBranch(case4, exit); + createBranch(case5, exit); + createBranch(case6, exit); + createBranch(case7, exit); + createBranch(case8, exit); + createBranch(case9, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test very large switch with 25 cases + */ +TEST_F(GcnShaderTest, VeryLargeSwitch25Cases) { + auto entry = createLabel("entry"); + std::vector cases; + for (int i = 0; i < 25; i++) { + cases.push_back(createLabel("case" + std::to_string(i))); + } + auto exit = createLabel("exit"); + + // Create switch with 25 cases + std::vector> switch_cases; + for (int i = 0; i < 25; i++) { + switch_cases.push_back({i, cases[i]}); + } + createSwitchBranch(entry, exit, switch_cases); + + // Each case branches to exit + for (auto case_label : cases) { + createBranch(case_label, exit); + } + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test huge switch with 50 cases + */ +TEST_F(GcnShaderTest, HugeSwitch50Cases) { + auto entry = createLabel("entry"); + std::vector cases; + for (int i = 0; i < 50; i++) { + cases.push_back(createLabel("case" + std::to_string(i))); + } + auto exit = createLabel("exit"); + + // Create switch with 50 cases + std::vector> switch_cases; + for (int i = 0; i < 50; i++) { + switch_cases.push_back({i, cases[i]}); + } + createSwitchBranch(entry, exit, switch_cases); + + // Each case branches to exit + for (auto case_label : cases) { + createBranch(case_label, exit); + } + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test massive switch with 100 cases + */ +TEST_F(GcnShaderTest, MassiveSwitch100Cases) { + auto entry = createLabel("entry"); + std::vector cases; + for (int i = 0; i < 100; i++) { + cases.push_back(createLabel("case" + std::to_string(i))); + } + auto exit = createLabel("exit"); + + // Create switch with 100 cases + std::vector> switch_cases; + for (int i = 0; i < 100; i++) { + switch_cases.push_back({i, cases[i]}); + } + createSwitchBranch(entry, exit, switch_cases); + + // Each case branches to exit + for (auto case_label : cases) { + createBranch(case_label, exit); + } + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with nested conditionals in cases + */ +TEST_F(GcnShaderTest, SwitchWithNestedConditionals) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto nested_true_0 = createLabel("nested_true_0"); + auto nested_false_0 = createLabel("nested_false_0"); + auto nested_true_1 = createLabel("nested_true_1"); + auto nested_false_1 = createLabel("nested_false_1"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Case 0 has nested conditional + createConditionalBranch(case0, nested_true_0, nested_false_0); + createBranch(nested_true_0, exit); + createBranch(nested_false_0, exit); + + // Case 1 has nested conditional + createConditionalBranch(case1, nested_true_1, nested_false_1); + createBranch(nested_true_1, exit); + createBranch(nested_false_1, exit); + + // Case 2 is simple + createBranch(case2, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with nested loops in cases + */ +TEST_F(GcnShaderTest, SwitchWithNestedLoops) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto loop_body_0 = createLabel("loop_body_0"); + auto loop_body_1 = createLabel("loop_body_1"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Case 0 has a loop + createConditionalBranch(case0, loop_body_0, exit); + createConditionalBranch(loop_body_0, case0, exit); // loop back + + // Case 1 has a loop + createConditionalBranch(case1, loop_body_1, exit); + createConditionalBranch(loop_body_1, case1, exit); // loop back + + // Case 2 is simple + createBranch(case2, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with sparse case values + */ +TEST_F(GcnShaderTest, SwitchWithSparseCases) { + auto entry = createLabel("entry"); + auto case1 = createLabel("case1"); + auto case10 = createLabel("case10"); + auto case50 = createLabel("case50"); + auto case100 = createLabel("case100"); + auto case999 = createLabel("case999"); + auto exit = createLabel("exit"); + + createSwitchBranch( + entry, exit, + {{1, case1}, {10, case10}, {50, case50}, {100, case100}, {999, case999}}); + createBranch(case1, exit); + createBranch(case10, exit); + createBranch(case50, exit); + createBranch(case100, exit); + createBranch(case999, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with negative case values + */ +TEST_F(GcnShaderTest, SwitchWithNegativeCases) { + auto entry = createLabel("entry"); + auto case_neg10 = createLabel("case_neg10"); + auto case_neg5 = createLabel("case_neg5"); + auto case0 = createLabel("case0"); + auto case5 = createLabel("case5"); + auto case10 = createLabel("case10"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{-10, case_neg10}, + {-5, case_neg5}, + {0, case0}, + {5, case5}, + {10, case10}}); + createBranch(case_neg10, exit); + createBranch(case_neg5, exit); + createBranch(case0, exit); + createBranch(case5, exit); + createBranch(case10, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch inside loop + */ +TEST_F(GcnShaderTest, SwitchInsideLoop) { + auto entry = createLabel("entry"); + auto loop_header = createLabel("loop_header"); + auto switch_block = createLabel("switch_block"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto loop_continue = createLabel("loop_continue"); + auto exit = createLabel("exit"); + + createBranch(entry, loop_header); + createConditionalBranch(loop_header, switch_block, exit); + + createSwitchBranch(switch_block, loop_continue, + {{0, case0}, {1, case1}, {2, case2}}); + createBranch(case0, loop_continue); + createBranch(case1, exit); // break from loop + createBranch(case2, loop_continue); + + createBranch(loop_continue, loop_header); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test loop inside switch case + */ +TEST_F(GcnShaderTest, LoopInsideSwitchCase) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto loop_header = createLabel("loop_header"); + auto loop_body = createLabel("loop_body"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Case 0 is simple + createBranch(case0, exit); + + // Case 1 contains a loop + createBranch(case1, loop_header); + createConditionalBranch(loop_header, loop_body, exit); + createConditionalBranch(loop_body, loop_header, exit); + + // Case 2 is simple + createBranch(case2, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test nested switches + */ +TEST_F(GcnShaderTest, NestedSwitches) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto inner_case0 = createLabel("inner_case0"); + auto inner_case1 = createLabel("inner_case1"); + auto inner_case2 = createLabel("inner_case2"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Case 0 is simple + createBranch(case0, exit); + + // Case 1 contains nested switch + createSwitchBranch(case1, exit, + {{0, inner_case0}, {1, inner_case1}, {2, inner_case2}}); + createBranch(inner_case0, exit); + createBranch(inner_case1, exit); + createBranch(inner_case2, exit); + + // Case 2 is simple + createBranch(case2, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with complex fallthrough chain + */ +TEST_F(GcnShaderTest, SwitchComplexFallthroughChain) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto case4 = createLabel("case4"); + auto case5 = createLabel("case5"); + auto case6 = createLabel("case6"); + auto case7 = createLabel("case7"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{0, case0}, + {1, case1}, + {2, case2}, + {3, case3}, + {4, case4}, + {5, case5}, + {6, case6}, + {7, case7}}); + + // Complex fallthrough pattern: 0->1->2, 3->break, 4->5->6->7, 7->break + createBranch(case0, case1); // fallthrough + createBranch(case1, case2); // fallthrough + createBranch(case2, exit); // break + createBranch(case3, exit); // break + createBranch(case4, case5); // fallthrough + createBranch(case5, case6); // fallthrough + createBranch(case6, case7); // fallthrough + createBranch(case7, exit); // break + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with cross-case jumps (goto simulation) + */ +TEST_F(GcnShaderTest, SwitchWithCrossCaseJumps) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto shared_code = createLabel("shared_code"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{0, case0}, {1, case1}, {3, case3}, {2, case2}}); + + // Cases can jump to shared code or each other + createBranch(case0, shared_code); + createBranch(case1, case3); // jump to case 3 + createBranch(case2, shared_code); + createBranch(case3, exit); + createBranch(shared_code, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with multiple shared exit points + */ +TEST_F(GcnShaderTest, SwitchMultipleSharedExits) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto exit1 = createLabel("exit1"); + auto exit2 = createLabel("exit2"); + auto final_exit = createLabel("final_exit"); + + createSwitchBranch(entry, final_exit, + {{0, case0}, {1, case1}, {2, case2}, {3, case3}}); + + // Cases branch to different exit points + createBranch(case0, exit1); + createBranch(case1, exit1); + createBranch(case2, exit2); + createBranch(case3, exit2); + + createBranch(exit1, final_exit); + createBranch(exit2, final_exit); + createReturn(final_exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with return statements in cases + */ +TEST_F(GcnShaderTest, SwitchWithReturns) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto case3 = createLabel("case3"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, + {{0, case0}, {1, case1}, {2, case2}, {3, case3}}); + + // Some cases return directly, others continue + createReturn(case0); // direct return + createBranch(case1, exit); + createReturn(case2); // direct return + createBranch(case3, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with exception-like jumps + */ +TEST_F(GcnShaderTest, SwitchWithExceptionJumps) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto normal_flow = createLabel("normal_flow"); + auto exception_handler = createLabel("exception_handler"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Cases can either continue normally or jump to exception handler + createConditionalBranch(case0, normal_flow, exception_handler); + createConditionalBranch(case1, normal_flow, exception_handler); + createBranch(case2, normal_flow); + + createBranch(normal_flow, exit); + createBranch(exception_handler, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch-based state machine + */ +TEST_F(GcnShaderTest, SwitchBasedStateMachine) { + auto entry = createLabel("entry"); + auto header = createLabel("header"); + auto state_machine = createLabel("state_machine"); + auto state0 = createLabel("state0"); + auto state1 = createLabel("state1"); + auto state2 = createLabel("state2"); + auto state3 = createLabel("state3"); + auto update_state = createLabel("update_state"); + auto exit = createLabel("exit"); + + createBranch(entry, header); + + // State machine loop + createConditionalBranch(header, exit, state_machine); // continue condition + createSwitchBranch(state_machine, exit, + {{0, state0}, {1, state1}, {2, state2}, {3, state3}}); + + // Each state processes and transitions + createBranch(state0, update_state); + createBranch(state1, update_state); + createBranch(state2, update_state); + createBranch(state3, exit); // final state + + createBranch(update_state, state_machine); // loop back + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with computed jump table simulation + */ +TEST_F(GcnShaderTest, SwitchComputedJumpTable) { + auto entry = createLabel("entry"); + auto compute_index = createLabel("compute_index"); + auto jump_table = createLabel("jump_table"); + auto target0 = createLabel("target0"); + auto target1 = createLabel("target1"); + auto target2 = createLabel("target2"); + auto target3 = createLabel("target3"); + auto target4 = createLabel("target4"); + auto merge = createLabel("merge"); + auto exit = createLabel("exit"); + + createBranch(entry, compute_index); + createBranch(compute_index, jump_table); + + // Jump table with 5 targets + createSwitchBranch( + jump_table, merge, + {{0, target0}, {1, target1}, {2, target2}, {3, target3}, {4, target4}}); + + // Each target does some work then merges + createBranch(target0, merge); + createBranch(target1, merge); + createBranch(target2, merge); + createBranch(target3, merge); + createBranch(target4, merge); + + createBranch(merge, exit); + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test switch with interleaved loops and conditionals + */ +TEST_F(GcnShaderTest, SwitchInterleavedLoopsConditionals) { + auto entry = createLabel("entry"); + auto case0 = createLabel("case0"); + auto case1 = createLabel("case1"); + auto case2 = createLabel("case2"); + auto loop0 = createLabel("loop0"); + auto cond0 = createLabel("cond0"); + auto loop1 = createLabel("loop1"); + auto exit = createLabel("exit"); + + createSwitchBranch(entry, exit, {{0, case0}, {1, case1}, {2, case2}}); + + // Case 0: loop then conditional + createBranch(case0, loop0); + createConditionalBranch(loop0, loop0, cond0); // loop + createConditionalBranch(cond0, exit, exit); + + // Case 1: conditional then loop + createConditionalBranch(case1, loop1, exit); + createConditionalBranch(loop1, loop1, exit); // loop + + // Case 2: simple exit + createBranch(case2, exit); + + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test ultra-large switch with 200 cases (stress test) + */ +TEST_F(GcnShaderTest, UltraLargeSwitch200Cases) { + auto entry = createLabel("entry"); + std::vector cases; + for (int i = 0; i < 200; i++) { + cases.push_back(createLabel("case" + std::to_string(i))); + } + auto exit = createLabel("exit"); + + // Create switch with 200 cases + std::vector> switch_cases; + for (int i = 0; i < 200; i++) { + switch_cases.push_back({i, cases[i]}); + } + createSwitchBranch(entry, exit, switch_cases); + + // Each case branches to exit (simple to focus on switch complexity) + for (auto case_label : cases) { + createBranch(case_label, exit); + } + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +} + +/** + * Test mega switch with 500 cases (ultimate stress test) + */ +TEST_F(GcnShaderTest, MegaSwitch500Cases) { + auto entry = createLabel("entry"); + std::vector cases; + for (int i = 0; i < 500; i++) { + cases.push_back(createLabel("case" + std::to_string(i))); + } + auto exit = createLabel("exit"); + + // Create switch with 500 cases + std::vector> switch_cases; + for (int i = 0; i < 500; i++) { + switch_cases.push_back({i, cases[i]}); + } + createSwitchBranch(entry, exit, switch_cases); + + // Each case branches to exit + for (auto case_label : cases) { + createBranch(case_label, exit); + } + createReturn(exit); + + EXPECT_TRUE(testStructurization()); +}