Files
TheRock/rocm-libraries/shared/rocroller/test/catch/ScheduleMultiplyAndLDSDetailTest.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

661 lines
25 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <common/SourceMatcher.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/KernelGraph/Transforms/ScheduleMultiplyAndLDS_detail.hpp>
#include <rocRoller/KernelGraph/Utils.hpp>
using namespace rocRoller;
using namespace rocRoller::KernelGraph;
using namespace Catch::Matchers;
namespace ScheduleMultiplyAndLDSDetailTest
{
using namespace ScheduleMultiplyAndLDSDetail;
namespace CF = rocRoller::KernelGraph::ControlGraph;
namespace CT = rocRoller::KernelGraph::CoordinateGraph;
TEST_CASE("toString formats DataType count map", "[kernel-graph][schedule-multiply-lds]")
{
SECTION("Empty map")
{
std::map<DataType, int> typeCounts;
auto result = toString(typeCounts);
CHECK(result == "[]");
}
SECTION("Single type")
{
std::map<DataType, int> typeCounts;
typeCounts[DataType::Float] = 2;
auto result = toString(typeCounts);
CHECK_THAT(result, ContainsSubstring("Float"));
CHECK_THAT(result, ContainsSubstring("2"));
}
SECTION("Multiple types")
{
std::map<DataType, int> typeCounts;
typeCounts[DataType::Float] = 2;
typeCounts[DataType::Half] = 3;
auto result = toString(typeCounts);
CHECK_THAT(result, ContainsSubstring("Float"));
CHECK_THAT(result, ContainsSubstring("2"));
CHECK_THAT(result, ContainsSubstring("Half"));
CHECK_THAT(result, ContainsSubstring("3"));
}
}
TEST_CASE("toString formats ChainTypes", "[kernel-graph][schedule-multiply-lds]")
{
SECTION("Empty ChainTypes")
{
ChainTypes chainTypes;
auto result = toString(chainTypes);
CHECK(result == "{}");
}
SECTION("Single chain with type counts")
{
ChainTypes chainTypes;
std::map<DataType, int> typeCounts;
typeCounts[DataType::Float] = 1;
chainTypes.push_back(typeCounts);
auto result = toString(chainTypes);
CHECK_THAT(result, ContainsSubstring("Float"));
}
}
TEST_CASE("showChain formats node vector", "[kernel-graph][schedule-multiply-lds]")
{
SECTION("Empty chain")
{
Chain chain;
auto result = showChain(chain);
CHECK(result == "()");
}
SECTION("Single node")
{
Chain chain = {42};
auto result = showChain(chain);
CHECK(result == "(42)");
}
SECTION("Multiple nodes")
{
Chain chain = {1, 2, 3};
auto result = showChain(chain);
CHECK(result == "(1, 2, 3)");
}
}
TEST_CASE("showChains formats vector of chains", "[kernel-graph][schedule-multiply-lds]")
{
SECTION("Empty chains")
{
Chains chains;
auto result = showChains(chains);
CHECK(result == "");
}
SECTION("Single chain")
{
Chains chains = {{1, 2, 3}};
auto result = showChains(chains);
CHECK_THAT(result, ContainsSubstring("1"));
CHECK_THAT(result, ContainsSubstring("2"));
CHECK_THAT(result, ContainsSubstring("3"));
}
SECTION("Multiple chains")
{
Chains chains = {{1, 2}, {3, 4, 5}};
auto result = showChains(chains);
CHECK_THAT(result, ContainsSubstring("1"));
CHECK_THAT(result, ContainsSubstring("2"));
CHECK_THAT(result, ContainsSubstring("3"));
CHECK_THAT(result, ContainsSubstring("4"));
CHECK_THAT(result, ContainsSubstring("5"));
}
}
TEST_CASE("showGroups formats groups of chains", "[kernel-graph][schedule-multiply-lds]")
{
SECTION("Empty groups")
{
Groups groups;
auto result = showGroups(groups);
CHECK_THAT(result, ContainsSubstring("0 groups"));
}
SECTION("Single group")
{
Groups groups = {{{1, 2, 3}}};
auto result = showGroups(groups);
CHECK_THAT(result, ContainsSubstring("1 groups"));
CHECK_THAT(result, ContainsSubstring("1"));
CHECK_THAT(result, ContainsSubstring("2"));
CHECK_THAT(result, ContainsSubstring("3"));
}
SECTION("Multiple groups")
{
Groups groups = {{{1, 2}}, {{3, 4, 5}}};
auto result = showGroups(groups);
CHECK_THAT(result, ContainsSubstring("2 groups"));
}
}
TEST_CASE("makeChains identifies linear chains", "[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Empty input returns empty")
{
std::vector<int> nodes;
auto chains = makeChains(graph, nodes);
CHECK(chains.empty());
}
SECTION("Single node creates single chain")
{
auto node1 = graph.control.addElement(CF::Multiply());
std::vector<int> nodes = {node1};
auto chains = makeChains(graph, nodes);
REQUIRE(chains.size() == 1);
CHECK(chains[0].size() == 1);
CHECK(chains[0][0] == node1);
}
SECTION("Connected chain of multiply nodes")
{
// Create 4 multiply nodes connected in sequence
auto node1 = graph.control.addElement(CF::Multiply());
auto node2 = graph.control.addElement(CF::Multiply());
auto node3 = graph.control.addElement(CF::Multiply());
auto node4 = graph.control.addElement(CF::Multiply());
graph.control.addElement(CF::Sequence(), {node1}, {node2});
graph.control.addElement(CF::Sequence(), {node2}, {node3});
graph.control.addElement(CF::Sequence(), {node3}, {node4});
std::vector<int> nodes = {node1, node2, node3, node4};
auto chains = makeChains(graph, nodes);
CHECK(chains == Chains{{node1, node2, node3, node4}});
}
SECTION("Two disconnected chains")
{
auto kernel = graph.control.addElement(CF::Kernel());
// Create first chain: 1 -> 2 -> 3
auto node1 = graph.control.addElement(CF::Multiply());
auto node2 = graph.control.addElement(CF::Multiply());
auto node3 = graph.control.addElement(CF::Multiply());
graph.control.addElement(CF::Body(), {kernel}, {node1});
graph.control.addElement(CF::Body(), {kernel}, {node1});
graph.control.chain<CF::Sequence>(node1, node2, node3);
auto nop = graph.control.addElement(CF::NOP());
// Create second chain: 5 -> 6 -> 7
auto node5 = graph.control.addElement(CF::Multiply());
auto node6 = graph.control.addElement(CF::Multiply());
auto node7 = graph.control.addElement(CF::Multiply());
graph.control.chain<CF::Sequence>(node3, nop, node5);
graph.control.chain<CF::Sequence>(node5, node6, node7);
std::vector<int> nodes = {node1, node2, node3, node5, node6, node7};
auto chains = makeChains(graph, nodes);
CHECK(chains == Chains{{node1, node2, node3}, {node5, node6, node7}});
}
}
TEST_CASE("getLDSNode follows SetCoordinate body edges",
"[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Direct LDS node returns itself")
{
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
auto result = getLDSNode(graph, ldsNode);
CHECK(result == ldsNode);
}
SECTION("SetCoordinate with single Body edge")
{
auto setCoord = graph.control.addElement(CF::SetCoordinate());
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Body(), {setCoord}, {ldsNode});
auto result = getLDSNode(graph, setCoord);
CHECK(result == ldsNode);
}
SECTION("Chain of SetCoordinate nodes with Body edges")
{
auto setCoord1 = graph.control.addElement(CF::SetCoordinate());
auto setCoord2 = graph.control.addElement(CF::SetCoordinate());
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Body(), {setCoord1}, {setCoord2});
graph.control.addElement(CF::Body(), {setCoord2}, {ldsNode});
auto result = getLDSNode(graph, setCoord1);
CHECK(result == ldsNode);
}
}
TEST_CASE("getLDSType returns data type of LDS node", "[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("LoadLDSTile with Float type")
{
auto tile = CT::MacroTile();
auto coord = graph.coordinates.addElement(tile);
auto ldsNode = graph.control.addElement(CF::LoadLDSTile{DataType::Float});
graph.mapper.connect<CT::MacroTile>(ldsNode, coord);
auto result = getLDSType(graph, ldsNode);
CHECK(result == DataType::Float);
}
SECTION("SetCoordinate pointing to LoadLDSTile with Half type")
{
auto tile = CT::MacroTile();
auto coord = graph.coordinates.addElement(tile);
auto setCoord = graph.control.addElement(CF::SetCoordinate());
auto ldsNode = graph.control.addElement(CF::LoadLDSTile{DataType::Half});
graph.mapper.connect<CT::MacroTile>(ldsNode, coord);
graph.control.addElement(CF::Body(), {setCoord}, {ldsNode});
auto result = getLDSType(graph, setCoord);
CHECK(result == DataType::Half);
}
}
TEST_CASE("getImmediateBodyParents updates nodes to body parents",
"[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("No body parents leaves nodes unchanged")
{
auto node1 = graph.control.addElement(CF::LoadLDSTile());
auto node2 = graph.control.addElement(CF::LoadLDSTile());
std::vector<int> nodes = {node1, node2};
getImmediateBodyParents(graph, nodes);
CHECK(nodes == Chain{node1, node2});
}
SECTION("Single body parent updates node")
{
auto setCoord = graph.control.addElement(CF::SetCoordinate());
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Body(), {setCoord}, {ldsNode});
std::vector<int> nodes = {ldsNode};
getImmediateBodyParents(graph, nodes);
CHECK(nodes == Chain{setCoord});
}
SECTION("Chain of body parents updates to root")
{
auto setCoord1 = graph.control.addElement(CF::SetCoordinate());
auto setCoord2 = graph.control.addElement(CF::SetCoordinate());
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Body(), {setCoord1}, {setCoord2});
graph.control.addElement(CF::Body(), {setCoord2}, {ldsNode});
std::vector<int> nodes = {ldsNode};
getImmediateBodyParents(graph, nodes);
CHECK(nodes == Chain{setCoord1});
}
}
TEST_CASE("findLoadLDSChains identifies LoadLDSTile chains",
"[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Empty graph returns empty chains")
{
auto chains = findLoadLDSChains(graph);
CHECK(chains.empty());
}
SECTION("Single LoadLDSTile node")
{
auto ldsNode = graph.control.addElement(CF::LoadLDSTile());
auto chains = findLoadLDSChains(graph);
CHECK(chains == Chains{{ldsNode}});
}
SECTION("Connected LoadLDSTile chain")
{
auto lds1 = graph.control.addElement(CF::LoadLDSTile());
auto lds2 = graph.control.addElement(CF::LoadLDSTile());
auto lds3 = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Sequence(), {lds1}, {lds2});
graph.control.addElement(CF::Sequence(), {lds2}, {lds3});
auto chains = findLoadLDSChains(graph);
CHECK(chains == Chains{{lds1, lds2, lds3}});
}
SECTION("LoadLDSTile with SetCoordinate parents")
{
auto setCoord1 = graph.control.addElement(CF::SetCoordinate());
auto setCoord2 = graph.control.addElement(CF::SetCoordinate());
auto lds1 = graph.control.addElement(CF::LoadLDSTile());
auto lds2 = graph.control.addElement(CF::LoadLDSTile());
graph.control.addElement(CF::Body(), {setCoord1}, {lds1});
graph.control.addElement(CF::Body(), {setCoord2}, {lds2});
graph.control.addElement(CF::Sequence(), {setCoord1}, {setCoord2});
auto chains = findLoadLDSChains(graph);
// Should find chain of SetCoordinate parents
CHECK(chains == Chains{{setCoord1, setCoord2}});
}
}
TEST_CASE("findMultiplyChainsAndCoords finds multiply chains",
"[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Empty graph returns empty results")
{
auto [chains, chainTypes] = findMultiplyChainsAndCoords(graph);
CHECK(chains.empty());
CHECK(chainTypes.empty());
}
SECTION("Connected multiply chain")
{
auto kernel = graph.control.addElement(CF::Kernel());
auto a0 = graph.coordinates.addElement(CT::MacroTile());
auto a1 = graph.coordinates.addElement(CT::MacroTile());
auto b0 = graph.coordinates.addElement(CT::MacroTile());
auto b1 = graph.coordinates.addElement(CT::MacroTile());
auto d0 = graph.coordinates.addElement(CT::MacroTile());
auto d1 = graph.coordinates.addElement(CT::MacroTile());
auto mult = [&](int a, int b, int d) {
auto mult = graph.control.addElement(CF::Multiply());
graph.mapper.connect(
mult, a, Connections::typeArgument<CT::MacroTile>(NaryArgument::LHS));
graph.mapper.connect(
mult, b, Connections::typeArgument<CT::MacroTile>(NaryArgument::RHS));
graph.mapper.connect(
mult, d, Connections::typeArgument<CT::MacroTile>(NaryArgument::DEST));
return mult;
};
auto mult1 = mult(a0, b0, d0);
auto mult2 = mult(a1, b1, d1);
auto mult3 = mult(a0, b1, d1);
auto mult4 = mult(a1, b0, d0);
graph.control.addElement(CF::Body(), {kernel}, {mult1});
graph.control.chain<CF::Sequence>(mult1, mult2, mult3, mult4);
CAPTURE(mult1, mult2, mult3, mult4);
auto [chains, chainTypes] = findMultiplyChainsAndCoords(graph);
CHECK(chains == Chains{{mult3, mult4}});
}
}
TEST_CASE("identifyParallelChains groups parallel chains",
"[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Empty input returns empty")
{
Groups groups;
auto result = identifyParallelChains(graph, groups);
CHECK(result.empty());
}
SECTION("Parallel chains")
{
auto kernel = graph.control.addElement(CF::Kernel());
auto makeChain = [&](auto tmpl, int len) {
std::vector<int> nodes;
nodes.reserve(len);
std::optional<int> prev;
for(int i = 0; i < len; i++)
{
auto node = graph.control.addElement(tmpl);
nodes.push_back(node);
if(prev)
graph.control.addElement(CF::Sequence(), {prev.value()}, {node});
prev = node;
}
return nodes;
};
auto multChain1 = makeChain(CF::Multiply(), 3);
auto multChain2 = makeChain(CF::Multiply(), 3);
auto ldsChain1 = makeChain(CF::LoadLDSTile(), 3);
auto ldsChain2 = makeChain(CF::LoadLDSTile(), 3);
auto ldsChain3 = makeChain(CF::LoadLDSTile(), 3);
graph.control.addElement(CF::Body(), {kernel}, {ldsChain1.front()});
auto loop = graph.control.addElement(CF::ForLoopOp());
graph.control.chain<CF::Sequence>(ldsChain1.back(), loop);
graph.control.addElement(CF::Body(), {loop}, {multChain1.front()});
graph.control.addElement(CF::Body(), {loop}, {ldsChain2.front()});
auto nop = graph.control.addElement(CF::NOP());
graph.control.chain<CF::Sequence>(ldsChain2.back(), nop, ldsChain3.front());
graph.control.chain<CF::Sequence>(multChain1.back(), nop, multChain2.front());
auto ldsChains = findLoadLDSChains(graph);
CHECK(ldsChains == Chains({ldsChain1, ldsChain2, ldsChain3}));
auto multiplyChains = findMultiplyChains(graph);
CHECK(multiplyChains == Chains({multChain1, multChain2}));
auto result = identifyParallelChains(graph, {multiplyChains, ldsChains});
CHECK(result == Groups({{{multChain1, ldsChain2}}, {{multChain2, ldsChain3}}}));
}
}
TEST_CASE("distributeChains creates sequence edges", "[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
SECTION("Empty chainSets does nothing")
{
std::vector<ParallelChainSet> chainSets;
size_t initialEdgeCount = graph.control.getEdges().to<std::vector>().size();
distributeChains(graph, chainSets);
size_t finalEdgeCount = graph.control.getEdges().to<std::vector>().size();
CHECK(finalEdgeCount == initialEdgeCount);
}
SECTION("ChainSet with multiply and LDS chains")
{
// Create multiply chain
auto mult1 = graph.control.addElement(CF::Multiply());
auto mult2 = graph.control.addElement(CF::Multiply());
graph.control.addElement(CF::Sequence(), {mult1}, {mult2});
// Create LDS chain with proper data types
auto tile1 = CT::MacroTile();
auto coord1 = graph.coordinates.addElement(tile1);
auto lds1 = graph.control.addElement(CF::LoadLDSTile{DataType::Float});
graph.mapper.connect<CT::MacroTile>(lds1, coord1);
auto tile2 = CT::MacroTile();
auto coord2 = graph.coordinates.addElement(tile2);
auto lds2 = graph.control.addElement(CF::LoadLDSTile{DataType::Float});
graph.mapper.connect<CT::MacroTile>(lds2, coord2);
graph.control.addElement(CF::Sequence(), {lds1}, {lds2});
ParallelChainSet chainSet;
chainSet.multiplyChain = {mult1, mult2};
chainSet.ldsChain = {lds1, lds2};
std::map<DataType, int> typeCounts;
typeCounts[DataType::Float] = 1;
chainSet.multiplyTagTypes.push_back(typeCounts);
chainSet.multiplyTagTypes.push_back(typeCounts);
chainSet.ldsChainTypes = {DataType::Float, DataType::Float};
std::vector<ParallelChainSet> chainSets = {chainSet};
size_t initialEdgeCount = graph.control.getEdges().to<std::vector>().size();
distributeChains(graph, chainSets);
size_t finalEdgeCount = graph.control.getEdges().to<std::vector>().size();
// Should have created new Sequence edges
CHECK(finalEdgeCount >= initialEdgeCount);
}
}
TEST_CASE("chainTagTable generates formatted table", "[kernel-graph][schedule-multiply-lds]")
{
auto graph = rocRoller::KernelGraph::KernelGraph();
auto addMultiply = [&](int coordA, int coordB, int coordD) {
auto mult = graph.control.addElement(CF::Multiply());
graph.mapper.connect(
mult, coordA, Connections::typeArgument<CT::MacroTile>(NaryArgument::LHS));
graph.mapper.connect(
mult, coordB, Connections::typeArgument<CT::MacroTile>(NaryArgument::RHS));
graph.mapper.connect(
mult, coordD, Connections::typeArgument<CT::MacroTile>(NaryArgument::DEST));
return mult;
};
auto addLoadLDSTile = [&](DataType type, int reg, int lds) {
auto op = graph.control.addElement(CF::LoadLDSTile{type});
graph.mapper.connect<CT::MacroTile>(op, reg);
graph.mapper.connect<CT::LDS>(op, lds);
return op;
};
{
auto kernel = graph.control.addElement(CF::Kernel());
auto lds1 = graph.coordinates.addElement(CT::LDS());
// Create multiple multiply nodes to show table structure
auto coordA1 = graph.coordinates.addElement(CT::MacroTile({}, LayoutType::MATRIX_A));
auto coordB1 = graph.coordinates.addElement(CT::MacroTile({}, LayoutType::MATRIX_B));
auto coordD
= graph.coordinates.addElement(CT::MacroTile({}, LayoutType::MATRIX_ACCUMULATOR));
auto coordA2 = graph.coordinates.addElement(CT::MacroTile({}, LayoutType::MATRIX_A));
auto coordB2 = graph.coordinates.addElement(CT::MacroTile({}, LayoutType::MATRIX_B));
auto mult1 = addMultiply(coordA1, coordB1, coordD);
auto mult2 = addMultiply(coordA2, coordB1, coordD);
auto mult3 = addMultiply(coordA2, coordB2, coordD);
auto loadA1 = addLoadLDSTile(DataType::FP4x8, coordA1, lds1);
auto loadB1 = addLoadLDSTile(DataType::FP4x8, coordB1, lds1);
auto loadD1 = addLoadLDSTile(DataType::Half, coordD, lds1);
auto loadA2 = addLoadLDSTile(DataType::FP4x8, coordA2, lds1);
auto loadB2 = addLoadLDSTile(DataType::FP4x8, coordB2, lds1);
graph.control.addElement(CF::Body(), {kernel}, {mult1});
graph.control.addElement(CF::Body(), {kernel}, {loadA1});
graph.control.chain<CF::Sequence>(mult1, mult2, mult3);
graph.control.chain<CF::Sequence>(loadA1, loadA2, loadB1, loadB2, loadD1);
SECTION("Multiply table")
{
Chain chain{mult1, mult2, mult3};
auto result = chainTagTable(graph, chain);
std::string expected = R"(
| | 2 | 3 | 5 | 6
===================================
| |8xFP4 |8xFP4 |8xFP4 |8xFP4
===================================
===================================
| | A | B | A | B
===================================
| 2 | V | V | |
| 3 | | V | V |
| 4 | | | V | V
Lasts: (3)(2, 3, 4)
)";
INFO(result);
CHECK(NormalizedSource(result) == NormalizedSource(expected));
}
SECTION("LoadLDSTile table")
{
Chain chain{loadA1, loadA2, loadB1, loadB2, loadD1};
auto result = chainTagTable(graph, chain);
std::string expected = R"(
| | 2 | 5 | 3 | 6
===================================
| |8xFP4 |8xFP4 |8xFP4 |8xFP4
===================================
===================================
| | A | A | B | B
===================================
| 5 | ^ | | |
| 8 | | ^ | |
| 6 | | | ^ |
| 9 | | | | ^
| 7 | | | |
Lasts: (5)(5, 8, 6, 9, 7)
)";
INFO(result);
CHECK(NormalizedSource(result) == NormalizedSource(expected));
}
}
}
}