Files
TheRock/rocm-libraries/shared/rocroller/test/catch/UnrollLoopsTest.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

198 lines
7.6 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/DataTypes/DataTypes.hpp>
#include <rocRoller/Utilities/Utils.hpp>
#include <rocRoller/CommandSolution.hpp>
#include <rocRoller/Expression.hpp>
#include <rocRoller/ExpressionTransformations.hpp>
#include <rocRoller/KernelGraph/ControlGraph/Operation.hpp>
#include <rocRoller/KernelGraph/CoordinateGraph/Dimension.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/KernelGraph/Transforms/Simplify.hpp>
#include <rocRoller/KernelGraph/Transforms/UnrollLoops.hpp>
#include <rocRoller/KernelGraph/Utils.hpp>
#include <rocRoller/Operations/Command.hpp>
#include <rocRoller/Utilities/Settings.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_contains.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <fstream>
#include "ExpressionMatchers.hpp"
#include "TestContext.hpp"
TEST_CASE("Test getForLoopName", "[kernel-graph][unroll]")
{
using namespace rocRoller;
namespace kg = rocRoller::KernelGraph;
kg::KernelGraph kgraph;
auto [forDim, forOp] = kg::rangeFor(kgraph, Expression::literal(4), KLOOP);
auto [forDim2, forOp2] = kg::rangeFor(kgraph, Expression::literal(16), "Another loop");
CHECK(kg::getForLoopName(kgraph, forOp) == KLOOP);
CHECK(kg::getForLoopName(kgraph, forOp2) == "Another loop");
}
TEST_CASE("Test getUnrollAmount", "[kernel-graph][unroll]")
{
using namespace rocRoller;
namespace kg = rocRoller::KernelGraph;
kg::KernelGraph kgraph;
auto params = std::make_shared<CommandParameters>();
params->unrollK = 5;
auto [forDim, forOp] = kg::rangeFor(kgraph, Expression::literal(4), KLOOP);
auto [forDim2, forOp2] = kg::rangeFor(kgraph, Expression::literal(16), "Another loop");
auto [forDim3, forOp3] = kg::rangeFor(kgraph, Expression::literal(4), XLOOP);
CHECK(kg::getUnrollAmount(kgraph, forOp, params) == 5);
CHECK(kg::getUnrollAmount(kgraph, forOp2, params) == 1);
// X loop is always fully unrolled when length is a constant
CHECK(kg::getUnrollAmount(kgraph, forOp3, params) == 4);
params->unrollK = 7;
CHECK(kg::getUnrollAmount(kgraph, forOp, params) == 7);
}
TEST_CASE("UnrollLoops simple test", "[kernel-graph][unroll][graph-transforms]")
{
using namespace rocRoller;
namespace kg = rocRoller::KernelGraph;
Settings::getInstance()->set(Settings::LogConsole, true);
Settings::getInstance()->set(Settings::LogLvl, LogLevel::Debug);
Settings::getInstance()->set(Settings::LogGraphs, false);
auto ctx = TestContext::ForDefaultTarget();
auto command = std::make_shared<Command>();
kg::KernelGraph kgraph;
auto [user, wg, wi, vgpr] = kgraph.coordinates.addElements( //
kg::CoordinateGraph::User{},
kg::CoordinateGraph::Workgroup{0, 0},
kg::CoordinateGraph::Workitem{0, Expression::literal(64)},
kg::CoordinateGraph::VGPR{});
auto argTag = command->allocateTag();
auto arg = command->allocateArgument(DataType::Int32, argTag, ArgumentType::Size);
auto [forDim, forOp] = kg::rangeFor(kgraph, arg->expression(), rocRoller::KLOOP);
kgraph.coordinates.addElement(kg::CoordinateGraph::Tile{}, {user}, {wg, wi, forDim});
kgraph.coordinates.addElement(kg::CoordinateGraph::Forget{}, {wg, wi, forDim}, {vgpr});
auto x = std::make_shared<Expression::Expression>(
Expression::DataFlowTag{forDim, Register::Type::Vector, DataType::Int32});
auto [kernel, calculate, store] = kgraph.control.addElements( //
kg::ControlGraph::Kernel{},
kg::ControlGraph::Assign{Register::Type::Vector, Expression::literal(5) * x},
kg::ControlGraph::StoreLinear{});
kgraph.mapper.connect<kg::CoordinateGraph::VGPR>(calculate, vgpr);
kgraph.control.chain<kg::ControlGraph::Body>(kernel, forOp, calculate);
kgraph.control.chain<kg::ControlGraph::Sequence>(forOp, store);
auto params = std::make_shared<CommandParameters>();
params->unrollK = 4;
SECTION("Only one for loop initially.")
{
auto ops
= kgraph.control.findElements(kgraph.control.isElemType<kg::ControlGraph::ForLoopOp>())
.to<std::set>();
REQUIRE(ops == std::set{forOp});
}
SECTION("Create tail loop manually.")
{
int forLoopDimension = kgraph.coordinates.addElement(kg::CoordinateGraph::ForLoop());
int unrollDimension = kgraph.coordinates.addElement(kg::CoordinateGraph::Unroll(4));
kg::UnrollLoops unroll(params, ctx.get());
auto tail = unroll.createTailLoop(kgraph, forOp, 4, unrollDimension, forLoopDimension);
CHECK(tail != std::nullopt);
kgraph = kgraph.transform(std::make_shared<kg::Simplify>());
CHECK(kgraph.control.compareNodes(rocRoller::UpdateCache, forOp, *tail)
== rocRoller::KernelGraph::ControlGraph::NodeOrdering::LeftFirst);
CHECK(kgraph.control.compareNodes(rocRoller::CacheOnly, forOp, *tail)
== rocRoller::KernelGraph::ControlGraph::NodeOrdering::LeftFirst);
CHECK(kgraph.control.compareNodes(rocRoller::UseCacheIfAvailable, forOp, *tail)
== rocRoller::KernelGraph::ControlGraph::NodeOrdering::LeftFirst);
CHECK(kgraph.control.compareNodes(rocRoller::IgnoreCache, forOp, *tail)
== rocRoller::KernelGraph::ControlGraph::NodeOrdering::LeftFirst);
auto ops
= kgraph.control.findElements(kgraph.control.isElemType<kg::ControlGraph::ForLoopOp>())
.to<std::set>();
REQUIRE(ops == std::set{forOp, *tail});
auto tailOp = kgraph.control.getNode<kg::ControlGraph::ForLoopOp>(*tail);
auto [_, tailOpSize] = split<Expression::LessThan>(tailOp.condition);
CHECK_THAT(tailOpSize, IdenticalTo(arg->expression()));
auto unrollInitTag
= kgraph.control.getOutputNodeIndices<kg::ControlGraph::Initialize>(*tail)
.only()
.value();
auto unrollInit = kgraph.control.getNode<kg::ControlGraph::Assign>(unrollInitTag);
auto origOp = kgraph.control.getNode<kg::ControlGraph::ForLoopOp>(forOp);
auto [__, origOpSize] = split<Expression::LessThan>(origOp.condition);
CHECK_THAT(origOpSize, IdenticalTo(unrollInit.expression));
}
SECTION("Create tail loop automatically in UnrollLoops xform.")
{
kgraph = kgraph.transform(std::make_shared<kg::UnrollLoops>(params, ctx.get()));
kgraph = kgraph.transform(std::make_shared<kg::Simplify>());
auto ops
= kgraph.control.findElements(kgraph.control.isElemType<kg::ControlGraph::ForLoopOp>())
.to<std::set>();
REQUIRE(ops.size() == 2);
REQUIRE_THAT(ops, Catch::Matchers::Contains(forOp));
// remove the first loop, the other one will be the new tail loop.
ops.erase(forOp);
auto tailOpTag = *ops.begin();
auto tailOp = kgraph.control.getNode<kg::ControlGraph::ForLoopOp>(tailOpTag);
auto [_, tailOpSize] = split<Expression::LessThan>(tailOp.condition);
CHECK_THAT(tailOpSize, IdenticalTo(arg->expression()));
auto unrollInitTag
= kgraph.control.getOutputNodeIndices<kg::ControlGraph::Initialize>(tailOpTag)
.only()
.value();
auto unrollInit = kgraph.control.getNode<kg::ControlGraph::Assign>(unrollInitTag);
auto origOp = kgraph.control.getNode<kg::ControlGraph::ForLoopOp>(forOp);
auto [__, origOpSize] = split<Expression::LessThan>(origOp.condition);
CHECK_THAT(origOpSize, IdenticalTo(unrollInit.expression));
}
}