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

285 lines
10 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/KernelGraph/ControlGraph/ControlFlowRWTracer.hpp>
#include <rocRoller/KernelGraph/CoordinateGraph/Transformer.hpp>
#include <rocRoller/KernelGraph/Transforms/LoadPacked.hpp>
#include <rocRoller/KernelGraph/Transforms/LoadPacked_detail.hpp>
#include <rocRoller/KernelGraph/Utils.hpp>
namespace rocRoller::KernelGraph
{
namespace LoadPackedDetail
{
std::map<int, Expression::ExpressionPtr> getStaticCoords(int controlNode,
KernelGraph const& graph)
{
std::map<int, Expression::ExpressionPtr> rv;
// Map from coord to the node that we used to set that coord, so
// that we can tell if we are above or below there.
std::map<int, int> coordSetBy;
auto setCoordNodes = getContainingSetCoordinates(graph, controlNode);
for(auto setCoordNode : setCoordNodes)
{
auto setCoord
= graph.control.get<ControlGraph::SetCoordinate>(setCoordNode).value();
auto connections = graph.mapper.getConnections(setCoordNode);
AssertFatal(connections.size() == 1,
"Invalid SetCoordinate operation; coordinate missing.");
auto coord = connections[0].coordinate;
auto iter = coordSetBy.find(coord);
if(iter == coordSetBy.end())
{
AssertFatal(!rv.contains(coord));
rv[coord] = setCoord.value;
coordSetBy[coord] = setCoordNode;
}
else
{
auto ordering = graph.control.compareNodes(
rocRoller::UpdateCache, setCoordNode, iter->second);
if(ordering == ControlGraph::NodeOrdering::LeftInBodyOfRight)
{
Log::debug("{}: replacing {} with {}.",
coord,
toString(rv[coord]),
toString(setCoord.value));
rv[coord] = setCoord.value;
iter->second = setCoordNode;
}
}
}
return rv;
}
std::map<int, Expression::ExpressionPtr>
fillRegisterCoords(std::unordered_set<int> const& requiredCoords,
KernelGraph const& graph,
ContextPtr context)
{
using namespace CoordinateGraph;
std::map<int, Expression::ExpressionPtr> rv;
auto isRegisterDim = [](auto dim) -> bool {
using T = std::decay_t<decltype(dim)>;
return CIsAnyOf<T, Wavefront, Workitem, Workgroup, ForLoop, MacroTileNumber>;
};
for(auto coord : requiredCoords)
{
if(std::visit(isRegisterDim, graph.coordinates.getNode(coord)))
{
auto reg = Register::Value::Placeholder(
context, Register::Type::Vector, DataType::Int32, 1);
rv[coord] = reg->expression();
}
}
return rv;
}
std::tuple<CoordinateGraph::Transformer, std::set<int>> getFakeTransformerForControlNode(
int controlNode, KernelGraph const& graph, ContextPtr context)
{
auto const& [coords, paths] = findAllRequiredCoordinates(controlNode, graph);
auto staticCoords = getStaticCoords(controlNode, graph);
auto regCoords = fillRegisterCoords(coords, graph, context);
CoordinateGraph::Transformer xform(&graph.coordinates);
for(auto const& [coord, expr] : staticCoords)
xform.setCoordinate(coord, expr);
for(auto const& [coord, expr] : regCoords)
{
xform.setCoordinate(coord, expr);
}
std::set<int> remainingCoords;
for(auto coord : coords)
if(!xform.hasCoordinate(coord))
remainingCoords.insert(coord);
return {xform, remainingCoords};
}
int getFastestMovingCoord(std::set<int> const& coords, KernelGraph const& graph)
{
AssertFatal(!coords.empty());
if(coords.size() == 1)
return *coords.begin();
std::optional<int> fastestCoord;
std::optional<int> maxSubDim;
for(auto coord : coords)
{
auto dim = graph.coordinates.getNode(coord);
auto visitor = rocRoller::overloaded{
[&]<std::derived_from<CoordinateGraph::SubDimension> T>(T const& subdim) {
if(!maxSubDim || subdim.dim > maxSubDim)
{
fastestCoord = coord;
maxSubDim = subdim.dim;
}
},
[&](CoordinateGraph::VGPR const& vgpr) {
fastestCoord = coord;
maxSubDim = 1000;
},
[&](auto const& other) { Log::debug("Other: {}", toString(other)); }};
std::visit(visitor, dim);
}
return fastestCoord.value();
}
}
LoadPacked::LoadPacked(ContextPtr context)
: m_context(context)
{
}
KernelGraph LoadPacked::apply(KernelGraph const& original)
{
using namespace ControlGraph;
using namespace CoordinateGraph;
using namespace LoadPackedDetail;
std::set<int> changedDims;
auto rv = original;
auto pred = [&](int node) {
auto visitor = [](auto op) -> bool {
using T = std::decay_t<decltype(op)>;
if constexpr(CIsAnyOf<T,
LoadTiled,
StoreTiled,
LoadTileDirect2LDS,
LoadLDSTile,
StoreLDSTile>)
{
return DataTypeInfo::Get(op.varType).packedVariableType().has_value();
}
return false;
};
return rv.control.getElementType(node) == Graph::ElementType::Node
&& std::visit(visitor, rv.control.getNode(node));
};
auto roots = rv.control.roots().to<std::vector>();
for(auto node : rv.control.findNodes(roots, pred))
{
Log::debug("Load/store op: ({})", node);
auto [target, direction] = getOperationTarget(node, rv);
target = getTransformTarget(target, rv);
auto op = rv.control.getNode(node);
auto varType = getVariableType(op);
auto packedType = DataTypeInfo::Get(varType).packedVariableType().value();
auto packedInfo = DataTypeInfo::Get(packedType);
auto waveTileTag = rv.mapper.get<WaveTile>(node);
if(waveTileTag > 0)
{
auto waveTile = rv.coordinates.get<WaveTile>(waveTileTag);
auto elements = waveTile.value().elements();
auto [_, lane] = rv.getDimension<Lane>(node);
auto activeLanesInWave = getUnsignedInt(evaluate(lane.size));
AssertFatal(elements % activeLanesInWave == 0);
auto elementsPerThread = elements / activeLanesInWave;
if(elementsPerThread < packedInfo.packing)
{
Log::debug(
"Skipping node {} due to insufficient elementsPerThread: {} (packing {})",
node,
elementsPerThread,
packedInfo.packing);
continue;
}
}
if(rv.mapper.get<ElementNumber>(node, 0) > 0
&& rv.mapper.get<ElementNumber>(node, 1) > 0)
{
auto [elemXTag, elemX] = rv.getDimension<ElementNumber>(node, 0);
auto [elemYTag, elemY] = rv.getDimension<ElementNumber>(node, 1);
auto const m = getUnsignedInt(evaluate(elemX.size));
auto n = getUnsignedInt(evaluate(elemY.size));
if(m * n < packedInfo.packing)
{
Log::debug("Skipping node {}: {}x{} due to ElementNumber size.",
node,
ShowValue(m),
ShowValue(n));
continue;
}
}
auto [xform, remainingCoords] = getFakeTransformerForControlNode(node, rv, m_context);
Log::debug("Remaining coords: {}", concatenate(remainingCoords));
if(remainingCoords.empty())
continue;
auto fastestCoord = getFastestMovingCoord(remainingCoords, rv);
for(auto coord : remainingCoords)
{
xform.setCoordinate(coord, Expression::literal(0u));
}
Log::debug("Fastest coord: {}, Target: {}, looking {}",
fastestCoord,
target,
toString(direction));
auto exprs = direction != Graph::Direction::Upstream
? xform.reverseStride(fastestCoord, Expression::literal(1u), {target})
: xform.forwardStride(fastestCoord, Expression::literal(1u), {target});
Log::debug("Stride: {}", toString(exprs[0]));
if(evaluationTimes(exprs[0])[Expression::EvaluationTime::Translate])
{
Log::debug("Stride: {}", toString(evaluate(exprs[0])));
if(getUnsignedInt(evaluate(exprs[0])) == 1)
{
Log::debug("Setting {} varType from {} to {}.",
node,
toString(varType),
toString(packedType));
setVariableType(op, packedType);
rv.control.setElement(node, op);
}
}
}
return rv;
}
}