#include #include // Include shader framework for CFG testing #include "shader/SpvConverter.hpp" #include "shader/analyze.hpp" #include "shader/dialect.hpp" #include "shader/ir.hpp" #include "shader/ir/Context.hpp" #include "shader/spv.hpp" #include "shader/transform.hpp" using namespace shader; using Builder = ir::Builder; class GcnShaderTest : public ::testing::Test { protected: void SetUp() override { // Setup SPIR-V context for CFG testing context = std::make_unique(); loc = context->getUnknownLocation(); trueV = context->getTrue(); falseV = context->getFalse(); } void TearDown() override { context.reset(); } ir::Value createLabel(const std::string &name) { auto builder = Builder::createAppend( *context, context->layout.getOrCreateFunctions(*context)); auto label = builder.createSpvLabel(loc); context->ns.setNameOf(label, name); return label; } void createBranch(ir::Value from, ir::Value to) { Builder::createInsertAfter(*context, from).createSpvBranch(loc, to); } void createConditionalBranch(ir::Value from, ir::Value a, ir::Value b) { Builder::createInsertAfter(*context, from) .createSpvBranchConditional(loc, trueV, a, b); } void createReturn(ir::Value from) { Builder::createInsertAfter(*context, from).createSpvReturn(loc); } void createSwitch(ir::Value from, std::span cases) { auto globals = Builder::createAppend( *context, context->layout.getOrCreateGlobals(*context)); auto globalVariable = globals.createSpvVariable( loc, context->getTypeUInt32(), ir::spv::StorageClass::Private, context->imm32(0)); auto switchOp = Builder::createInsertAfter(*context, from) .createSpvSwitch(loc, globalVariable, cases[0]); std::uint32_t i = 0; for (auto c : cases.subspan(1)) { switchOp.addOperand(i++); switchOp.addOperand(c); } } void createSwitchBranch(ir::Value from, ir::Value defaultTarget, const std::vector>& cases) { // Create a switch value (use a constant for testing) auto type = context->getTypeUInt32(); auto globals = Builder::createAppend( *context, context->layout.getOrCreateGlobals(*context)); auto globalVariable = globals.createSpvConstant( loc, type, 0); auto builder = Builder::createInsertAfter(*context, from); auto switchInst = builder.createSpvSwitch(loc, globalVariable, defaultTarget); // Add each case for (const auto& [value, target] : cases) { switchInst.addOperand(value); switchInst.addOperand(target); } } bool testStructurization() { auto region = context->layout.getOrCreateFunctions(*context); context->layout.regions[spv::BinaryLayout::kFunctions] = {}; auto functions = context->layout.getOrCreateFunctions(*context); structurizeCfg(*context, region); { auto debugs = Builder::createAppend( *context, context->layout.getOrCreateDebugs(*context)); 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)); } } inst.erase(); functions.addChild(inst); } } region = functions; auto entryLabel = region.getFirst().cast(); auto memModel = Builder::createAppend( *context, context->layout.getOrCreateMemoryModels(*context)); auto capabilities = Builder::createAppend( *context, context->layout.getOrCreateCapabilities(*context)); capabilities.createSpvCapability(loc, ir::spv::Capability::Shader); memModel.createSpvMemoryModel(loc, ir::spv::AddressingModel::Logical, ir::spv::MemoryModel::GLSL450); auto mainReturnT = context->getTypeVoid(); auto mainFnT = context->getTypeFunction(mainReturnT, {}); auto builder = Builder::createPrepend(*context, region); auto mainFn = builder.createSpvFunction( loc, mainReturnT, ir::spv::FunctionControl::None, mainFnT); builder.createSpvLabel(loc); builder.createSpvBranch(loc, entryLabel); Builder::createAppend(*context, region).createSpvFunctionEnd(loc); auto entryPoints = Builder::createAppend( *context, context->layout.getOrCreateEntryPoints(*context)); auto executionModes = Builder::createAppend( *context, context->layout.getOrCreateExecutionModes(*context)); executionModes.createSpvExecutionMode( mainFn.getLocation(), mainFn, ir::spv::ExecutionMode::LocalSize(1, 1, 1)); entryPoints.createSpvEntryPoint(mainFn.getLocation(), ir::spv::ExecutionModel::GLCompute, mainFn, "main", {}); auto spv = shader::spv::serialize(context->layout.merge(*context)); if (shader::spv::validate(spv)) { return true; } shader::spv::dump(spv, true); return false; } protected: std::unique_ptr context; ir::Location loc; ir::Value trueV; ir::Value falseV; }; TEST_F(GcnShaderTest, ProjectDivaTest1) { 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"); createBranch(_1, _2); createConditionalBranch(_2, _4, _3); createConditionalBranch(_3, _12, _11); createConditionalBranch(_4, _6, _5); createConditionalBranch(_5, _9, _8); createConditionalBranch(_6, _7, _8); createBranch(_7, _6); createBranch(_8, _3); createBranch(_9, _10); createBranch(_10, _7); createBranch(_11, _12); createBranch(_12, _13); createReturn(_13); 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); 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()); }