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

343 lines
14 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/CodeGen/CopyGenerator.hpp>
#include <rocRoller/CodeGen/MemoryInstructions.hpp>
#include <rocRoller/CommandSolution.hpp>
#include <rocRoller/Expression.hpp>
#include <rocRoller/ExpressionTransformations.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/Operations/Command.hpp>
#include "GPUContextFixture.hpp"
#include "GenericContextFixture.hpp"
#include "Utilities.hpp"
#include <common/TestValues.hpp>
using namespace rocRoller;
namespace FastMultiplicationTest
{
class FastMultiplicationTest : public GenericContextFixture
{
};
TEST_F(FastMultiplicationTest, MultiplicationByConstantExpressions)
{
#define ExpectCommutative(lhs, rhs, result) \
EXPECT_EQ(Expression::toString(fastMultiplication(lhs* rhs)), result); \
EXPECT_EQ(Expression::toString(fastMultiplication(rhs* lhs)), result)
auto command = std::make_shared<Command>();
auto aTag = command->allocateTag();
auto a = std::make_shared<Expression::Expression>(command->allocateArgument(
{DataType::Int32, PointerType::Value}, aTag, ArgumentType::Value));
auto bTag = command->allocateTag();
auto b = std::make_shared<Expression::Expression>(command->allocateArgument(
{DataType::Float, PointerType::Value}, bTag, ArgumentType::Value));
ExpectCommutative(a, std::make_shared<Expression::Expression>(0), "0:I");
ExpectCommutative(
a, std::make_shared<Expression::Expression>(1), "CommandArgument(user_Int32_Value_0)I");
ExpectCommutative(a, std::make_shared<Expression::Expression>(0u), "0:I");
ExpectCommutative(a, Expression::literal(0u), "0:I");
ExpectCommutative(a,
std::make_shared<Expression::Expression>(1u),
"Convert(CommandArgument(user_Int32_Value_0)I)U32");
ExpectCommutative(a,
std::make_shared<Expression::Expression>(8u),
"ShiftL(Convert(CommandArgument(user_Int32_Value_0)I)U32, 3:U32)U32");
ExpectCommutative(a,
std::make_shared<Expression::Expression>(16),
"ShiftL(CommandArgument(user_Int32_Value_0)I, 4:U32)I");
ExpectCommutative(a,
Expression::literal(64u),
"ShiftL(Convert(CommandArgument(user_Int32_Value_0)I)U32, 6:U32)U32");
ExpectCommutative(a,
std::make_shared<Expression::Expression>(256),
"ShiftL(CommandArgument(user_Int32_Value_0)I, 8:U32)I");
#undef ExpectCommutative
auto expr = a * std::make_shared<Expression::Expression>(-5);
auto expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Int32_Value_0)I, -5:I)I");
expr = std::make_shared<Expression::Expression>(-5) * a;
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(-5:I, CommandArgument(user_Int32_Value_0)I)I");
expr = a * std::make_shared<Expression::Expression>(-4);
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Int32_Value_0)I, -4:I)I");
expr = std::make_shared<Expression::Expression>(-4) * a;
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(-4:I, CommandArgument(user_Int32_Value_0)I)I");
expr = a * std::make_shared<Expression::Expression>(11u);
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Int32_Value_0)I, 11:U32)U32");
expr = std::make_shared<Expression::Expression>(11u) * a;
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(11:U32, CommandArgument(user_Int32_Value_0)I)U32");
expr = b * std::make_shared<Expression::Expression>(3.14);
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Float_Value_1)S, 3.14000:D)D");
expr = b * Expression::literal(3.14);
expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Float_Value_1)S, 3.14000:D)D");
}
TEST_F(FastMultiplicationTest, MultiplicationByArgumentExpressions)
{
auto command = std::make_shared<Command>();
auto aTag = command->allocateTag();
auto a = std::make_shared<Expression::Expression>(command->allocateArgument(
{DataType::Int32, PointerType::Value}, aTag, ArgumentType::Value));
auto bTag = command->allocateTag();
auto b_unsigned = std::make_shared<Expression::Expression>(command->allocateArgument(
{DataType::UInt32, PointerType::Value}, bTag, ArgumentType::Value));
auto expr = a * b_unsigned;
auto expr_fast = rocRoller::Expression::fastMultiplication(expr);
EXPECT_EQ(Expression::toString(expr_fast),
"Multiply(CommandArgument(user_Int32_Value_0)I, "
"CommandArgument(user_UInt32_Value_1)U32)U32");
}
class FastMultiplicationTestByConstantCurrentGPU : public CurrentGPUContextFixture,
public ::testing::WithParamInterface<int>
{
};
void executeFastMultiplicationByConstant(int multiplier, ContextPtr m_context)
{
auto command = std::make_shared<Command>();
auto resultTag = command->allocateTag();
auto result_arg = command->allocateArgument(
{DataType::Int32, PointerType::PointerGlobal}, resultTag, ArgumentType::Value);
auto aTag = command->allocateTag();
auto a_arg = command->allocateArgument(
{DataType::Int32, PointerType::Value}, aTag, ArgumentType::Value);
auto result_exp = std::make_shared<Expression::Expression>(result_arg);
auto a_exp = std::make_shared<Expression::Expression>(a_arg);
auto k = m_context->kernel();
k->addArgument({"result",
{DataType::Int32, PointerType::PointerGlobal},
DataDirection::WriteOnly,
result_exp});
k->addArgument({"a", DataType::Int32, DataDirection::ReadOnly, a_exp});
auto one = std::make_shared<Expression::Expression>(1u);
auto zero = std::make_shared<Expression::Expression>(0u);
k->setWorkgroupSize({1, 1, 1});
k->setWorkitemCount({one, one, one});
k->setDynamicSharedMemBytes(zero);
m_context->schedule(k->preamble());
m_context->schedule(k->prolog());
auto kb = [&]() -> Generator<Instruction> {
Register::ValuePtr s_result, s_a;
co_yield m_context->argLoader()->getValue("result", s_result);
co_yield m_context->argLoader()->getValue("a", s_a);
auto v_result
= Register::Value::Placeholder(m_context,
Register::Type::Vector,
DataType::Raw32,
2,
Register::AllocationOptions::FullyContiguous());
auto v_c = Register::Value::Placeholder(
m_context, Register::Type::Vector, DataType::Int32, 1);
co_yield v_result->allocate();
co_yield(m_context->copier()->copy(v_result, s_result));
auto a = s_a->expression();
std::shared_ptr<Expression::Expression> expr;
expr = fastMultiplication(a * Expression::literal(multiplier));
Register::ValuePtr s_c;
co_yield Expression::generate(s_c, expr, m_context);
co_yield(m_context->copier()->copy(v_c, s_c));
co_yield m_context->mem()->storeGlobal(v_result, v_c, 0, 4);
};
m_context->schedule(kb());
m_context->schedule(k->postamble());
m_context->schedule(k->amdgpu_metadata());
std::shared_ptr<rocRoller::ExecutableKernel> executableKernel
= m_context->instructions()->getExecutableKernel();
auto d_result = make_shared_device<int>();
CommandKernel commandKernel;
commandKernel.setContext(m_context);
commandKernel.generateKernel();
auto values = TestValues::int32Values;
for(int a : values)
{
CommandArguments commandArgs = command->createArguments();
commandArgs.setArgument(resultTag, ArgumentType::Value, d_result.get());
commandArgs.setArgument(aTag, ArgumentType::Value, a);
commandKernel.launchKernel(commandArgs.runtimeArguments());
int result;
ASSERT_THAT(hipMemcpy(&result, d_result.get(), sizeof(int), hipMemcpyDefault),
HasHipSuccess(0));
EXPECT_EQ(result, a * multiplier) << "A:" << a << " multiplier: " << multiplier;
}
}
void executeFastMultiplicationByConstantInt64(int multiplier, ContextPtr m_context)
{
auto command = std::make_shared<Command>();
auto resultTag = command->allocateTag();
auto result_arg = command->allocateArgument(
{DataType::Int64, PointerType::PointerGlobal}, resultTag, ArgumentType::Value);
auto aTag = command->allocateTag();
auto a_arg = command->allocateArgument(
{DataType::Int64, PointerType::Value}, aTag, ArgumentType::Value);
auto result_exp = std::make_shared<Expression::Expression>(result_arg);
auto a_exp = std::make_shared<Expression::Expression>(a_arg);
auto k = m_context->kernel();
k->addArgument({"result",
{DataType::Int64, PointerType::PointerGlobal},
DataDirection::WriteOnly,
result_exp});
k->addArgument({"a", DataType::Int64, DataDirection::ReadOnly, a_exp});
auto one = std::make_shared<Expression::Expression>(1u);
auto zero = std::make_shared<Expression::Expression>(0u);
k->setWorkgroupSize({1, 1, 1});
k->setWorkitemCount({one, one, one});
k->setDynamicSharedMemBytes(zero);
m_context->schedule(k->preamble());
m_context->schedule(k->prolog());
auto kb = [&]() -> Generator<Instruction> {
Register::ValuePtr s_result, s_a;
co_yield m_context->argLoader()->getValue("result", s_result);
co_yield m_context->argLoader()->getValue("a", s_a);
auto v_result = Register::Value::Placeholder(
m_context, Register::Type::Vector, DataType::Int64, 1);
auto v_c = Register::Value::Placeholder(m_context,
Register::Type::Vector,
DataType::Raw32,
2,
Register::AllocationOptions::FullyContiguous());
co_yield v_result->allocate();
co_yield(m_context->copier()->copy(v_result, s_result));
auto a = s_a->expression();
std::shared_ptr<Expression::Expression> expr;
expr = fastMultiplication(a * Expression::literal(multiplier));
Register::ValuePtr s_c;
co_yield Expression::generate(s_c, expr, m_context);
co_yield(m_context->copier()->copy(v_c, s_c));
co_yield m_context->mem()->storeGlobal(v_result, v_c, 0, 8);
};
m_context->schedule(kb());
m_context->schedule(k->postamble());
m_context->schedule(k->amdgpu_metadata());
std::shared_ptr<rocRoller::ExecutableKernel> executableKernel
= m_context->instructions()->getExecutableKernel();
auto d_result = make_shared_device<int64_t>();
CommandKernel commandKernel;
commandKernel.setContext(m_context);
commandKernel.generateKernel();
auto values = TestValues::int64Values;
for(auto a : values)
{
CommandArguments commandArgs = command->createArguments();
commandArgs.setArgument(resultTag, ArgumentType::Value, d_result.get());
commandArgs.setArgument(aTag, ArgumentType::Value, a);
commandKernel.launchKernel(commandArgs.runtimeArguments());
int64_t result;
ASSERT_THAT(hipMemcpy(&result, d_result.get(), sizeof(int64_t), hipMemcpyDefault),
HasHipSuccess(0));
EXPECT_EQ(result, a * multiplier) << "A:" << a << " multiplier: " << multiplier;
}
}
TEST_P(FastMultiplicationTestByConstantCurrentGPU, GPU_FastMultiplicationByConstant)
{
executeFastMultiplicationByConstant(GetParam(), m_context);
}
TEST_P(FastMultiplicationTestByConstantCurrentGPU, GPU_FastMultiplicationByConstantInt64)
{
executeFastMultiplicationByConstantInt64(GetParam(), m_context);
}
INSTANTIATE_TEST_SUITE_P(
FastMultiplicationTestByConstantCurrentGPUs,
FastMultiplicationTestByConstantCurrentGPU,
::testing::Values(-12345, -128, -3, -2, -1, 0, 1, 2, 3, 5, 8, 128, 12345));
}