Files
TheRock/rocm-libraries/projects/hipdnn/frontend/tests/TestTensorValueAttributes.cpp
T
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

239 lines
9.6 KiB
C++

// Copyright © Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <gtest/gtest.h>
#include <hipdnn_frontend/Graph.hpp>
#include <hipdnn_frontend/attributes/TensorAttributes.hpp>
#include <optional>
#include <variant>
using hipdnn_data_sdk::types::bfloat16;
using hipdnn_data_sdk::types::half;
using hipdnn_frontend::graph::Graph;
using hipdnn_frontend::graph::ScalarType;
using hipdnn_frontend::graph::TensorAttributes;
namespace
{
constexpr float PI_FLOAT = 3.14159265358979323846F;
// Assert the full RFC-0016 §4.2 getter matrix for a float-valued tensor.
// The primary variant getters (std::optional<pass_by_values_t>) must mirror the
// typed convenience wrappers: a value is visible through get_pass_by_value() iff
// it is visible through get_pass_by_value<T>(), and likewise for the
// compile-time-constant getter.
void expectFloatState(const TensorAttributes& tensor,
const bool isPassByValue,
const std::optional<float> passByValue,
const std::optional<float> compileTimeConstant,
const bool hasCompileTimeConstant,
const bool isRuntimePassByValue)
{
EXPECT_EQ(tensor.get_is_pass_by_value(), isPassByValue);
EXPECT_EQ(tensor.get_is_runtime_pass_by_value(), isRuntimePassByValue);
EXPECT_EQ(tensor.get_has_compile_time_constant(), hasCompileTimeConstant);
const std::optional<float> pbv = tensor.get_pass_by_value<float>();
EXPECT_EQ(pbv.has_value(), passByValue.has_value());
if(passByValue.has_value() && pbv.has_value())
{
EXPECT_FLOAT_EQ(pbv.value(), passByValue.value());
}
const std::optional<float> ctc = tensor.get_compile_time_constant<float>();
EXPECT_EQ(ctc.has_value(), compileTimeConstant.has_value());
if(compileTimeConstant.has_value() && ctc.has_value())
{
EXPECT_FLOAT_EQ(ctc.value(), compileTimeConstant.value());
}
const std::optional<TensorAttributes::pass_by_values_t> pbvVar = tensor.get_pass_by_value();
EXPECT_EQ(pbvVar.has_value(), passByValue.has_value());
const std::optional<TensorAttributes::pass_by_values_t> ctcVar
= tensor.get_compile_time_constant();
EXPECT_EQ(ctcVar.has_value(), compileTimeConstant.has_value());
}
// Round-trip a runtime-with-default scalar of an arbitrary supported type.
template <typename T>
void expectRuntimeRoundTrip(const T value)
{
const TensorAttributes tensor(value, ScalarType::RUNTIME_PARAM);
EXPECT_TRUE(tensor.get_is_pass_by_value());
EXPECT_TRUE(tensor.get_is_runtime_pass_by_value());
EXPECT_FALSE(tensor.get_has_compile_time_constant());
const std::optional<T> opt = tensor.get_pass_by_value<T>();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), value);
// A runtime tensor never answers the compile-time getter, even for the right type.
EXPECT_FALSE(tensor.get_compile_time_constant<T>().has_value());
}
} // namespace
// --- Compile-time-constant default paths (plain ctor / set_value; flag false) ---
// Per RFC-0016 §4.3, the plain constructor and set_value bake a baseline-1.0.0
// compile-time constant (runtime flag clear); use the (scalar,
// ScalarType::RUNTIME_PARAM) constructor or set_as_runtime_parameter() for a
// runtime-with-default scalar.
TEST(TestTensorValueAttributes, PlainConstructorIsCompileTimeConstant)
{
const TensorAttributes tensor(PI_FLOAT);
expectFloatState(tensor,
/*isPassByValue*/ true,
/*passByValue*/ std::nullopt,
/*compileTimeConstant*/ PI_FLOAT,
/*hasCompileTimeConstant*/ true,
/*isRuntimePassByValue*/ false);
}
TEST(TestTensorValueAttributes, SetValueIsCompileTimeConstant)
{
TensorAttributes tensor;
tensor.set_value(PI_FLOAT);
expectFloatState(tensor, true, std::nullopt, PI_FLOAT, true, false);
}
// --- Compile-time-constant creation paths (flag false, value present) --------
TEST(TestTensorValueAttributes, SetCompileTimeConstantIsCompileTimeConstant)
{
TensorAttributes tensor;
tensor.set_compile_time_constant(PI_FLOAT);
expectFloatState(tensor, true, std::nullopt, PI_FLOAT, true, false);
}
TEST(TestTensorValueAttributes, ConstructorCompileTimeConstMode)
{
const TensorAttributes tensor(PI_FLOAT, ScalarType::COMPILE_TIME_CONST);
expectFloatState(tensor, true, std::nullopt, PI_FLOAT, true, false);
}
TEST(TestTensorValueAttributes, GraphTensorCompileTimeConstMode)
{
const std::shared_ptr<TensorAttributes> tensor
= Graph::tensor(PI_FLOAT, ScalarType::COMPILE_TIME_CONST);
ASSERT_NE(tensor, nullptr);
expectFloatState(*tensor, true, std::nullopt, PI_FLOAT, true, false);
}
// --- Runtime-with-default creation paths (flag true, value present) ----------
TEST(TestTensorValueAttributes, ConstructorRuntimeParamMode)
{
const TensorAttributes tensor(PI_FLOAT, ScalarType::RUNTIME_PARAM);
expectFloatState(tensor, true, PI_FLOAT, std::nullopt, false, true);
}
TEST(TestTensorValueAttributes, GraphTensorRuntimeParamMode)
{
const std::shared_ptr<TensorAttributes> tensor
= Graph::tensor(PI_FLOAT, ScalarType::RUNTIME_PARAM);
ASSERT_NE(tensor, nullptr);
expectFloatState(*tensor, true, PI_FLOAT, std::nullopt, false, true);
}
TEST(TestTensorValueAttributes, SetIsPassByValueFlipsCompileTimeConstantToRuntimeWithDefault)
{
TensorAttributes tensor;
tensor.set_compile_time_constant(PI_FLOAT); // flag false, value present
tensor.set_is_pass_by_value(true); // flip only the flag; value must survive
// Compile-time constant becomes runtime-with-default: value retained as a default.
expectFloatState(tensor, true, PI_FLOAT, std::nullopt, false, true);
}
// --- Runtime user-supplied creation path (flag true, value cleared) ----------
TEST(TestTensorValueAttributes, SetAsRuntimeParameterClearsValue)
{
TensorAttributes tensor(PI_FLOAT, ScalarType::RUNTIME_PARAM); // start as runtime-with-default
tensor.set_as_runtime_parameter();
expectFloatState(tensor, true, std::nullopt, std::nullopt, false, true);
}
TEST(TestTensorValueAttributes, ClearValueOnRuntimeDefaultBecomesUserSupplied)
{
TensorAttributes tensor(PI_FLOAT, ScalarType::RUNTIME_PARAM);
tensor.clear_value();
// Flag stays true, value gone: this is the pure user-supplied state.
expectFloatState(tensor, true, std::nullopt, std::nullopt, false, true);
}
// --- set_value always bakes a compile-time constant, regardless of prior flag state ---
TEST(TestTensorValueAttributes, SetValueAfterSetIsPassByValueIsCompileTimeConstant)
{
TensorAttributes tensor;
tensor.set_is_pass_by_value(true);
tensor.set_value(PI_FLOAT); // set_value bakes a compile-time constant, clearing the flag
expectFloatState(tensor, true, std::nullopt, PI_FLOAT, true, false);
}
// --- Ordinary (not by-value) -------------------------------------------------
TEST(TestTensorValueAttributes, DefaultConstructedIsOrdinary)
{
const TensorAttributes tensor;
expectFloatState(tensor, false, std::nullopt, std::nullopt, false, false);
}
// --- Type dispatch: wrong-type queries return nullopt ------------------------
TEST(TestTensorValueAttributes, WrongTypeCompileTimeConstantReturnsNullopt)
{
TensorAttributes tensor;
tensor.set_compile_time_constant(42.0F); // compile-time constant float
const std::optional<float> match = tensor.get_compile_time_constant<float>();
ASSERT_TRUE(match.has_value());
EXPECT_FLOAT_EQ(match.value(), 42.0F);
EXPECT_FALSE(tensor.get_compile_time_constant<half>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<bfloat16>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<uint8_t>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<int32_t>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<int64_t>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<double>().has_value());
EXPECT_FALSE(tensor.get_compile_time_constant<bool>().has_value());
// Compile-time constant never answers the runtime getter, not even for float.
EXPECT_FALSE(tensor.get_pass_by_value<float>().has_value());
}
TEST(TestTensorValueAttributes, WrongTypeRuntimeWithDefaultReturnsNullopt)
{
const TensorAttributes tensor(int32_t{123}, ScalarType::RUNTIME_PARAM);
const std::optional<int32_t> match = tensor.get_pass_by_value<int32_t>();
ASSERT_TRUE(match.has_value());
EXPECT_EQ(match.value(), 123);
EXPECT_FALSE(tensor.get_pass_by_value<float>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<double>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<half>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<bfloat16>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<uint8_t>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<int64_t>().has_value());
EXPECT_FALSE(tensor.get_pass_by_value<bool>().has_value());
// Runtime tensor never answers the compile-time getter, not even for int32.
EXPECT_FALSE(tensor.get_compile_time_constant<int32_t>().has_value());
}
TEST(TestTensorValueAttributes, RuntimeWithDefaultRoundTripsAllTypes)
{
expectRuntimeRoundTrip<float>(PI_FLOAT);
expectRuntimeRoundTrip<double>(2.718281828459045);
// half/bfloat16 use an exactly-representable value so the round-trip is bit-exact.
expectRuntimeRoundTrip<half>(half(1.5F));
expectRuntimeRoundTrip<bfloat16>(bfloat16(1.5F));
expectRuntimeRoundTrip<uint8_t>(200);
expectRuntimeRoundTrip<int32_t>(-12345);
expectRuntimeRoundTrip<int64_t>(456789012345LL);
expectRuntimeRoundTrip<bool>(true);
expectRuntimeRoundTrip<bool>(false);
}