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

250 lines
10 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/AssemblyKernel.hpp>
#include <rocRoller/CodeGen/ArgumentLoader.hpp>
#include <rocRoller/CommandSolution.hpp>
#include <rocRoller/DataTypes/DataTypes.hpp>
#include <rocRoller/ExecutableKernel.hpp>
#include <rocRoller/GPUArchitecture/GPUArchitectureLibrary.hpp>
#include <rocRoller/KernelArguments.hpp>
#include <rocRoller/KernelGraph/CoordinateGraph/CoordinateGraph.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/KernelGraph/Transforms/All.hpp>
#include <rocRoller/KernelGraph/Utils.hpp>
#include <rocRoller/KernelOptions_detail.hpp>
#include <rocRoller/Operations/Command.hpp>
#include "CustomMatchers.hpp"
#include "TestContext.hpp"
#include <common/Utilities.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>
using namespace rocRoller;
using namespace rocRoller::KernelGraph::CoordinateGraph;
using namespace rocRoller::KernelGraph::ControlGraph;
namespace Direct2LDSTileCopyTest
{
using DFFunc = std::function<Expression::ExpressionPtr(int)>;
using AssignExprFactory
= std::function<Expression::ExpressionPtr(int mactile0, DFFunc const& DF)>;
ContextPtr buildDirect2LDSKernel(int MN, DataType dt, AssignExprFactory const& makeAssignExpr)
{
auto testContext = TestContext::ForTestDevice();
auto context = testContext.get();
if(!context->targetArchitecture().HasCapability(GPUCapability::HasDirectToLds))
{
SKIP("Architecture " + context->targetArchitecture().target().toString()
+ " does not support DirectToLDS");
}
const int K = 1;
auto expr1u = Expression::literal(1u);
auto exprMN = Expression::literal(MN);
auto exprK = Expression::literal(K);
int subtileMN = 1;
int subtileK = 1;
rocRoller::KernelGraph::KernelGraph kgraph;
auto user0 = kgraph.coordinates.addElement(
User("a", std::make_shared<Expression::Expression>((size_t)MN * K)));
auto idim0 = kgraph.coordinates.addElement(SubDimension(0, exprMN, exprK));
auto idim1 = kgraph.coordinates.addElement(SubDimension(1, exprK, expr1u));
auto mactile0 = kgraph.coordinates.addElement(MacroTile(
{MN, K}, LayoutType::ROW_MAJOR, {subtileMN, subtileK}, MemoryType::WAVE_Direct2LDS));
auto mactile1 = kgraph.coordinates.addElement(
MacroTile({MN, K}, LayoutType::ROW_MAJOR, {subtileMN, subtileK}, MemoryType::VGPR));
auto odim0 = kgraph.coordinates.addElement(SubDimension(0, exprMN, exprK));
auto odim1 = kgraph.coordinates.addElement(SubDimension(1, exprK, expr1u));
auto user1 = kgraph.coordinates.addElement(
User("result", std::make_shared<Expression::Expression>((size_t)MN * K)));
kgraph.coordinates.addElement(Split(), {user0}, {idim0, idim1});
kgraph.coordinates.addElement(ConstructMacroTile(), {idim0, idim1}, {mactile0});
kgraph.coordinates.addElement(DataFlow(), {mactile0}, {mactile1});
kgraph.coordinates.addElement(DestructMacroTile(), {mactile1}, {odim0, odim1});
kgraph.coordinates.addElement(Join(), {odim0, odim1}, {user1});
kgraph.coordinates.addElement(DataFlow(), {user0}, {mactile0});
kgraph.coordinates.addElement(DataFlow(), {mactile1}, {user1});
auto DF = [dt](int tag) -> Expression::ExpressionPtr {
return std::make_shared<Expression::Expression>(
Expression::DataFlowTag{tag, Register::Type::Vector, dt});
};
auto kernel = kgraph.control.addElement(Kernel());
auto load = kgraph.control.addElement(LoadTiled(dt));
auto assignOp = kgraph.control.addElement(
Assign{Register::Type::Vector, makeAssignExpr(mactile0, DF)});
auto store = kgraph.control.addElement(StoreTiled(dt));
kgraph.control.addElement(Body(), {kernel}, {load});
kgraph.control.addElement(Sequence(), {load}, {assignOp});
kgraph.control.addElement(Sequence(), {assignOp}, {store});
kgraph.mapper.connect<User>(load, user0);
kgraph.mapper.connect<MacroTile>(load, mactile0);
kgraph.mapper.connect<MacroTile>(store, mactile1);
kgraph.mapper.connect<User>(store, user1);
kgraph.mapper.connect(assignOp, mactile1, NaryArgument::DEST);
auto k = context->kernel();
k->setKernelDimensions(2);
auto one = Expression::literal(1u);
auto workitemCountExpr
= Expression::literal(static_cast<unsigned int>(MN * K) / (subtileMN * subtileK));
k->setWorkitemCount({workitemCountExpr, one, one});
k->setWorkgroupSize({static_cast<unsigned int>(MN * K) / (subtileMN * subtileK), 1, 1});
auto params = std::make_shared<CommandParameters>();
params->setWaveTilesPerWavefront(1, 1);
using namespace rocRoller::KernelGraph;
kgraph = kgraph.transform(std::make_shared<AddLDS>(params, context));
{
auto tile0 = kgraph.coordinates.getNode<MacroTile>(mactile0);
tile0.memoryType = MemoryType::VGPR;
kgraph.coordinates.setElement(mactile0, tile0);
}
kgraph = kgraph.transform(std::make_shared<AddPrefetch>(params, context));
kgraph = kgraph.transform(std::make_shared<LowerTile>(params, context));
kgraph = kgraph.transform(std::make_shared<AddDirect2LDS>(context, params));
kgraph = kgraph.transform(std::make_shared<UpdateWavefrontParameters>(params));
kgraph = kgraph.transform(std::make_shared<AddLDSBarriers>());
auto command = std::make_shared<rocRoller::Command>();
command->allocateArgument({dt, PointerType::PointerGlobal},
Operations::OperationTag(0),
ArgumentType::Value,
DataDirection::WriteOnly,
"result");
command->allocateArgument({dt, PointerType::PointerGlobal},
Operations::OperationTag(1),
ArgumentType::Value,
DataDirection::ReadOnly,
"a");
kgraph = kgraph.transform(std::make_shared<AssignIndexExpressions>(context, command));
if(context->kernelOptions()->removeSetCoordinate)
kgraph = kgraph.transform(std::make_shared<RemoveSetCoordinate>());
kgraph = kgraph.transform(std::make_shared<CleanArguments>(context, command));
context->schedule(k->preamble());
context->schedule(k->prolog());
context->schedule(rocRoller::KernelGraph::generate(kgraph, context->kernel()));
context->schedule(k->postamble());
context->schedule(k->amdgpu_metadata());
return context;
}
TEMPLATE_TEST_CASE("Direct2LDS tile copy", "[direct2lds][gpu]", uint8_t, uint16_t, uint32_t)
{
using T = TestType;
auto dt = TypeInfo<T>::Var.dataType;
const int MN = 64;
auto copyExpr = [](int mactile0, DFFunc const& DF) { return DF(mactile0); };
auto context = buildDirect2LDSKernel(MN, dt, copyExpr);
auto code = context->instructions()->toString();
std::string expectedInstr = (sizeof(T) == 1) ? "buffer_load_ubyte"
: (sizeof(T) == 2) ? "buffer_load_ushort"
: "buffer_load_dword";
CHECK(countSubstring(code, expectedInstr) == 1);
CHECK(countSubstring(code, "ds_write") == 0);
std::vector<char> assembledKernel = context->instructions()->assemble();
REQUIRE(assembledKernel.size() > 0);
std::vector<T> a(MN);
for(size_t i = 0; i < a.size(); ++i)
a[i] = static_cast<T>(i);
auto dA = make_shared_device(a);
auto dResult = make_shared_device<T>(MN);
KernelArguments kargs;
kargs.append("a", dA.get());
kargs.append("result", dResult.get());
KernelInvocation kinv;
kinv.workitemCount = {static_cast<unsigned int>(MN), 1, 1};
kinv.workgroupSize = {static_cast<unsigned int>(MN), 1, 1};
context->instructions()->getExecutableKernel()->executeKernel(kargs, kinv);
std::vector<T> expected(MN);
if(sizeof(T) < 4)
{
// Direct2LDS writes at M0 + TID*4 (always dword-aligned).
// For sub-dword types this leaves zero gaps in LDS:
// uint8: [0,0,0,0, 1,0,0,0, 2,0,0,0, ...] (stride 4)
// uint16: [0,0, 1,0, 2,0, 3,0, ...] (stride 2)
constexpr int stride = 4 / sizeof(T);
for(int i = 0; i < MN; ++i)
expected[i] = (i % stride == 0) ? static_cast<T>(i / stride) : T(0);
}
else
{
for(int i = 0; i < MN; ++i)
expected[i] = static_cast<T>(i);
}
REQUIRE_THAT(dResult, HasDeviceVectorEqualTo(expected));
}
TEST_CASE("Direct2LDS tile copy with add", "[direct2lds][gpu]")
{
const int MN = 256;
auto addExpr = [](int mactile0, DFFunc const& DF) { return DF(mactile0) + DF(mactile0); };
auto context = buildDirect2LDSKernel(MN, DataType::UInt32, addExpr);
std::vector<char> assembledKernel = context->instructions()->assemble();
REQUIRE(assembledKernel.size() > 0);
std::vector<uint32_t> a(MN);
for(int i = 0; i < MN; i++)
a[i] = i;
auto dA = make_shared_device(a);
auto dResult = make_shared_device<uint32_t>(MN);
KernelArguments kargs;
kargs.append("a", dA.get());
kargs.append("result", dResult.get());
KernelInvocation kinv;
kinv.workitemCount = {static_cast<unsigned int>(MN), 1, 1};
kinv.workgroupSize = {static_cast<unsigned int>(MN), 1, 1};
context->instructions()->getExecutableKernel()->executeKernel(kargs, kinv);
std::vector<uint32_t> expected(MN);
for(int i = 0; i < MN; i++)
expected[i] = a[i] + a[i];
REQUIRE_THAT(dResult, HasDeviceVectorEqualTo(expected));
}
}