Files
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

169 lines
5.8 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <optional>
#include <tuple>
#include <unordered_set>
#include <variant>
#include <rocRoller/Expression.hpp>
#include <rocRoller/KernelGraph/ControlToCoordinateMapper.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/KernelGraph/Transforms/FuseExpressions.hpp>
#include <rocRoller/KernelGraph/Utils.hpp>
namespace rocRoller::KernelGraph
{
using namespace ControlGraph;
/**
* @brief Look for {Assign Multiply(., .)} --Sequence--> {Assign Add(., .)}.
*
* Look for
*
* Assign Multiply(., .) -- Sequence --> Assign Add(., .)
*
* Make sure only one DF edge out of the result of the multiply.
*/
std::optional<std::tuple<int, int>> findMultiplyAdd(KernelGraph const& kgraph,
std::unordered_set<int> const& exclude)
{
namespace CT = rocRoller::KernelGraph::CoordinateGraph;
for(auto const& parent : kgraph.control.getNodes<Assign>())
{
if(exclude.contains(parent))
continue;
// find Multiply
auto multiplyAssign = kgraph.control.get<Assign>(parent);
if(!std::holds_alternative<Expression::Multiply>(*multiplyAssign->expression))
continue;
auto child = only(kgraph.control.getOutputNodeIndices<Sequence>(parent));
if(!child)
continue;
auto addAssign = kgraph.control.get<Assign>(*child);
if(!addAssign)
continue;
auto dst = kgraph.mapper.get(parent, NaryArgument::DEST);
AssertFatal(dst != -1, "Invalid connection.");
auto dfs = only(kgraph.coordinates.getOutputNodeIndices(dst, CT::isEdge<CT::DataFlow>));
if(!dfs)
continue;
if(!std::holds_alternative<Expression::Add>(*addAssign->expression))
continue;
return {{parent, *child}};
}
return {};
}
/**
* @brief Reconnect incoming and outgoing DataFlow edges from dimension.
*
* Inputs coming into the dimension are augmented with `other_inputs`.
*/
void reflow(KernelGraph& graph, int dim, std::vector<int> const& other_inputs)
{
namespace CT = rocRoller::KernelGraph::CoordinateGraph;
std::vector<int> inputs, outputs;
for(auto const& tag : graph.coordinates.getNeighbours<Graph::Direction::Upstream>(dim))
{
auto df = graph.coordinates.get<CT::DataFlow>(tag);
if(!df)
continue;
auto parents = graph.coordinates.getNeighbours<Graph::Direction::Upstream>(tag);
for(auto const parent : parents)
inputs.push_back(parent);
graph.coordinates.deleteElement(tag);
}
for(auto const& tag : graph.coordinates.getNeighbours<Graph::Direction::Downstream>(dim))
{
auto df = graph.coordinates.get<CT::DataFlow>(tag);
if(!df)
continue;
auto children = graph.coordinates.getNeighbours<Graph::Direction::Downstream>(tag);
for(auto const child : children)
outputs.push_back(child);
graph.coordinates.deleteElement(tag);
}
std::copy(other_inputs.cbegin(), other_inputs.cend(), std::back_inserter(inputs));
graph.coordinates.addElement(CT::DataFlow(), inputs, outputs);
}
/**
* @brief Fuse Add(Multiply(., .), .) into MultiplyAdd(., ., .).
*/
KernelGraph fuseMultiplyAdd(KernelGraph const& original)
{
using Expression::multiplyAdd;
auto kgraph = original;
std::unordered_set<int> excluded;
for(;;)
{
auto candidate = findMultiplyAdd(kgraph, excluded);
if(!candidate)
break;
auto const& [multiplyTag, addTag] = *candidate;
excluded.emplace(multiplyTag);
auto [addLHS, addLHSDF] = getBinaryLHS<Expression::Add>(kgraph, addTag);
auto mulDST = getDEST(kgraph, multiplyTag);
if(addLHS != mulDST)
continue;
auto addDST = getDEST(kgraph, addTag);
auto [addRHS, addRHSDF] = getBinaryRHS<Expression::Add>(kgraph, addTag);
auto [mulLHS, mulLHSDF] = getBinaryLHS<Expression::Multiply>(kgraph, multiplyTag);
auto [mulRHS, mulRHSDF] = getBinaryRHS<Expression::Multiply>(kgraph, multiplyTag);
auto fma = multiplyAdd(mulLHSDF, mulRHSDF, addRHSDF);
// Reuse register type and count from Multiply
auto fmaAssign = *kgraph.control.get<Assign>(multiplyTag);
fmaAssign.expression = fma;
auto fmaTag = kgraph.control.addElement(fmaAssign);
// Connect FMA; delete Multiply and Add operations
reconnect<Graph::Direction::Downstream>(kgraph, -1, multiplyTag);
reconnect<Graph::Direction::Upstream>(kgraph, fmaTag, multiplyTag);
reconnect<Graph::Direction::Upstream>(kgraph, fmaTag, addTag);
reconnect<Graph::Direction::Downstream>(kgraph, fmaTag, addTag);
kgraph.control.deleteElement(multiplyTag);
kgraph.control.deleteElement(addTag);
// Tidy up coordinate graph
reflow(kgraph, addLHS, {addRHS});
kgraph.coordinates.deleteElement(addLHS);
// Tidy up connections
kgraph.mapper.purge(multiplyTag);
kgraph.mapper.purge(addTag);
// Connect FMA
kgraph.mapper.connect(fmaTag, addDST, NaryArgument::DEST);
}
return kgraph;
}
KernelGraph FuseExpressions::apply(KernelGraph const& original)
{
return fuseMultiplyAdd(original);
}
}