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

200 lines
7.4 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <cstdio>
#ifdef ROCROLLER_USE_HIP
#include <hip/hip_ext.h>
#include <hip/hip_runtime.h>
#endif /* ROCROLLER_USE_HIP */
#include <rocRoller/AssemblyKernel.hpp>
#include <rocRoller/CodeGen/ArgumentLoader.hpp>
#include <rocRoller/KernelArguments.hpp>
#include <rocRoller/Utilities/Generator.hpp>
#include "GenericContextFixture.hpp"
#include "SourceMatcher.hpp"
using namespace rocRoller;
namespace rocRollerTest
{
class ArgumentLoaderTest : public GenericContextFixture
{
void SetUp() override
{
Settings::getInstance()->set(Settings::AllowUnknownInstructions, true);
GenericContextFixture::SetUp();
}
};
TEST_F(ArgumentLoaderTest, IsContiguousRange)
{
std::vector<int> numbers{0, 1, 2, 3, 5, 6, 7, 9};
EXPECT_EQ(true, IsContiguousRange(numbers.begin(), numbers.begin() + 4));
EXPECT_EQ(false, IsContiguousRange(numbers.begin(), numbers.begin() + 5));
EXPECT_EQ(false, IsContiguousRange(numbers.begin() + 3, numbers.begin() + 5));
EXPECT_EQ(true, IsContiguousRange(numbers.begin() + 4, numbers.begin() + 7));
EXPECT_EQ(false, IsContiguousRange(numbers.begin() + 4, numbers.begin() + 8));
}
TEST_F(ArgumentLoaderTest, pickInstructionWidth)
{
auto indices = Generated(iota(0, 16));
std::vector<int> gap{0, 1, 3, 4, 5, 6, 7, 8};
EXPECT_EQ(4, rocRoller::PickInstructionWidthBytes(0, 4, indices.begin(), indices.end()));
EXPECT_EQ(8, rocRoller::PickInstructionWidthBytes(0, 8, indices.begin(), indices.end()));
EXPECT_EQ(16, rocRoller::PickInstructionWidthBytes(0, 16, indices.begin(), indices.end()));
EXPECT_EQ(32, rocRoller::PickInstructionWidthBytes(0, 32, indices.begin(), indices.end()));
EXPECT_EQ(64, rocRoller::PickInstructionWidthBytes(0, 64, indices.begin(), indices.end()));
EXPECT_EQ(64, rocRoller::PickInstructionWidthBytes(0, 128, indices.begin(), indices.end()));
EXPECT_EQ(4, rocRoller::PickInstructionWidthBytes(4, 16, indices.begin(), indices.end()));
// only the first 2 registers in `gap` are contiguous.
EXPECT_EQ(8, rocRoller::PickInstructionWidthBytes(0, 16, gap.begin(), gap.end()));
// registers must be aligned
EXPECT_EQ(4, rocRoller::PickInstructionWidthBytes(0, 16, gap.begin() + 1, gap.end()));
EXPECT_EQ(16, rocRoller::PickInstructionWidthBytes(0, 16, gap.begin() + 3, gap.end()));
}
TEST_F(ArgumentLoaderTest, loadArgExtra)
{
auto kernel = m_context->kernel();
auto loader = m_context->argLoader();
kernel->setKernelDimensions(1);
AssemblyKernelArgument arg{
"bar", {DataType::Float}, DataDirection::ReadOnly, nullptr, 4, 4};
kernel->addArgument(arg);
m_context->schedule(kernel->allocateInitialRegisters());
m_context->schedule(loader->loadArgument(arg));
std::string expected = R"(
s_load_dword s3, s[0:1], 4
)";
EXPECT_EQ(NormalizedSource(expected), NormalizedSource(output()));
clearOutput();
Register::ValuePtr reg;
m_context->schedule(loader->getValue("bar", reg));
ASSERT_NE(nullptr, reg);
EXPECT_EQ(DataType::Float, reg->variableType());
EXPECT_EQ(std::vector<int>{3}, Generated(reg->registerIndices()));
// Should not need to load a second time.
EXPECT_EQ(NormalizedSource(""), NormalizedSource(output()));
}
TEST_F(ArgumentLoaderTest, eagerLoadArguments)
{
auto kernel = m_context->kernel();
kernel->setKernelDimensions(2);
VariableType floatPtr{DataType::Float, PointerType::PointerGlobal};
kernel->addArgument({"a", floatPtr, DataDirection::WriteOnly});
kernel->addArgument({"b", floatPtr, DataDirection::ReadOnly});
kernel->addArgument({"c", {DataType::UInt64}});
auto loader = m_context->argLoader();
m_context->schedule(kernel->allocateInitialRegisters());
m_context->schedule(loader->eagerLoadArguments());
m_context->schedule(loader->splitOutArgumentRegisters());
std::string expected = R"(
s_load_dwordx4 s[4:7], s[0:1], 0
s_load_dwordx2 s[8:9], s[0:1], 16
)";
EXPECT_EQ(NormalizedSource(expected), NormalizedSource(output()));
clearOutput();
Register::ValuePtr a, b, c;
m_context->schedule(loader->getValue("a", a));
m_context->schedule(loader->getValue("b", b));
m_context->schedule(loader->getValue("c", c));
ASSERT_NE(nullptr, a);
EXPECT_EQ((std::vector<int>{4, 5}), Generated(a->registerIndices()));
EXPECT_EQ(floatPtr, a->variableType());
ASSERT_NE(nullptr, b);
EXPECT_EQ((std::vector<int>{6, 7}), Generated(b->registerIndices()));
EXPECT_EQ(floatPtr, b->variableType());
ASSERT_NE(nullptr, c);
EXPECT_EQ((std::vector<int>{8, 9}), Generated(c->registerIndices()));
EXPECT_EQ(DataType::UInt64, c->variableType());
EXPECT_EQ(NormalizedSource(""), NormalizedSource(output()));
}
TEST_F(ArgumentLoaderTest, releaseArguments)
{
auto kernel = m_context->kernel();
kernel->setKernelDimensions(2);
VariableType floatPtr{DataType::Float, PointerType::PointerGlobal};
kernel->addArgument({"a", floatPtr, DataDirection::WriteOnly});
kernel->addArgument({"b", floatPtr, DataDirection::ReadOnly});
kernel->addArgument({"c", {DataType::UInt64}});
auto loader = m_context->argLoader();
m_context->schedule(kernel->allocateInitialRegisters());
m_context->schedule(loader->eagerLoadArguments());
m_context->schedule(loader->splitOutArgumentRegisters());
Register::ValuePtr a, b, c;
m_context->schedule(loader->getValue("a", a));
m_context->schedule(loader->getValue("b", b));
m_context->schedule(loader->getValue("c", c));
const auto prevUseCount = a.use_count();
// Releasing the argument from the loader will reduce the ValuePtr use_count by 1.
loader->releaseArgument("a");
EXPECT_EQ(prevUseCount - 1, a.use_count());
a.reset();
// Clearing the KMQueue via a WaitCount::KMCnt ensures that reloading the Value uses
// the same set of registers.
auto inst = Instruction::Wait(WaitCount::KMCnt(m_context->targetArchitecture(), 0, ""));
m_context->schedule(inst);
clearOutput();
m_context->schedule(loader->getValue("a", a));
EXPECT_EQ(NormalizedSource("s_load_dwordx2 s[4:5], s[0:1], 0"), NormalizedSource(output()));
EXPECT_EQ((std::vector<int>{4, 5}), Generated(a->registerIndices()));
VariableType expectedType = {DataType::Float, PointerType::PointerGlobal};
EXPECT_EQ(expectedType, a->variableType());
// Reset all remaining pointers to the original Allocation.
loader->releaseAllArguments();
a.reset();
b.reset();
c.reset();
clearOutput();
m_context->schedule(inst);
clearOutput();
m_context->schedule(loader->getValue("c", c));
EXPECT_EQ(NormalizedSource("s_load_dwordx2 s[4:5], s[0:1], 16"),
NormalizedSource(output()));
EXPECT_EQ((std::vector<int>{4, 5}), Generated(c->registerIndices()));
EXPECT_EQ(DataType::UInt64, c->variableType());
}
}