aboutsummaryrefslogtreecommitdiff
path: root/reference_model
diff options
context:
space:
mode:
authorevacha01 <evan.chandler@arm.com>2024-03-08 16:39:24 +0000
committerEric Kunze <eric.kunze@arm.com>2024-04-16 16:02:16 +0000
commit4a2051146f498cb9ec35d7213720540c5c3e81e2 (patch)
tree543000b3ef22bd587c3c7702100742e4b94eb5fb /reference_model
parent5d0e9c7f3748e80d6f14a3eeaef858eeb912e1fd (diff)
downloadreference_model-4a2051146f498cb9ec35d7213720540c5c3e81e2.tar.gz
SPECIAL data gen mode for FP16 and FP32
Signed-off-by: evacha01 <evan.chandler@arm.com> Change-Id: I5a9a1c63345bd83ca04bc6c2a99b0ef3612971ee
Diffstat (limited to 'reference_model')
-rw-r--r--reference_model/CMakeLists.txt4
-rw-r--r--reference_model/src/generate/generate_entry.cc5
-rw-r--r--reference_model/src/generate/generate_fp_special.cc180
-rw-r--r--reference_model/src/generate/generate_fp_special.h34
-rw-r--r--reference_model/src/generate/generate_utils.cc17
-rw-r--r--reference_model/src/generate/generate_utils.h11
-rw-r--r--reference_model/src/verify/verifiers.h8
-rw-r--r--reference_model/src/verify/verify_entry.cc3
-rw-r--r--reference_model/src/verify/verify_fp_special.cc106
-rw-r--r--reference_model/test/generate_tests.cpp97
10 files changed, 463 insertions, 2 deletions
diff --git a/reference_model/CMakeLists.txt b/reference_model/CMakeLists.txt
index b780781..cf1e9fe 100644
--- a/reference_model/CMakeLists.txt
+++ b/reference_model/CMakeLists.txt
@@ -75,6 +75,7 @@ set(CXX_SOURCE
src/generate/generate_pseudo_random.cc
src/generate/generate_fixed_data.cc
src/generate/generate_full_range.cc
+ src/generate/generate_fp_special.cc
src/generate/generate_entry.cc
src/generate/generate_utils.cc
src/verify/verify_abs_error.cc
@@ -84,6 +85,7 @@ set(CXX_SOURCE
src/verify/verify_reduce_product.cc
src/verify/verify_relative.cc
src/verify/verify_ulp.cc
+ src/verify/verify_fp_special.cc
src/verify/verify_utils.cc
src/ops/op_factory.cc
src/ops/tensor_ops.cc
@@ -161,6 +163,7 @@ add_library(tosa_reference_verify_lib SHARED
src/verify/verify_reduce_product.cc
src/verify/verify_relative.cc
src/verify/verify_ulp.cc
+ src/verify/verify_fp_special.cc
src/verify/verify_utils.cc
src/verify/verify_config.cc
src/func_debug.cc
@@ -179,6 +182,7 @@ add_library(tosa_reference_generate_lib SHARED
src/generate/generate_pseudo_random.cc
src/generate/generate_fixed_data.cc
src/generate/generate_full_range.cc
+ src/generate/generate_fp_special.cc
src/generate/generate_entry.cc
src/generate/generate_utils.cc
src/generate/generate_config.cc
diff --git a/reference_model/src/generate/generate_entry.cc b/reference_model/src/generate/generate_entry.cc
index 6f797b3..36d99ad 100644
--- a/reference_model/src/generate/generate_entry.cc
+++ b/reference_model/src/generate/generate_entry.cc
@@ -16,6 +16,7 @@
#include "generate_dot_product.h"
#include "generate_fixed_data.h"
+#include "generate_fp_special.h"
#include "generate_full_range.h"
#include "generate_pseudo_random.h"
#include "generate_utils.h"
@@ -46,6 +47,10 @@ bool generate(const GenerateConfig& cfg, void* data, size_t size)
return generateFullRange(cfg, data, size);
break;
}
+ case GeneratorType::FpSpecial: {
+ return generateFpSpecial(cfg, data, size);
+ break;
+ }
default: {
WARNING("[Generator] Unsupported generation mode.");
break;
diff --git a/reference_model/src/generate/generate_fp_special.cc b/reference_model/src/generate/generate_fp_special.cc
new file mode 100644
index 0000000..3602f51
--- /dev/null
+++ b/reference_model/src/generate/generate_fp_special.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2024, ARM Limited.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "generate_fp_special.h"
+#include "half.hpp"
+
+#include <map>
+
+namespace
+{
+
+class SpecialValue
+{
+public:
+ enum SpecialValsEnum
+ {
+ Zero,
+ Inf,
+ NaN,
+ Min,
+ Max,
+ One,
+ };
+
+ SpecialValue() = default;
+ SpecialValue(SpecialValsEnum v)
+ : value(v)
+ {}
+ operator SpecialValsEnum() const
+ {
+ return value;
+ }
+ SpecialValue& operator=(SpecialValsEnum v)
+ {
+ value = v;
+ return *this;
+ }
+ bool operator==(const SpecialValsEnum v) const
+ {
+ return value == v;
+ }
+ bool operator!=(const SpecialValsEnum v) const
+ {
+ return value != v;
+ }
+ SpecialValue operator-()
+ {
+ negative = !negative;
+ return *this;
+ }
+
+ template <typename DataType>
+ DataType evaluate()
+ {
+ switch (value)
+ {
+ case Zero:
+ return static_cast<DataType>(negative ? -0.0 : 0.0);
+ case Inf:
+ return negative ? -std::numeric_limits<DataType>::infinity()
+ : std::numeric_limits<DataType>::infinity();
+ case NaN:
+ return std::numeric_limits<DataType>::quiet_NaN();
+ case Min:
+ return negative ? -std::numeric_limits<DataType>::min() : std::numeric_limits<DataType>::min();
+ case Max:
+ return negative ? -std::numeric_limits<DataType>::max() : std::numeric_limits<DataType>::max();
+ case One:
+ return static_cast<DataType>(negative ? -1.0 : 1.0);
+ default:
+ WARNING("[Generator][FS] Uninitialised special value.");
+ return static_cast<DataType>(0.0);
+ }
+ }
+
+private:
+ SpecialValsEnum value;
+ bool negative = false;
+};
+
+/*
+Test vals format
+
+I: Number of inputs to an op - referenced by cfg.inputPos
+T: Number of test cases defined for the op
+
+vector of test inputs: {
+ vector of values for test 0: { valueForinputPos0, valueForinputPos1, ..., valueForinputPosI-1 },
+ vector of values for test 1: { valueForinputPos0, valueForinputPos1, ..., valueForinputPosI-1 },
+ ...
+ vector of values for test T-1: { valueForinputPos0, valueForinputPos1, ..., valueForinputPosI-1 },
+}
+*/
+using TestValues = std::vector<std::vector<SpecialValue>>;
+
+TestValues equalOpsTestVals{ { SpecialValue(SpecialValue::Zero), -SpecialValue(SpecialValue::Zero) },
+ { SpecialValue(SpecialValue::Inf), -SpecialValue(SpecialValue::Inf) } };
+
+TestValues addTestVals{ { SpecialValue(SpecialValue::Max), SpecialValue(SpecialValue::One) },
+ { SpecialValue(SpecialValue::Inf), -SpecialValue(SpecialValue::Inf) } };
+
+TestValues defaultTestVals{ { SpecialValue(SpecialValue::Zero) }, { -SpecialValue(SpecialValue::Zero) },
+ { SpecialValue(SpecialValue::Inf) }, { -SpecialValue(SpecialValue::Inf) },
+ { SpecialValue(SpecialValue::NaN) }, { SpecialValue(SpecialValue::Min) },
+ { SpecialValue(SpecialValue::Max) } };
+
+std::map<Op, TestValues> testValues = { { Op::Op_EQUAL, equalOpsTestVals },
+ { Op::Op_GREATER, equalOpsTestVals },
+ { Op::Op_GREATER_EQUAL, equalOpsTestVals },
+ { Op::Op_ADD, addTestVals } };
+
+template <typename DataType>
+bool generate(const TosaReference::GenerateConfig& cfg, DataType* data, size_t size)
+{
+ const TosaReference::FpSpecialInfo& fsinfo = cfg.fpSpecialInfo;
+ uint8_t startIndex = fsinfo.startIndex;
+
+ std::vector<DataType> values;
+ auto testValuesResult = testValues.find(cfg.opType);
+ TestValues opTestVals = defaultTestVals;
+ size_t inputIndex = 0;
+ if (testValuesResult != testValues.end())
+ {
+ // When an op has an entry in testValues we use its op specific special test values, otherwise default values are used
+ opTestVals = testValuesResult->second;
+ inputIndex = cfg.inputPos;
+ }
+
+ for (std::vector<SpecialValue> inputs : opTestVals)
+ {
+ values.push_back(inputs[inputIndex].evaluate<DataType>());
+ }
+
+ const auto T = TosaReference::numElementsFromShape(cfg.shape);
+ for (auto t = 0; t < T; ++t)
+ {
+ data[t] = values[(t + startIndex) % values.size()];
+ }
+ return true;
+}
+} // namespace
+
+namespace TosaReference
+{
+bool generateFpSpecial(const GenerateConfig& cfg, void* data, size_t size)
+{
+ // Check we support the operator
+ if (cfg.opType == Op::Op_UNKNOWN)
+ {
+ WARNING("[Generator][FS] Unknown operator.");
+ return false;
+ }
+
+ switch (cfg.dataType)
+ {
+ case DType::DType_FP16: {
+ half_float::half* outData = reinterpret_cast<half_float::half*>(data);
+ return generate(cfg, outData, size);
+ }
+ case DType::DType_FP32: {
+ float* outData = reinterpret_cast<float*>(data);
+ return generate(cfg, outData, size);
+ }
+ default:
+ WARNING("[Generator][FS] Unsupported type.");
+ return false;
+ }
+}
+} // namespace TosaReference \ No newline at end of file
diff --git a/reference_model/src/generate/generate_fp_special.h b/reference_model/src/generate/generate_fp_special.h
new file mode 100644
index 0000000..9a7315b
--- /dev/null
+++ b/reference_model/src/generate/generate_fp_special.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2024, ARM Limited.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GENERATE_FP_SPECIAL_H_
+#define GENERATE_FP_SPECIAL_H_
+
+#include "generate_utils.h"
+
+namespace TosaReference
+{
+
+/// \brief Perform FP special data generation
+///
+/// \param cfg Generator related meta-data
+/// \param data Buffer to generate the data to
+/// \param size Size of the buffer
+///
+/// \return True on successful generation
+bool generateFpSpecial(const GenerateConfig& cfg, void* data, size_t size);
+
+}; // namespace TosaReference
+
+#endif // GENERATE_FP_SPECIAL_H_ \ No newline at end of file
diff --git a/reference_model/src/generate/generate_utils.cc b/reference_model/src/generate/generate_utils.cc
index f31b443..d62c247 100644
--- a/reference_model/src/generate/generate_utils.cc
+++ b/reference_model/src/generate/generate_utils.cc
@@ -107,7 +107,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(GeneratorType,
{ GeneratorType::DotProduct, "DOT_PRODUCT" },
{ GeneratorType::FullRange, "FULL_RANGE" },
{ GeneratorType::Boundary, "BOUNDARY" },
- { GeneratorType::Special, "SPECIAL" },
+ { GeneratorType::FpSpecial, "FP_SPECIAL" },
{ GeneratorType::FixedData, "FIXED_DATA" },
})
@@ -159,6 +159,14 @@ void from_json(const nlohmann::json& j, FullRangeInfo& fullRangeInfo)
}
}
+void from_json(const nlohmann::json& j, FpSpecialInfo& fpSpecialInfo)
+{
+ if (j.contains("start_idx"))
+ {
+ j.at("start_idx").get_to(fpSpecialInfo.startIndex);
+ }
+}
+
void from_json(const nlohmann::json& j, GenerateConfig& cfg)
{
j.at("data_type").get_to(cfg.dataType);
@@ -201,6 +209,13 @@ void from_json(const nlohmann::json& j, GenerateConfig& cfg)
{
j.at("full_range_info").get_to(cfg.fullRangeInfo);
}
+
+ //Set up defaults for fpSpecialInfo
+ cfg.fpSpecialInfo.startIndex = 0;
+ if (j.contains("fp_special_info"))
+ {
+ j.at("fp_special_info").get_to(cfg.fpSpecialInfo);
+ }
}
std::optional<GenerateConfig> parseGenerateConfig(const char* json, const char* tensorName)
diff --git a/reference_model/src/generate/generate_utils.h b/reference_model/src/generate/generate_utils.h
index 8ce9b0e..0428fd8 100644
--- a/reference_model/src/generate/generate_utils.h
+++ b/reference_model/src/generate/generate_utils.h
@@ -33,7 +33,7 @@ enum class GeneratorType
DotProduct,
FullRange,
Boundary,
- Special,
+ FpSpecial,
FixedData,
};
@@ -82,6 +82,14 @@ struct FullRangeInfo
uint16_t startVal;
};
+/// \brief Op specific generator meta-data
+struct FpSpecialInfo
+{
+ FpSpecialInfo() = default;
+
+ uint8_t startIndex;
+};
+
/// \brief Generator configuration
struct GenerateConfig
{
@@ -95,6 +103,7 @@ struct GenerateConfig
PseudoRandomInfo pseudoRandomInfo;
FixedDataInfo fixedDataInfo;
FullRangeInfo fullRangeInfo;
+ FpSpecialInfo fpSpecialInfo;
};
/// \brief Parse the generator config when given in JSON form
diff --git a/reference_model/src/verify/verifiers.h b/reference_model/src/verify/verifiers.h
index e5f9df1..48c971d 100644
--- a/reference_model/src/verify/verifiers.h
+++ b/reference_model/src/verify/verifiers.h
@@ -85,6 +85,14 @@ bool verifyRelative(const CTensor* referenceTensor,
const CTensor* implementationTensor,
const RelativeVerifyInfo& rInfo);
+/// \brief Perform FP special tests verification
+///
+/// \param referenceTensor Reference tensor
+/// \param implementationTensor Implementation resulting tensor
+///
+/// \return True if compliant else false
+bool verifyFpSpecial(const CTensor* referenceTensor, const CTensor* implementationTensor);
+
}; // namespace TosaReference
#endif // VERIFIERS_H_
diff --git a/reference_model/src/verify/verify_entry.cc b/reference_model/src/verify/verify_entry.cc
index 9702c36..a04c62e 100644
--- a/reference_model/src/verify/verify_entry.cc
+++ b/reference_model/src/verify/verify_entry.cc
@@ -46,6 +46,9 @@ bool verify(const CTensor* ref, const CTensor* refBnd, const CTensor* imp, const
case VerifyMode::Relative: {
return verifyRelative(ref, imp, cfg.relativeInfo);
}
+ case VerifyMode::FpSpecial: {
+ return verifyFpSpecial(ref, imp);
+ }
default: {
WARNING("[Verifier] Unsupported verification mode.");
break;
diff --git a/reference_model/src/verify/verify_fp_special.cc b/reference_model/src/verify/verify_fp_special.cc
new file mode 100644
index 0000000..94550fd
--- /dev/null
+++ b/reference_model/src/verify/verify_fp_special.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2024, ARM Limited.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "half.hpp"
+#include "verifiers.h"
+
+namespace
+{
+template <typename Datatype>
+bool compliant(const double& referenceValue, const Datatype& implementationValue)
+{
+ // Compliant when values are both nans OR when values are both finite/infinite and have the same sign
+ return (std::isnan(referenceValue) && std::isnan(implementationValue)) ||
+ (std::isnan(referenceValue) == std::isnan(implementationValue) &&
+ std::isfinite(referenceValue) == std::isfinite(implementationValue) &&
+ std::signbit(referenceValue) == std::signbit(implementationValue));
+}
+
+template <>
+bool compliant(const double& referenceValue, const half_float::half& implementationValue)
+{
+ // Compliant when values are both nans OR when values are both finite/infinite and have the same sign
+ return (std::isnan(referenceValue) && half_float::isnan(implementationValue)) ||
+ (std::isnan(referenceValue) == half_float::isnan(implementationValue) &&
+ std::isfinite(referenceValue) == half_float::isfinite(implementationValue) &&
+ std::signbit(referenceValue) == half_float::signbit(implementationValue));
+}
+
+template <typename Datatype>
+bool verify(const double* refData,
+ const double* refDataEnd,
+ Datatype* impData,
+ const int64_t elementCount,
+ const std::vector<int32_t> refShape)
+{
+ auto pair = std::mismatch(refData, refDataEnd, impData, std::next(impData, elementCount),
+ [](const double& referenceValue, const Datatype& implementationValue) {
+ return compliant(referenceValue, implementationValue);
+ });
+
+ if (std::get<0>(pair) == refDataEnd)
+ {
+ // No mismatch found
+ return true;
+ }
+ else
+ {
+ auto pos = TosaReference::indexToPosition(std::get<0>(pair) - refData, refShape);
+ WARNING("[Verfier][FS] Location %s", TosaReference::positionToString(pos).c_str());
+ return false;
+ }
+}
+} // namespace
+
+namespace TosaReference
+{
+
+bool verifyFpSpecial(const CTensor* referenceTensor, const CTensor* implementationTensor)
+{
+ // Validate that tensors are provided
+ TOSA_REF_REQUIRE(referenceTensor != nullptr, "[FS] Reference tensor is missing");
+ TOSA_REF_REQUIRE(implementationTensor != nullptr, "[FS] Implementation tensor is missing");
+
+ // Get number of elements
+ const std::vector<int32_t> refShape(referenceTensor->shape, referenceTensor->shape + referenceTensor->num_dims);
+ const auto elementCount = numElements(refShape);
+ TOSA_REF_REQUIRE(elementCount > 0, "[FS] Invalid shape for reference tensor");
+
+ TOSA_REF_REQUIRE(referenceTensor->data_type == tosa_datatype_fp64_t, "[FS] Reference tensor is not fp64");
+ const auto* refData = reinterpret_cast<const double*>(referenceTensor->data);
+ TOSA_REF_REQUIRE(refData != nullptr, "[FS] Missing data for reference");
+ const auto* refDataEnd = std::next(refData, elementCount);
+
+ switch (implementationTensor->data_type)
+ {
+ case tosa_datatype_fp32_t: {
+ const auto* impData = reinterpret_cast<const float*>(implementationTensor->data);
+ TOSA_REF_REQUIRE(impData != nullptr, "[FS] Missing data for implementation");
+
+ return verify(refData, refDataEnd, impData, elementCount, refShape);
+ }
+ case tosa_datatype_fp16_t: {
+ const auto* impData = reinterpret_cast<const half_float::half*>(implementationTensor->data);
+ TOSA_REF_REQUIRE(impData != nullptr, "[FS] Missing data for implementation");
+
+ return verify(refData, refDataEnd, impData, elementCount, refShape);
+ }
+ default:
+ WARNING("[Verifier][FS] Data-type not supported.");
+ break;
+ }
+
+ return false;
+}
+} // namespace TosaReference
diff --git a/reference_model/test/generate_tests.cpp b/reference_model/test/generate_tests.cpp
index 73db631..19b808b 100644
--- a/reference_model/test/generate_tests.cpp
+++ b/reference_model/test/generate_tests.cpp
@@ -1609,4 +1609,101 @@ TEST_CASE("positive - FP16 full range")
}
}
+void fp_special_test_FP32(const std::string tosaName,
+ const size_t tosaElements,
+ const std::string templateJsonCfg,
+ const std::string opStr,
+ const std::string startIndexStr,
+ const std::vector<uint32_t> expected)
+{
+ std::string jsonCfg = templateJsonCfg;
+ update_json_template(jsonCfg, "_OP_", opStr);
+ update_json_template(jsonCfg, "_START_", startIndexStr);
+
+ std::vector<float> buffer(tosaElements);
+ REQUIRE(tgd_generate_data(jsonCfg.c_str(), tosaName.c_str(), (void*)buffer.data(), tosaElements * 4));
+ check_output<float>(buffer, expected);
+}
+
+TEST_CASE("positive - FP32 FP Special")
+{
+ std::string templateJsonCfg = R"({
+ "tensors" : {
+ "input0" : {
+ "generator": "FP_SPECIAL",
+ "data_type": "FP32",
+ "input_type": "VARIABLE",
+ "shape" : [ 5, 6, 7 ],
+ "input_pos": 0,
+ "op" : "_OP_",
+ "fp_special_info": {
+ "start_idx": _START_
+ }
+ },
+ "input1" : {
+ "generator": "FP_SPECIAL",
+ "data_type": "FP32",
+ "input_type": "VARIABLE",
+ "shape" : [ 5, 6, 7 ],
+ "input_pos": 1,
+ "op" : "_OP_",
+ "fp_special_info": {
+ "start_idx": _START_
+ }
+ }
+ }
+ })";
+
+ const std::string tosaName0 = "input0";
+ const std::string tosaName1 = "input1";
+ const size_t tosaElements = 5 * 6 * 7;
+
+ SUBCASE("equal, input 0")
+ {
+ std::vector<uint32_t> expected = { 0x0, 0x7F800000, 0x0 };
+ fp_special_test_FP32(tosaName0, tosaElements, templateJsonCfg, "EQUAL", "0", expected);
+ }
+ SUBCASE("equal, input 1")
+ {
+ std::vector<uint32_t> expected = { 0x80000000, 0xFF800000, 0x80000000 };
+ fp_special_test_FP32(tosaName1, tosaElements, templateJsonCfg, "EQUAL", "0", expected);
+ }
+ SUBCASE("greater, input 0")
+ {
+ std::vector<uint32_t> expected = { 0x0, 0x7F800000, 0x0 };
+ fp_special_test_FP32(tosaName0, tosaElements, templateJsonCfg, "GREATER", "0", expected);
+ }
+ SUBCASE("greater, input 1")
+ {
+ std::vector<uint32_t> expected = { 0x80000000, 0xFF800000, 0x80000000 };
+ fp_special_test_FP32(tosaName1, tosaElements, templateJsonCfg, "GREATER", "0", expected);
+ }
+ SUBCASE("add, input 0")
+ {
+ std::vector<uint32_t> expected = { 0x7F7FFFFF, 0x7F800000, 0x7F7FFFFF };
+ fp_special_test_FP32(tosaName0, tosaElements, templateJsonCfg, "ADD", "0", expected);
+ }
+ SUBCASE("add, input 1")
+ {
+ std::vector<uint32_t> expected = { 0x3F800000, 0xFF800000, 0x3F800000 };
+ fp_special_test_FP32(tosaName1, tosaElements, templateJsonCfg, "ADD", "0", expected);
+ }
+ SUBCASE("maximum, input 0")
+ {
+ std::vector<uint32_t> expected = { 0x0, 0x80000000, 0x7F800000 };
+ fp_special_test_FP32(tosaName0, tosaElements, templateJsonCfg, "MAXIMUM", "0", expected);
+ }
+ SUBCASE("maximum, input 1")
+ {
+ std::vector<uint32_t> expected = { 0x0, 0x80000000, 0x7F800000 };
+ fp_special_test_FP32(tosaName1, tosaElements, templateJsonCfg, "MAXIMUM", "0", expected);
+ }
+ SUBCASE("maximum, startIndex 100")
+ {
+ // A startIndex of 100 creates an offset of 2 in the MAXIMUM op's test data (size: 7) 100 % 7 = 2
+ std::vector<uint32_t> expected = { 0x7F800000, 0xFF800000, 0x7FC00000 };
+ fp_special_test_FP32(tosaName0, tosaElements, templateJsonCfg, "MAXIMUM", "100", expected);
+ }
+}
+
TEST_SUITE_END(); // generate