// Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include #include "TestContext.hpp" #include #include #include #include #include #include using namespace rocRoller; using namespace Catch::Matchers; namespace ScheduleMultiplyAndLDSTest { TEST_CASE("ScheduleMultiplyAndLDS handles empty graph", "[kernel-graph][graph-transforms][schedule-multiply-lds]") { using namespace rocRoller::KernelGraph::ControlGraph; rocRoller::KernelGraph::KernelGraph graph; auto kernel = graph.control.addElement(Kernel()); // Apply transform on graph with no multiply or LDS nodes auto transformedGraph = rocRoller::KernelGraph::ScheduleMultiplyAndLDS().apply(graph); // Graph structure should be unchanged CHECK(transformedGraph.control.getNodes().to().size() == graph.control.getNodes().to().size()); } TEST_CASE("ScheduleMultiplyAndLDS creates sequence edges between Multiply and LoadLDSTile", "[kernel-graph][graph-transforms][schedule-multiply-lds]") { using namespace rocRoller::KernelGraph; auto dataTypeAB = GENERATE(DataType::Float, DataType::FP4); DYNAMIC_SECTION("dataTypeAB=" << dataTypeAB) { auto dataTypeCD = dataTypeAB == DataType::Float ? DataType::Float : DataType::Half; auto example = rocRollerTest::Graphs::GEMM(dataTypeAB, dataTypeAB, dataTypeCD, dataTypeCD); auto context = TestContext::ForDefaultTarget(); example.setUseLDS(true, true, false); example.setPrefetch(true, 2, 1, true); if(dataTypeAB == DataType::Float) { example.setMFMA(32, 32, 2, 1); example.setTileSize(128, 128, 16); } else { example.setTileSize(128, 128, 256); example.setMFMA(16, 16, 128, 1); example.setScaling(Operations::ScaleMode::Separate, Operations::ScaleMode::Separate, DataType::E8M0, DataType::E8M0, 32); example.setScaleLoadPaths(SolutionParams::LoadPath::BufferToLDS, SolutionParams::LoadPath::BufferToLDS); } auto graph = example.getKernelGraph(); auto params = example.getCommandParameters(); // Apply full transform pipeline up to ScheduleMultiplyAndLDS graph = transform(graph); graph = transform(graph, true); graph = transform(graph, params); graph = transform(graph, params, context.get()); graph = transform(graph, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph, params, context.get()); graph = transform(graph); graph = transform(graph); graph = transform(graph); // Get nodes and edges before applying ScheduleMultiplyAndLDS auto multiplyNodesBefore = graph.control.getNodes().to(); auto ldsNodesBefore = graph.control.getNodes().to(); REQUIRE(!multiplyNodesBefore.empty()); REQUIRE(!ldsNodesBefore.empty()); // Count Sequence edges before auto sequenceEdgesBefore = graph.control.getEdges() .filter([&](auto edge) { return graph.control.get(edge).has_value(); }) .to() .size(); // Apply ScheduleMultiplyAndLDS auto transformedGraph = transform(graph); // Get nodes and edges after transformation auto multiplyNodesAfter = transformedGraph.control.getNodes().to(); auto ldsNodesAfter = transformedGraph.control.getNodes().to(); // Verify multiply and LDS nodes are preserved CHECK(multiplyNodesAfter == multiplyNodesBefore); CHECK(ldsNodesAfter == ldsNodesBefore); // Count Sequence edges after auto sequenceEdgesAfter = transformedGraph.control.getEdges() .filter([&](auto edge) { return transformedGraph.control.get(edge) .has_value(); }) .to() .size(); // Verify new Sequence edges were created CHECK(sequenceEdgesAfter > sequenceEdgesBefore); // Verify that some Multiply nodes now have Sequence edges to LoadLDSTile nodes bool foundMultiplyToLDSEdge = false; for(auto multiplyNode : multiplyNodesAfter) { auto sequenceTargets = transformedGraph.control .getOutputNodeIndices(multiplyNode) .to(); for(auto target : sequenceTargets) { if(transformedGraph.control.get(target).has_value() || transformedGraph.control.get(target) .has_value()) { foundMultiplyToLDSEdge = true; break; } } if(foundMultiplyToLDSEdge) break; } CHECK(foundMultiplyToLDSEdge); } } } // namespace ScheduleMultiplyAndLDSTest